//debug.
if( 0 ) {
addEventListener( "load", async function() {
let seek = 0;
let seek2 = -1;
let place;
//クッキー読み込み
console.log( document.cookie );
let cookies = new Object();
let pairs = document.cookie.split( '; ' );
for( let i = 0; i < pairs.length; i++ ) {
let pair = pairs[ i ].split( '=' );
cookies[ pair[ 0 ] ] = pair[ 1 ];
}
if( cookies.navicontinue ) {
document.cookie = "navicontinue=; max-age=0";
seek = cookies.naviseek;
seek2 = cookies.naviseek2 - 1;
seek2 = 0;
// seekAtEndOfPart = cookies.naviseekAtEndOfPart;
//check.
// if( seek2 == -2 ) {
// seek -= 1;
//check.
// if( seek == -1 ) seek = 0;
// seek2 = seekAtEndOfPart;
// }
place = decodeURIComponent( cookies.naviplace );
console.log( "cookie loaded:", seek, seek2, place );
}
await srcnavi( a_navi, seek, seek2, place );
let restart = function() {
let seek, seek2, place;
//クッキー書き込み
seek = this.seek;
seek2 = this.seek2;
place = this.place;
document.cookie = "naviseek=" + encodeURIComponent( seek ) + "; ";
document.cookie = "naviseek2=" + encodeURIComponent( seek2 ) + "; ";
// document.cookie = "naviseekAtEndOfPart=" + encodeURIComponent( seekAtEndOfPart ) + "; ";
document.cookie = "naviplace=" + encodeURIComponent( place ) + "; ";
document.cookie = "navicontinue=" + encodeURIComponent( "true" ) + "; ";
console.log( "cookie wrote:", seek, seek2, place );
location.reload();
}.bind( timeline );
addEventListener( "keydown", function( e ) {
switch( e.which ) {
case 67:
this.calcAndApplyPosition();
break;
case 82: //r
restart();
break;
case 68:
//クッキー削除
document.cookie = "key1=; max-age=0";
break;
case 8: //BS
//check.
if( ! this.placeBak ) {
alert( "placeBak が「" + this.placeBak + "」なので戻れません" );
return false;
}
this.seek2 -= 2;
//check.
if( this.seek2 < 0 ) {
this.seek -= 1;
//check.
if( this.seek < 0 ) {
this.seek = 0;
}
this.seek2 = this.seekAtEndOfPart;
}
this.place = this.placeBak;
restart();
default:
console.log( e.which );
return true;
}
}.bind( timeline ) );
ondblclick = function() {
restart();
}.bind( timeline );
} );
}
//---セリフ設定部
a_navi = {
navis : [
{
id : "",
script : function() {/*
this.huki.style.borderColor = "magenta";
this.huki.style.color = "#a09";
this.showChar();
こんにちは~!
それではわたくし、3Dお姉さんが説明させていただきます。
*/},
},
{
id : "",
script : function() {/*
終了する場合は私を『ダブルクリック』するか、
『私とフキダシを、2本の指で同時タッチ』してください。
*/},
},
{
id : "",
script : function() {/*
なお、わたしがしゃべっているあいだ、画面に表示されているリンクをクリックして別のページへ移動することはできますし、
*/},
},
{
id : "",
script : function() {/*
画面を動かしてこのページの別の場所を読んでもらっても大丈夫です。
でも別の場所を読んでいるときにわたしのこのフキダシをクリックして私のおしゃべりを進めると、私が指さすところへ向かってグイーンと 勝手に画面が動くことがあります。
*/},
},
{
id : "",
script : function() {/*
:testcanvas
this.test( 2 );
では、このカラフルな「まる」がたくさん動いているプログラムについて説明していきますヨ!
どうぞよろしくお願いいたします★
:testcanvas
それではさっそく!
:testcanvas
このプログラムは、大きく分けて2つのファイルで作られています。
:h4_html
this.test( 1 );
1つはこの「作ったプログラムをインターネットブラウザで表示するためのプログラム」です。
「HTML」と呼ばれています。
もう1つは、
:h4_js
this.test( 1 );
この JavaScript プログラムです。
このJavaScriptプログラムが、カラフルな「まる」を動かすメインのプログラムなんです。
:h4_html
では、ざっと説明していきますね
:h4_html
this.test( 1 );
インターネットブラウザは、ユーザーによってこのHTMLファイルのURLを指定されると、
:L1@loader1
そのファイルの一番最初から読んでいきます。
:L2@loader1
まずHEADタグがあり、
:L3@loader1
HEADタグの中へ入って、METAタグがあります。
:L4@loader1
このSCRIPTタグでは、メインのJavaScriptプログラムを読み込んでいます。
読み込み始めると、そのファイルの中へ入っていきます。
:h4_js
this.test( 2 );
このファイルの中へ入ります。
メイン・プログラムですね。
:L1@js1
中へ入ると、一番最初のここから読み込んでいきます。
このファイルでは、JavaScriptのプログラムだけが書かれています。
まずはクラスAppを、
:L48@js1
ここまで読み込んで定義して、
:L50@js1
もうひとつ、クラスBallを、
:L86@js1
ここまで読み込んで定義しています。
このファイルに書かれているプログラムは、この2つのクラスの定義だけです。
:L86@js1
ブラウザはファイルの最後まで読み込むと、もとのファイルへ戻ります。
つまり…
:L4@loader1
ここに戻ります。
メインのJavaScriptプログラムを読み込んだら、
:L5@loader1
つづいてSCRIPTタグがありまして、
:L6@loader1,L9@loader1
関数が一個、定義されています。
…
さっきから定義、定義って「テーギってなんなの?」って思いませんか?
:L6@loader1,L9@loader1
定義というのはですね。
:L6@loader1,L9@loader1
たとえば、大勢の人がいて、
多くの物があって、
これから何か大きな催し物をやろうっていうときに、
:L6@loader1,L9@loader1
誰にどんな役割を担当して動いてもらって、
どんな物が必要で、その物をみんながわかるようにどんな呼び名で呼ぶのかを決めないと、
催し物は動き出しませんよね?
:L6@loader1,L9@loader1
それと同じように、
:L6@loader1,L9@loader1
プログラムでも最初にどんなクラスや関数、変数があってどういう動きをするものなのか、どんな値を入れるのかを決めて、それぞれどんな名前にするのかも決めます。
そういう取り決めを行って はじめてプログラムは動き出します。
:L6@loader1,L9@loader1
そのような事前の取り決めを、プログラムでは「定義」と呼んでいます。
:L6@loader1,L9@loader1
テーキではないし、ステーキでもない、
「定義」です★
:L6@loader1,L9@loader1
お話は戻りまして、
:L11@loader1
ここまでHEADタグを読んだら、
:L13@loader1
つづいてBODYタグが来まして、
:L14@loader1,L16@loader1
その中にCANVASタグがあります。
:testcanvas
this.test( 2 );
CANVASタグとは、この画面のことです。
JavaScriptを使ってこの画面にコンピューターグラフィックスを描くことができます。
:L20@loader1
そしてここまで読み込むと、すべての読み込みが完了です。
「すべての読み込みが完了した」ということで、ブラウザは
「onloadイベント、レッツゴー!」という動きをします。
つまり、
:L13@loader1
this.test( 2 );
このBODYタグの設定で、onload="..."と書かれている、この中身の "onloadx()" をJavaScriptプログラムの一部として実行してくれるんです。
とうとうJavaScriptが動き始めるぞ!という感じですねー
:L13@loader1
このBODYタグに書かれた onloadx() というのは…
:L6@loader1,L9@loader1
this.test( 1 );
ズバリ、これです。
:L7@loader1
この中へ入っていきまして、
このnew App(...)が実行されると、
:L2@js1
this.test( 2 );
このクラス App の constructor() というところに来るんです。
ちょっと難しいですか?
:L2@js1
constructorとは「コンストラクタ」と読みます。
英単語としては「建設する人」という意味だそうです。
クラスAppを動かすために「まず初期設定を行うもの」と覚えておくと良いと思います。
:L2@js1
経験のあるプログラマーの人でさえ、
constructorという単語は「やや難しい単語を使っているな」と思っているくらいなので、みなさんが「難しい」と感じるのも無理もないですよ。
:L3@js1
それでコンストラクタが行う初期設定とは、
このようなCANVASの設定、
さっき見た「まる」がたくさん動いていた画面のことですね。
その設定を行ったり、
:L9@js1
「まる」をたくさん作成~~
:L10@js1
for文を使って、各色ごとに「まる」を作っています。
この行は赤で、
:L11@js1
緑、
:L12@js1
青、
:L13@js1
ピンク、
:L14@js1
水色、
:L15@js1
黄色と、いろいろな色を順次、for文で切り替えていきますよ、という意味になっています。
:L17@js1
そして、for文の中の1行目で1つの「まる」を作っています。
for文で切り替えた色である color をここで指定しています。
それで その色の「まる」を作っているんです。
:L17@js1
new Ball(...)なので、
:L51@js1,L58@js1
this.test( 1 );
このBallクラスのコンストラクタに来ます。初期設定ですねー。
内容を見ると、いくつかの数値を初期設定しているだけのようですね。
:L58@js1
というわけで初期設定をしてここまで来ましたら、
もとの場所に戻りましょう。
:L17@js1
そうやって、「まる」が1つできたところで、
:L18@js1,L21@js1
今 初期設定した一部の値を、「乱数」の値に変更します。
乱数(random)にしているので、
:testcanvas
this.test( 2 );
このようにバラバラに動いて楽しい感じになるんですね!
バラバラでしょ?
:L22@js1
そしてこれで「まる」が1つ完成したので、完成した「まる」を配列に入れます。
:L23@js1
for文で色の数だけ繰り返して「まる」を全部作り終わると、
:L24@js1
ここでAppのコンストラクタ(初期設定)が終わります。
:L7@loader1
そしてここに戻ってくるわけですね。onloadx()の中です。
:L8@loader1
以上で準備は終わって、次にstart()メソッドを実行します。
いよいよプログラムが動き出しますよ~
startメソッドは
:L1@js1
Appクラスの、
:L2@js1
…これはコンストラクタで…
:L25@js1
その次のここ!
Appのstartメソッド!
:L27@js1
この中で、setIntervalという「JavaScriptの基本の関数」の1つを実行してます。
setIntervalは「定期的に指定のメソッドを実行する」というもので、
これのおかげで、
:testcanvas
this.test( 2 );
こういうアニメができるんです!
setIntervalは「コンマ何秒の世界」なので、アニメの1コマのレベルで繰り返し実行してくれます★
:L27@js1
その1コマとして、setIntervalが呼び出しているメソッドは、Appのframeというメソッドです。
すぐ近くの…。
:L35@js1
これですね。
でもこのframeメソッドの説明はちょっと後にしましょう。
:L27@js1
setIntervalは定期的にframeメソッドを呼び出すというアニメの設定をして、
:L28@js1
その後、ここに来まして、start()メソッドが終了します。
:L8@loader1
そしてHTMLファイルのここに戻ってきます。
:L9@loader1
ここに来て、onloadx()も終了し、
:L13@loader1
さらにこのBODYタグのonload="onloadx()"の"onloadx()"の末尾まで戻ってくるんです。
ブラウザは、
:L13@loader1
1. ファイルを全部読み終わった、
2. だからonloadイベントレッツゴーした、
3. BODYタグに書かれているonload="onloadx()"の"onloadx()"を実行した!
そうやって全部終わってしまうと、このひと続きの流れはそれで終わり。その後は何もしなくなります。プログラムの終わりです。
…ところが!
:L27@js1
ここで定期的なアニメの設定をしているので、
「定期的にframeメソッドを実行する」
という動きを、止めない限りずっと続けることになります。
:L27@js1
…ということで、
大丈夫ですか?疲れていませんか?
休憩するのもプログラミングとしては大切なので覚えておきましょう。
:L35@js1
…ということで、
後にしていた、このframeメソッドの説明に戻ってきました。
:L36@js1
各色の「まる」について、
:L37@js1
frameメソッドを呼び出しています。
このballはさっきnew Ball(...)で初期設定したり、乱数に変更したりして作ったものです。
Ballクラスですから、
:L50@js1
このBallクラスの、
:L59@js1
これ!
:L60@js1,L61@js1
frameメソッドは、まず「まる」の位置(x,y)を変更しています。
:L62@js1,L74@js1
this.test( 1 );
位置を変更したらチェック!
:L63@js1
”右の壁にぶつかりましたか~?”
:L64@js1
ぶつかったなら、方向を反対にします★
これ、横方向の増分(addX)に-1を掛けると値が反対になり、動く方向が逆になるんです。
たとえば、5だったものに、-1を掛けると-5になります。
:L60@js1
それというのは、ここで「まる」の位置(x)に「5」を足すなら右に5ずつ移動するんですが、
反転して、「-5」を足すなら(5を引くなら)左に5ずつ移動する、と。
そういうことなんです。
:L60@js1
右端の * 1.25 については気にしないでください。微調整しているものです。
:L66@js1
つづけて、”左の壁にぶつかったんですか~?”
:L67@js1
ぶつかったなら、方向を反転します。
:L69@js1
”下の壁にぶつかっちゃいましたか~?”
:L70@js1
ぶつかったなら、方向を反転します。
yなので、上下方向の反転ですね。
:L72@js1
”上の壁にぶつかりましたか~?”
:L73@js1
方向を反転します。
:L73@js1
これで、「まる」は壁にぶつかると跳ね返る…という動きを表現できるんですねぇ。
x,yの増分に-1をかけるだけだなんて、めっちゃ簡単よね!
:L73@js1
実はこのプログラムの作者(web6047管理人)も「あれ?そうなんだ?」と思ったそうです。
:L75@js1
ここでframeは終わりまして…
:L37@js1
ここに戻ってきます。
for文がすべて終わったら、
:L39@js1
ドロウです!
描画ですね。
Appのdrawはすぐ下の
:L41@js1
これです。
:L42@js1
まず色を白にして、
:L43@js1
全体を消去!
:L44@js1
次にfor文でそれぞれの「まる」について、
:L45@js1
ドロウ!
Ballのdrawは、
:L76@js1
これ!
「まる」を描きたいので、
:L78@js1
アーク(arc)というメソッドで、下絵(まる)を描き、
:L81@js1
半透明モードにして、
:L82@js1
色を その「まる」の色にして、
:L83@js1
下絵を塗りつぶします。フィル!
:L84@js1
なお、この行のコメント(先頭の//)を取り外すと、残像がなくなりますよ。
:testcanvas
this.test( 2 );
この残像…きれいですけど、どうしてこうなったのか…作者もわからないそうです。
偶然 残像になって「イイゾ!」と言ってそのままにしたんだとか…
:testcanvas
もっと!こう!
「知的に筋道立ててこう考えたからこうできたんだゾ」って、
できないんですかねぇ?
:testcanvas
壁の反転のときも「あれ?そうなんだ?」
プログラマーってそんなもんなの??(プンプン)
:L45@js1
…ともかく、BallのdrawからAppのdrawに戻りまして、
:L46@js1
for文をすべて終えたら、
:L47@js1
Appのdrawも終わるので、
:L39@js1
Appのframeのここに戻ってきます。
:L40@js1
これでsetIntervalによる1コマ(frameメソッド呼び出し)が終わったわけです。
:L40@js1
位置を変えて、ドロウして、(1コマ)
位置を変えて、ドロウして、(1コマ)
位置を変えて、ドロウして、(1コマ)
:L40@js1
そして!
:testcanvas
this.test( 3 );
このようなアニメになっているんです★
:testcanvas
どうですか?
ざっと説明してきましたが、だいたいの流れはつかめましたか?
わかりづらいところもあったと思いますが、がんばってお勉強してくださいね。
みなさんのプログラミングの一助になれば幸いです。
:testcanvas
パチパチパチパチパチ
*/},
},
{
id : "testcanvas",
script : function() {/*
それではまた、サイナラ~!
・ ・ ・
消えまーす。
:testcanvas
this.hideChar();
*/},
},
],
}