イベント
これで、実行時に自由にHTMLドキュメント内の要素を変更できるようになりました。これまでのプログラムは、BODY
要素の子要素としてSCRIPT
要素を記述し、HTML ドキュメントが読み込まれている途中にスクリプトを実装してきました。しかし、ゲームはユーザーの操作や入力に反応してドキュメントを変更させる必要があります。これには、要素オブジェクトのイベントを利用します。
イベントに反応することで、マウスがクリックされた時にスクリプトを実行できるようになります。イベントは、HTML要素の属性として指定することができます。処理できるイベントは要素ごとに異なりますが、マウスやキーボードなどのイベントについては多くの要素で共通しています。onから始まるイベント属性に、次のようなものがあります。
イベント名 | 発生条件 |
onclick | オブジェクト上でクリックされたときに発生する。 |
ondblclick | オブジェクト上でダブルクリックされたときに発生する。 |
onmousedown | オブジェクト上でマウスボタンが押されたときに発生する。 |
onmouseup | オブジェクト上でマウスボタンが離されたときに発生する。 |
onmousemove | オブジェクト上でマウスカーソルを動かしたときに発生する。 |
onmouseover | オブジェクト上にマウスカーソルが入ったときに1度だけ発生する。 |
onmouseout | オブジェクト上からマウスカーソルが外に出たときに発生する。 |
onkeydown | ユーザーがキーを押したときに発生する。 |
onkeyup | ユーザーがキーを離したときに発生する。 |
onload | オブジェクトがブラウザに読み込まれた直後に発生する。 |
この他にもいくつかのイベントが要素オブジェクトごとに存在しますが、代表的なイベントは上記の表にあるようなマウスやキーボード関連のイベントでしょう。onload
イベントはBODY
要素やIMG
要素に指定し、ブラウザにドキュメントやイメージが完全に読み込まれたときに実行させたいスクリプトに使います。
イベントに反応して起動するスクリプトをイベントハンドラと呼びます。イベントハンドラとなる関数を要素と関連付ける方法はいくつかありますが、最も簡単で代表的な方法はHTMLテキスト上で要素の属性としてイベントハンドラを記述する方法でしょう。例えば、イメージ上で発生したクリックイベントを処理するには次のように記述します。
<img src="ソースURL" onclick="イベント処理スクリプト">
onclick
属性の値は実行するスクリプトそのものです。ここに直接スクリプトコードを記述することもできますが、HTMLソースの可読性を考えると、HEAD
要素内などでスクリプトの関数を作成して、イベント発生時に対応するメソッドを呼び出したほうがスマートです。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>サンプル 05</title> <script language="javascript"> function imgMouseDown() { label.innerHTML = "マウスボタンが押されました"; } function imgMouseUp() { label.innerHTML = "マウスボタンが離されました"; } function imgMouseOver() { label.innerHTML = "マウスカーソルが入りました"; } function imgMouseLeave() { label.innerHTML = "マウスカーソルが外に出ました"; } </script> </head> <body> <p id="label">ここにイベント情報を表示します</p> <img src="test00.jpg" onmousedown="imgMouseDown()" onmouseup="imgMouseUp()" onmouseover="imgMouseOver()" onmouseleave="imgMouseLeave()" > </body> </html>
このプログラムは、表示されているイメージ上でカーソルを動かしたり、マウスボタンを押すと、ユーザーの入力に反応してイベントが起動し、P
要素のテキストが動的に変更されるというプログラムです。例えば、マウスのボタンをイメージ上で押すと、IMG
要素のonmousedown
属性に記述しているスクリプト(イベントハンドラ)が実行されます。
この他に、SCRIPT
要素で直接イベントを処理するスクリプトコードを宣言してしまう方法があります。HTMLはデータ構造を記述するためのデータ記述言語なので、プログラムコードを記述するプログラミング言語との相性は良いものではありません。この記法はあまり見かけませんが、HTMLのデータ構造とプログラムを分離したいときに使うことができます。SCRIPT
要素でイベントハンドラを定義するには次のように記述します。
<script for="オブジェクト名" event="イベント" language="JavaScript"> //イベント処理スクリプトコード </script>
for
属性には、このイベントハンドラの対象オブジェクトのid
属性と一致する識別子を指定します。event
属性には処理するイベントを指定します。例えば、for
属性にlabel
、event
属性にonclick
を指定したすると、label
という名前の要素オブジェクト上で発生したクリックイベントを定義することになります。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>サンプル 06</title> <script for="image" event="onmousedown" language="javascript"> if (image.alt != "test00.jpg"){ image.src = "test00.jpg"; image.alt = "test00.jpg"; } else { image.src = "test01.jpg"; image.alt = "test01.jpg"; } </script> </head> <body> <p>イメージをクリックしてください</p> <img src="test00.jpg" id="image" alt="test00.jpg"> </body> </html>
このプログラムは、表示されているイメージをクリックするとsrc
属性を変更してイメージを切り替えるというプログラムです。BODY
要素の中を見ると、IMG
要素にはonmousedown
属性を指定していません。その代わりにHEAD
要素内にスクリプトを記述し、SCRIPT
要素のfor
属性とevent
属性で、処理対象のオブジェクトとイベントを指定しています。
この記法は、HTMLデザイナとスクリプタが異なる人物で、組織的に開発を進める際に採用するべきです。デザイナは専門外のスクリプトの記述を避け、専門とするデザインに集中することができ、スクリプタもデータ構造に関係なく目的のコードの記述に専念することができます。
実際には、イベントは要素オブジェクトが保有するプロパティの一種です。onから始まるイベント用プロパティは、イベントハンドラとなる関数へのポインタを保存しているだけなので、スクリプト実行時にイベントハンドラをオブジェクトに与えたり、イベントハンドラを組み替えることができます。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>サンプル 06</title> <script language="javascript"> function image_Click1() { image.src = "test00.jpg"; image.onclick = image_Click2; } function image_Click2() { image.src = "test01.jpg"; image.onclick = image_Click1; } </script> </head> <body> <p>イメージをクリックしてください</p> <img src="test00.jpg" id="image" onclick="image_Click2()"> </body> </html>
これは前のプログラムと同じように、イメージをクリックすると表示されるイメージを切り替えるプログラムですが、実装方法が異なっています。IMG
要素では、onclick
属性を指定してクリックイベント発生時にimage_Click2()
関数を呼び出すように設定していますが、image_Click2()
関数ではimage
オブジェクトのonclick
イベントプロパティを書き換えてimage_Click1()
関数を代入しています。これは、image_Click1()
関数のポインタをonclick
プロパティに与えています。その後、image
オブジェクトで発生したクリックイベントはimage_Click1()
関数を呼び出すようになります。同様にimage_Click1()
関数が実行されるとonclick
プロパティが再び書き換えられてimage_Click2()
が呼び出されるようになります。実行時にイベントハンドラを変更したい場合に、この方法を使うことができます。
イベント情報
イベントハンドラを設定することで、クリックやマウスカーソルの移動など、ユーザーの入力にプログラムが反応できるようになりました。ただし、これだけでは不十分な場合が多いでしょう。マウスのクリックや移動に関するイベントを処理する時には、どのボタンが押されたのかや、カーソルの座標などの情報が必要になります。キーイベントであれば、入力されたキーの文字が何かを取得する必要があるかもしれません。
こうした情報を取得するには、イベントハンドラ内でevent
オブジェクトを使います。event
オブジェクトは発生したイベントの情報を提供するオブジェクトです。そのため、イベントハンドラ内でのみ有効なオブジェクトとなります。例えば、イベント発生時のマウスのX座標はx
プロパティで、Y 座標はy
プロパティで取得します。この座標は、イベントが発生したオブジェクトの左上隅を0とする相対座標です。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>サンプル 08</title> <script language="javascript"> function img_MouseMove() { label.innerHTML = "MouawMove: X=" + event.x + ", Y=" + event.y; } </script> </head> <body> <p id="label">イメージ上でカーソルを動かしてください</p> <img src="test00.jpg" onmousemove="img_MouseMove()"> </body> </html>
このプログラムは、表示したイメージ上でマウスカーソルが移動すると、P
要素の内部テキストとしてイベント発生時のマウス座標を表示します。img_MouseMove()
関数内で、event
オブジェクトからx
とy
プロパティの値を参照していることに注目してください。
他にも、例えばクリックイベントで押されたボタンが何かを知りたい場合は、button
プロパティから取得することができます。button
プロパティは0~4までの数値で押されているボタンを表します。
値 | 状態 |
0 | どれも押されていない。 |
1 | 左ボタンが押された。 |
2 | 右ボタンが押された。 |
4 | 中央のボタンが押された。 |
キー入力イベントであれば、押されたキーの文字コードをkeyCode
プロパティから取得することができます。こうした座標やキー情報は、ゲーム画面上でユーザーが操作するキャラクターを移動させるなどの処理に利用できるでしょう。
サンプルゲーム
さて、今回はJavaScriptとDHTMLによる動的なページの開発方法について、その中でも特に基本的な内容を解説してきました。これまでのまとめとしてタイピングゲームを作成します。タイピングゲームは、画面上に表示されているアルファベット文字列の先頭と同じキーが押されると先頭の文字が削除される簡単な内容です。そのため、キーイベントの処理と、乱数でゲームを作ることができます。
タイピングゲームでは、タイプターゲットとなる文字列を表示するためのP
要素をドキュメント上で表示して、これにlabel
という名前をID
属性で指定するものとします。このP
要素に表示している文字列の先頭のアルファベットと同じキーがタイプされると、文字列から先頭の一文字だけを取り除いて、残りの文字を再表示させます。P
要素の内部テキストの変更にはinnerText
プロパティを使えばよいでしょう。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>サンプル 09</title> <script language="javascript"> var successful_count = 0; var failure_count = 0; var typeTargets = new Array( "LOVE", "HAVE", "GO", "DO", "MAKE", "TAKE", "GIVE", "GET", "SAY", "COME", "BE", "SEE", "LOOK", "KNOW", "THINK", "SEEM", "LIKE", "ASK", "TALK", "SPEAK", "HEAR", "LISTEN", "USE" ); function init() { label.innerHTML = next(); } function keyDown() { var text = label.innerHTML; var code = text.charCodeAt(0); if (event.keyCode == code) { text = text.substring(1, text.length); if (text.length == 0) text = next(); label.innerHTML = text; successful_count++; } else failure_count++ successful.innerHTML = successful_count; failure.innerHTML = failure_count; } function next() { var index = Math.round(Math.random() * (typeTargets.length - 1)); return typeTargets[index]; } </script> </head> <body onkeydown="keyDown()" onload="init()"> <table border="0" width="100%" height="100%"> <tr><td>成功数=<span id="successful">0</span> , 失敗数=<span id="failure">0</span></td></tr> <tr><th height="100%"><font size="7"><p id="label"></p> </font></th></tr> </table> </body> </html>
ページ上で発生したキー入力イベントを受け取るために、BODY
要素にonkeydown
属性を設定しています。この属性では、キー入力時のイベントハンドラとなるkeyDown()
関数を呼び出します。keyDown()
関数は、event
オブジェクトを調べて、label.innerHTML
プロパティの先頭文字とコードが等しいかどうかを調べ、等しければ文字列オブジェクトからsubstring()
関数を使って先頭の文字だけを取り除きます。
もし、substring()
の結果、全ての文字が削除されていればnext()
関数を呼び出して次に表示するべき文字列をランダムに取得します。この結果をlabel.innerHTML
プロパティに設定することで、画面上では次の単語が表示されます。画面に表示される文字列はnext()
関数がtypeTargets
配列オブジェクトの中から乱数を使ってランダムに選び出します。
最後に
今回作成したプログラムは、どれもHTMLドキュメントの静的な構造に、スクリプトから局所的な変更を加えるというものでした。ゲーム特有の画面を縦横無尽に動き回る演出や、BGM、効果音など、ゲームに不可欠な要素はどれも実現できていません。しかし、今回使ったinnerHTML
プロパティなどを駆使すれば、実行時に、自由にHTMLドキュメントの内容を変更することができるため、CSSによるレイアウト技術や画像演出と組み合わせることで、リッチなゲームを実現することができるようになるでしょう。
参考資料
- MSDNライブラリ 2005年4月