Edited at

[連載] javascriptで作るシューティングゲーム的な何か(1)

More than 1 year has passed since last update.


さあ、はじめよう


はじめに

本稿は掲題の通り javascript を用いて[ シューティングゲーム的な何か ]を作ろうという試みについて解説するテキストの第一回です。


想定する読者


  • 割と暇である

  • プログラミングに興味がある

  • ゲーム作りに興味がある

  • javascriptの基本をマスターしたけど特に作るものがない

  • javascriptを使った動きのある処理を実装してみたい

  • canvas でなんか作ってみたい


本連載の狙い

本連載はどちらかというと初心者向けです。

このページに検索からやってきた「ゲーム作りてえええええ」と日に三十回くらい叫んでいる小中学生諸君は、まずjavascriptの基本をお勉強してから本連載を読みましょう。

また、最終的に出来上がる[ シューティングゲーム的な何か ]は、そんなに大層なものではありません。シューティングゲームがどのような感じで作られていくのか、その過程を眺めていろいろ考えていただくキッカケを作ることが本連載の狙いです。

また、本連載では伝わりやすさ優先でテキストを書きます。たとえば javascript には厳密にはクラスはありませんが、連載内でクラスという言葉を使って解説します。このあたりは理解しやすさや、雰囲気を伝えることを優先して書きます。


オンラインサンプル

本連載は全10回を予定しています。

各回にはその時点までの[ シューティングゲーム的な何か ]のサンプルが付属します。

各テキストからリンクを張っておきますので、オンラインで実際に動作確認が行えます。

サンプルプログラム一式については著作権とかライセンスとかそういったものは一切ありません。

ちなみに、最終的に完成する[ シューティングゲーム的な何か ]はこんな感じです。

マウスによる移動、クリックによるショットが可能です。ESC キーでプログラムを停止します。

javascriptで作るシューティングゲーム的な何か(1)

javascriptで作るシューティングゲーム的な何か(2)

javascriptで作るシューティングゲーム的な何か(3)

javascriptで作るシューティングゲーム的な何か(4)

javascriptで作るシューティングゲーム的な何か(5)

javascriptで作るシューティングゲーム的な何か(6)

javascriptで作るシューティングゲーム的な何か(7)

javascriptで作るシューティングゲーム的な何か(8)

javascriptで作るシューティングゲーム的な何か(9)

javascriptで作るシューティングゲーム的な何か(最終回)


書いてる人

書いてる人はdoxasという人です。

こんな企画もやってますので、少しでも javascript でシューティングゲームを作成することに興味がわいたら、ぜひ参加してください。待ってますよ!!


さて、つくろう


サンプルの実行結果


まず適当に新しくフォルダを作りましょう。

そのなかに、次のような名前のテキストファイルを用意します。


  • index.html

  • main.js

  • common.js

main.js には、ゲーム全体の流れを管理する処理や、イベントに関連する処理を書いていきます。

common.js には、汎用的に利用するクラスなどを書きます。

それでは早速ですが、まずは index.html の中身からです。


index.html

<!DOCTYPE html>

<html>
<head>
<script src="common.js"></script>
<script src="main.js"></script>
<style>canvas {border: 1px solid gray;}</style>
</head>
<body>
<canvas id="screen"></canvas>
<p id="info"></p>
</body>
</html>

ふたつの javascript ファイルを読み込んでやり、body のなかには canvas タグと p タグを配置してあります。id をそれぞれに付加しておき、javascript から参照できるようにしておきます。

ちなみに canvas が目で見てわかりやすいように枠線だけスタイルを当てています。

ここまでは簡単ですね。


common.js

common.js には、先述の通り汎用的なクラスを記述しますが、今回は制作するのがシューティングゲームですので、シューティングゲームを作成するうえで助けとなる 座標を扱うクラス を記述しておきます。

とは言っても、まだ初回なので下記のように非常に簡素です。


common.js

function Point(){

this.x = 0;
this.y = 0;
}

要は X と Y のふたつの座標情報を格納するためだけのクラスです。

このあたりはいずれ、必要に応じて拡張していきましょう。


main.js

さてプログラムの本丸となる main.js です。

こちらはちょっとコードの量が多いですが臆せずいきましょう。


main.js

// - global -------------------------------------------------------------------

var screenCanvas, info;
var run = true;
var fps = 1000 / 30;
var mouse = new Point();

// - main ---------------------------------------------------------------------
window.onload = function(){

// スクリーンの初期化
screenCanvas = document.getElementById('screen');
screenCanvas.width = 256;
screenCanvas.height = 256;

// イベントの登録
screenCanvas.addEventListener('mousemove', mouseMove, true);
window.addEventListener('keydown', keyDown, true);

// エレメント関連
info = document.getElementById('info');

// ループ処理を呼び出す
(function(){
// HTMLを更新
info.innerHTML = mouse.x + ' : ' + mouse.y;

// フラグにより再帰呼び出し
if(run){setTimeout(arguments.callee, fps);}
})();
};

