言語村 トップページ






皇帝流
テトリスの作り方
トップページ




皇帝流テトリス





皇帝流テトリスの作り方

 その3へ戻る


その4 メインルーチンを作ろう



すかじい うおっほん。
今回は、メインルーチンを作ってみよう。

ひろちゃん皇帝 すかじい、「メインルーチン」って何?


すかじい
メインルーチンとは、プログラムの中心的な処理を行う部分のことじゃ。
いわばプログラムの司令塔じゃな。


りな姫 え?まだ完成からは程遠いのに、
いきなり司令塔を作って大丈夫なの???


すかじい
ふぉっふぉっふぉ。そう思うのももっともじゃが、ソース自体は非常に短いんじゃ。
とりあえずソースを見てみようかの。
今回はHTML部分も含んでおる。
赤い部分が前回からの追加部分じゃ。


<html>
<head>
<title>テトリスもどき</title>
<script language="JavaScript">
<!--

// 使用する変数の宣言 --------------------------------------------------------

cr = "\r\n"
mojiretu= "";	// 画面に表示する文字列取得用
width = 8;	// 画面の広さ
height = 20;	// 画面の高さ
gameflag = false;	// ゲーム中かどうかのフラグ
mode = 0;		// 現在のゲームの状態チェック用変数
speed = 1000;		// 次の処理へ進むスピード
score = 0;		// スコア
level = 1;		// レベル

// 仮想VRAM用2次配列
vr = new Array( width );
for ( i = 0; i < width; i++ ) {
	vr[i] = new Array( height );
}


// 初期化用関数 -------------------------------------------------------------------
function Syokika() {
	
	// 変数の初期化
	gameflag = false;
	mode = 0;
	score = 0;
	level = 1;
	speed = 1000;
	
	for ( i = 0; i < height; i++ ) {
		for ( j = 0; j < width; j++ ) {
			vr[j][i] = "□";	// 仮想画面クリア
		}
	}
	// 仮想画面を表示する
	Hyouji();
	
	// 次画面をクリアする
	mojiretu =	"□□□□" + cr +
			"□□□□" + cr +
			"□□□□" + cr +
			"□□□□";
	document.game.tugi.value = mojiretu;
	
}



// 仮想画面を表示する関数
function Hyouji() {
	// 画面に表示する文字列の作成
	mojiretu = "";
	for ( i = 0; i < height; i++) {
		for ( j = 0; j < width; j++ ) {
			mojiretu = mojiretu + vr[j][i];
		}
		if ( i != height - 1 ) {
			mojiretu = mojiretu + cr;
		}
	}
	// 画面の表示
	document.game.gamen.value = mojiretu;
	document.game.SCORE.value = score;
	document.game.LEVEL.value = level;
}


// 各ボタンに対する関数
// 回転
function Moveturn() {
	// ゲームが始まっていない時は、ゲームを始める
	if ( !( gameflag ) ) {
		gameflag = true;
		Main();
	}
}
// 左
function Moveleft() {
	// ゲームが始まっていない時は、ゲームを始める
	if ( !( gameflag ) ) {
		gameflag = true;
		Main();
	}
}
// 右
function Moveright() {
	// ゲームが始まっていない時は、ゲームを始める
	if ( !( gameflag ) ) {
		gameflag = true;
		Main();
	}
}
// 下
function Movedown() {
	// ゲームが始まっていない時は、ゲームを始める
	if ( !( gameflag ) ) {
		gameflag = true;
		Main();
	}
}


// メインルーチン
function Main() {
	// ゲームが始まっている時のみ処理をする
	if ( gameflag ) {
		// ゲームの状態によって、処理を変える
		switch ( mode ) {
			case 0:
				
				break;
		}
	}
	window.setTimeout( "Main()", speed );
}




// -->
</script>
</head>
<body onload="Syokika()">
<form name="game">
<center>
<table>
<tr><td>
</td><td>
	<input type="text" name="SCORE" size="20">
</td><tr>
<tr><td valign="top">
	<textarea name="tugi" rows="4" cols="10"></textarea><br>
	Next<br><br>
	<input type="text" name="LEVEL" size="5"><br>
	Level
</td><td>
	<textarea name="gamen" rows="20" cols="20"></textarea>
	<table>
	<tr align="center">
	<td colspan="2">
		<input type="button" name="TURN" value="TURN" onclick="Moveturn()">
	</td>
	</tr>
	<tr align="center">
	<td>
		<input type="button" name="LEFT" value=" LEFT" onclick="Moveleft()">
	</td>
	<td>
		<input type="button" name="RIGHT" value="RIGHT" onclick="Moveright()">
	</td>
	</tr>
	<tr align="center">
	<td colspan="2">
		<input type="button" name="DOWN" value="DOWN" onclick="Movedown()">
	</td>
	</tr>
	</table>
</td></tr>
</table>
</center>
</form>
</body>
</html>


ひろちゃん皇帝
本当だ。司令塔って言う割に、追加部分は少ないんだね。


すかじい
function Main() 部分で Main()関数を定義しているが、これがメインルーチンの全貌じゃ。
もっとも、今後処理が増えてくると、メインルーチンの中もいろいろと追加が出てくるがの。
そうは言っても、メインルーチンはできるだけシンプルにしておくのがベストじゃ。


