宿題06の解説とヒント

1. Javascriptゲーム 08

問題

サンプル08のJavascriptを使ったページを作成し、キャラクターの初期位置、ネズミの速度などのパラメーターを調整して工夫をし、js09.htmlという名前で、hw/hw04/内にアップロードしなさい。

このゲームでは、ねずみのキャラクターをrequestAnimationFrame()関数で一定時間ごとに表示位置を書き換えることで、走り回るように変更した。このアニメーションは、[ネズミを活性化/凍結]ボタンで、再開と一時停止ができる。
本来ならば、ゲームの全ての情報をJavascriptで制御した方が効率が良いが、前回のサンプルを改造したので、ネズミのクリックや、チーズの移動の部分はCSSから得られる情報を使った形のままである。

id要素

この例では、以下ように4つのidが付けられた要素を用いている。

id="Bkg"
背景画像のIMG要素である。背景画像は500px×500pxのサイズで、ファイル名はbackground.pngである。
id="Nezumi1"
ねずみのキャラクターのDIV要素で、子要素にファイル名nezumi.pngのIMG要素を含んでいる。nezumi.pngのサイズは64px×64pxである。
CSSで、idセレクタ#Nezumi1のプロパティの定義で、position: absolute;を指定することで、親要素であるDIV要素の左上が(0,0)の原点になるようしている。leftプロパティはid="Nezumi1"の要素の左上の角のx座標、topプロパティはy座標になっている。
クリックするとジャンプするのは、<img src="nezumi.png" alt="ねずみ1" onClick="randomove('Nezumi1', D_nezumi)">のように、onClickのイベントハンドラーとしてrandomove()関数を呼び出して実行しているからである。
id="Nezumi2"
id="Nezumi1"と同様である。
id="Hole"
穴を表すDIV要素である。サイズは100px×100pxである。CSSで、idセレクタ#Holeのプロパティの定義で、position: absolute;を指定することで、親要素であるDIV要素の左上が(0,0)の原点になるようしている。leftプロパティは200px、topプロパティは200pxとしている。IMG要素は使用せず、background-color: #000000;で黒く塗りつぶしているだけである。
グローバル変数

以下のグローバル変数を使用している。

D_nezumi
ねずみをクリックしたときに、ランダムに移動するが、そのときの最大の移動量を格納する変数である。70px移動するように設定されている。この値を大きくすると、ねずみのジャンプ量が大きくなり、小さくすると少ししか動かなくなる。
num_nezumi
生き残っているネズミの総数を格納する変数。ネズミが池に落ちると、一つ減るようにする。この変数の値が0以下で、ゲーム終了とする。
V_nezumi
ネズミを活性化したときの、1フレームあたりの移動距離。
frame
アニメーションの1秒間あたりののフレーム数(コマ数)
ftime
frameから計算される1フレームの持続時間。単位はミリ秒(= 1/1000 秒)。
CH
登場するキャラクターの情報を格納する連想配列。具体的には、すぐ下で定義されるCH['Nezumi1']、CH['Nezumi2']、CH['Cheese']を、各々キー'Nezumi1'、'Nezumi2'、'Cheese'の値としている。CHの値CH['Nezumi1']自体も連想配列で、キーx, y, vx, vyを持つ。xはx座標、yはy座標、vxはx方向の速さ、vyはy方向の速さである。CH['Cheese']には、vx, vyは定義されていない。
D_cheese
キーを押したときにチーズが移動する距離
OVERLAP
ネズミとチーズの重なり具合を表す変数。touch()関数で二つの要素の重なりがあるかないかを判定するが、第3パラメータとして、そのときの重なり具合を決めるパラメータとして使用するためのグローバル変数である。これは、ねずみとチーズの重なり具合を定め、-40という値にしている。
OVERLAP_HOLE
ネズミ(やチーズ)と穴の重なり具合を表す変数。touch()関数で二つの要素の重なりがあるかないかを判定するが、第3パラメータとして、そのときの重なり具合を決めるパラメータとして使用するためのグローバル変数である。これは、ねずみと穴の重なり具合を定め、-60という値にしている。
msec
animate()関数で使用。フレームを書き換える間隔を表す。
requestId
window.requestAnimationFrame(animate)の戻り値を保持する変数。アニメーションを停止するときに、window.cancelAnimationFrame(requestId)のように引数に指定する。
lost
ゲームに負けたときにtrueとする。今回は未使用
finish
ゲームが終了したときにtrueとする。今回は未使用
関数(サブルーチン)

以下の関数を定義している。

initialize()
document.getElementIdBy()関数を使って、id="Nezumi1"、id="Nezumi2"、id="Hole"、id="Bkg"のx座標、y座標、幅、高さなどのプロパティを設定している。ページを読み込んだときに、このinitialize()関数を実行し(87行目)、CSSで設定した値をこれらのプロパティの値で上書きしている。
touch( obj1, obj2, overlap )
第一引数と第二引数の要素が重なっている場合は1、重なっていない場合は0を返す関数である。第三引数は重なりの条件を調節することができるパラメータで、0とすると調整なしの条件になる。randomove()関数の中で、ねずみと穴の重なりがあるかないかの判定に使用している。
coordinates(element)
要素のleftプロパティとtopプロパティの値は、"px"という単位が付いていいるので、正規表現を使って"px"を除いた数字部分だけを取り出す関数で、返り値はposition = {x: 0, y: 0};と初期化された連想配列である。
elmSize(element)
要素のwidthプロパティとheightプロパティの値は、"px"という単位が付いていいるので、正規表現を使って"px"を除いた数字部分だけを取り出す関数で、返り値はelm_size = {w: 0, h: 0};と初期化された連想配列である。
KeyDownFunc(e)
イベントリスナーで、キーが押されたときの処理をする関数である。key_code変数の値でどのキーが押されたのかを判断し、それに合わせてmove_cheese()関数で、押されたカーソルキーの方向にチーズを移動する。 また、id="Nezumi1"とid="Nezumi2"を、move2cheese()関数を使って、チーズの方向に移動している。
move_cheese(Delta_x, Delta_y)
チーズを移動する関数。移動後、穴に入ったか否かを判定している。
move2cheese(element_id, Delta)
ねずみをチーズの方向に移動する関数。移動後に、ねずみがチーズとぶつかったか、ねずみが穴に落ちたかを判定している。
randomove(element_id, Delta)
ねずみをランダムに移動する関数である。 OnClickイベントハンドラーとして使用する。 第一引数にはid名、第二引数は移動量の最大値である。また、移動したのち、穴(id="Hole")と重なった場合は、ねずみのキャラクターのdisplayプロパティを"none"にして、非表示にしている。ねずみがチーズをぶつかったか否かの判定を追加した。
move(element, dx, dy)
第一引数の要素を、第二、第三引数のx、y座標だけ移動して表示する関数である。randomove()、run()、move_cheese()、move2cheese()内で使用されている。このために、pstn = coordinates(element);のようにCSSのプロパティを参照することはやめて、連想配列CH[]の情報を使うように変更した。
start()
[ネズミの活性化/凍結]ボタンがクリックされたときに呼び出される。アニメーションの開始と停止を行う。
animate()
アニメーションを開始する
pause_animation()
アニメーションを停止する
run(element_id)
ネズミを走らせる。
ページの構造を理解するためのヒント

DIV要素に枠線を付けると、ページの構造が把握しやすくなる。 例えば、DIV要素に赤い枠線を表示するよにするには、STYLE要素の内容に以下のCSSの記述を追加すれば良い。

div {
   border: solid thin red;
}

戻る