// - event --------------------------------------------------------------------
function mouseMove(event){
// マウスカーソル座標の更新
mouse.x = event.clientX - screenCanvas.offsetLeft;
mouse.y = event.clientY - screenCanvas.offsetTop;
}

function keyDown(event){
// キーコードを取得
var ck = event.keyCode;

// Escキーが押されていたらフラグを降ろす
if(ck === 27){run = false;}
}


window.onloadに、ページの読み込み完了と同時にプログラムが動き出すように関数を仕込みます。これがメインのプログラムになります。

main.js にはこのほか、マウスカーソルの位置を拾うためのmouseMoveと、キーの入力を拾うためのkeyDownが含まれます。


グローバル変数

グローバルな変数には index.html で記述しておいた canvas と p を参照するための変数screenCanvasinfoのほか、以下のものが含まれます。


  • run = ゲームの処理を継続するかどうかのフラグ

  • fps = ゲームの更新頻度を表す FPS

  • mouse = マウスカーソルの座標を格納する


main.js:グローバル変数の部分を抜粋

var screenCanvas, info;

var run = true;
var fps = 1000 / 30;
var mouse = new Point();

変数runは、真偽値を格納します。

この変数の中身がfalseならゲームの進行をストップし、trueならゲームを継続します。

変数fpsはゲームを更新する頻度を ミリ秒 単位で格納しておくために使います。

1000ミリ秒=1秒 なので、今回の場合は 1 秒間に約 30 回更新されるゲームになるということですね。

変数mouseには common.js で記述したPointクラスをさっそく利用して、マウスカーソルの座標位置を格納するためのインスタンスを作っておきます。


まずは初期化

ゲームでは、絶えずスクリーンを更新し続けます。

更新し続ける、というと難しい感じがするかもしれませんが、要はキャラクターを繰り返し少しずつ動かしていくことによってアニメーションさせるわけです。

まずは初期化を行っている部分を抜粋して見てみます。


main.js初期化部分を抜粋

    // スクリーンの初期化

screenCanvas = document.getElementById('screen');
screenCanvas.width = 256;
screenCanvas.height = 256;

// イベントの登録
screenCanvas.addEventListener('mousemove', mouseMove, true);
window.addEventListener('keydown', keyDown, true);

// エレメント関連
info = document.getElementById('info');


スクリーンとはすなわち canvas のことです。

getElementByIdを使って canvas への参照を取得して、大きさを変更しておきましょう。

今回は、スクリーンのサイズは 256 ピクセルとしました。

イベントの登録にはaddEventListenerを使っています。

登録している関数については後述しますが、要はマウスカーソルの位置を検知するための関数と、キー入力を検知するための関数のふたつを登録しています。

変数infoには HTML 内の p タグへの参照を入れておきます。

この p タグの中身を動的に書き換えてコンソール出力のような感じで使います。


ループ処理

先ほども書いた通り、シューティングゲームとは絶えずスクリーンを更新し続けキャラクターを動かします。

そのためにループ構造を作り、画面を更新するなどの必要な処理をループ内に記述します。

ループ処理と言っても、一般的な for 文などによる繰り返し処理ではなく、本連載では無名関数を再帰的に呼び出す方法を使って繰り返し処理を実現します。


main.jsループ処理部分を抜粋

    (function(){

// HTMLを更新
info.innerHTML = mouse.x + ' : ' + mouse.y;

// フラグにより再帰呼び出し
if(run){setTimeout(arguments.callee, fps);}
})();


このようにsetTimeoutを用いて無名関数自体を再帰的に呼び出します。

このループ処理のなかでグローバル変数のmouseを使って HTML を更新しているのがわかると思います。

mouseの中身は、後述するイベント処理用の関数で更新されるようになっていますので、ループ処理のなかでは特に値を設定するような処理はしていません。


イベント処理用の関数

イベント処理には、次のふたつの関数を使っています。


main.jsイベント処理用の関数

function mouseMove(event){

// マウスカーソル座標の更新
mouse.x = event.clientX - screenCanvas.offsetLeft;
mouse.y = event.clientY - screenCanvas.offsetTop;
}

function keyDown(event){
// キーコードを取得
var ck = event.keyCode;

// Escキーが押されていたらフラグを降ろす
if(ck === 27){run = false;}
}


mouseMove関数は canvas 上でマウスカーソルが動いたとき、左上を原点とした X (横方向)と Y (縦方向)のそれぞれの座標を変数mouseに設定します。

keyDown関数はキーの入力があった際に動作し、キーコードからどのキーが押されたのか判断します。

キーコードが 27 の場合は ESC キーが押されています。本連載のサンプルプログラムは、この ESC キーによって動作をストップするようにするため、キーコードが 27 だったときにはゲームの進行を管理する変数runfalseを設定しています。


まとめ

かなり説明が簡素な感じですが、まず第一回はここまでです。

オンラインサンプル.01で実際に今回のサンプルの動作を確認できます。

canvas 上でマウスカーソルを動かすと、マウスカーソルの座標を p タグ内の HTML として動的に変更します。

また、ESC キーでメインプログラムの動作が停止する点についても、実際にサンプルを動かして確認しておくといいでしょう。