ひろちゃん皇帝
なぜシンプルなのがいいの?


すかじい
メインルーチンが何をやっているのか解りやすく書くことが、ソース全体を読みやすくすることに繋がるからじゃ。
メインルーチンでは、関数をどういう順番で呼ぶのか?と言うことのみの処理に集中し、実際の処理は関数の中に書いていく、という作りが解りやすくてベストじゃ。


リナ姫
ということは、今後、このMain()関数からいろいろな関数が呼ばれる処理が追加されるのね?


すかじい
うむ。そういうことじゃ。

さて、ソースの説明を行う前に、イベントドリブンについて話しておこう。
JavaScriptを理解するうえで、重要な概念だ。


ひろちゃん皇帝
イベントドリブン???


すかじい
イベントドリブンとは、操作する人が何かを行った時だけ動作をする仕組みのことじゃ。
ボタンを押した時や、マウスを動かした時、などじゃな。
それ以外の時は、誰かが操作するまでず〜っと待機しておる。


ひろちゃん皇帝
え〜?それだったら、誰かが操作するまでゲームが進まなくなってしまうよ???
ブロックが勝手に落ちてきたりしなくなってしまうよ?


すかじい
いい質問じゃな。
つまりイベントドリブンはボタンが押された時だけ処理をする、というような処理には向いているのじゃが、継続的に処理を行う、ということには向いていないんじゃ。
そこで、setTimeout() という関数を使うことになる。
この関数は、指定した時間ごとに別の関数を呼ぶことができるので、誰かが操作しなくても関数を起動することができるんじゃ。
詳しい使い方は、ソースの説明の中で行うぞ。

では、ソースの説明に移ろう。

先ほど話したMain()関数がどうやって呼ばれるか解るかな?


ひろちゃん皇帝
え〜っと、前回作った初期化用の関数からは呼ばれていないなあ。
あっ!「各ボタンに対する関数」のところに Main() ってのがある!


すかじい
では、その「各ボタンに対する関数」は、どうやって呼ばれるのか解るかな?

リナ姫
それは、「その2」の時にちょっと出てきたわ。
HTML部分の各ボタンのINPUTタグに書かれていて、確かボタンが押された時にその関数が呼ばれるんだったわね?


ひろちゃん皇帝
そっか!それが「イベントドリブン」なんだ!!


すかじい
そのとおりじゃ。
各ボタンのINPUTタグにある「onclick=""」というのが、ボタンが押された時に処理を行うイベントドリブンの正体じゃ。

ちょっと流れを整理してみよう。

まず、最初の方で変数を追加しておるが、その中に「gameflag」という変数があり、Syokika()関数内で false に設定されておる。
これは、現在ゲーム中かどうかを判断するフラグとして使用しており、ゲーム中なら true 、違うなら false になる。
最初はゲームが始まっていないので、初期値は false になる。

次に、「TURN」「LEFT」「RIGHT」「DOWN」のどれかのボタンが押されると、それぞれのボタン用の関数が呼ばれる。
その各ボタン用の関数では、gameflag を見て、ゲームが始まっていない(false)ならゲームが始まったことにし、(true)その後 Main() 関数を呼んでおる。

Main() 関数についてじゃが、ゲームが始まっているかどうかチェックをして、ゲームが始まっている時のみ次の switch 文が実行される。


ひろちゃん皇帝
switch 文って何?

すかじい
if文などのように何かを判断する構文の一つで、switch に指定された値によって、その次の case 〜 break までの間が実行される。
現在は case 文が1つなので解りにくいが、今後 case 文が増えてくると、理解できるじゃろ。
今回追加した mode という変数が、Syokika() 関数で0に設定されているが、0の場合のみ、この case 0:〜 break; が実行されるのじゃ。
今は case 〜 break の間に命令が無いので、何も行われないがな。


リナ姫
一番最後にあるのが、さっき話していた setTimeout() 関数ね?


すかじい
そうじゃ。
window.setTimeout( "Main()", speed );
という書き方になっておるな。
最初の window は、今開いているwindowオブジェクトを表している。難しいので解らなくてもOKじゃ。オブジェクト指向を学べば解るようになるぞ。
setTimeout() 関数は、windowオブジェクトが最初から持っている関数じゃ。自分で作る関数では無いのじゃ。
だから、構文も決まっておる。
window.setTimeout( "Main()", speed ); のように、引数はJavaScriptの構文(文字列)と、その関数を呼ぶまでの待ち時間(数値)じゃ。
今回はJavaScriptの構文として、Main()関数を呼び出す処理が書かれておる。
また、待ち時間の単位は、ミリ秒じゃ。


ひろちゃん皇帝
え〜っと、今回追加した speed 変数は、Syokika() 関数で1000に設定されているから・・・。
次に Main() 関数が呼ばれるのは1秒後ってこと?


すかじい
そのとおり。
自分で自分の関数を呼び出しているから、この関数内で処理がぐるぐる回るのが解るじゃろ。
この Main() 関数を通ると、それ以後は speed の値ごとにMain()関数が呼ばれる、というわけじゃ。

今回のプログラムでは、前回と見た目は変わらないが、ボタンを押すと1秒ごとにMain()関数が呼ばれておるのじゃ。



Next


Level
その5 「次のブロック」を表示しようへ続く・・・