言語村 トップページ






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




皇帝流テトリス





皇帝流テトリスの作り方

 その4へ戻る


その5 「次のブロック」を表示しよう



すかじい うおっほん。
今回は、次のブロックを表示してみよう。
自動で次々とブロックを表示するので、
ようやくJavaScriptっぽくなるぞい。

ひろちゃん皇帝 やっとゲームっぽくなるんだね!?


すかじい
いや、まだそこまではいかないがな。
でも、JavaScriptの処理を目で見ることができるので、面白くなってくるぞい。


りな姫 前回までで、ゲームの初期化をしてメインルーチンが動く所まで
できたわね。


すかじい
そうじゃ。今回はそのメインルーチンの次の動きを作ることになる。

流れとしては、「次のブロック」を「落ちるブロック」に渡してから
新しく「次のブロック」を作って表示する
という感じになる。

では、ソースを見てみようかの。
今回はHTML部分の変更が無いので、JavaScript部分のみ載せているぞい。


<script language="JavaScript">
<!--

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

cr = "\r\n"
mojiretu= "";	// 画面に表示する文字列取得用
width = 8;	// 画面の広さ
height = 20;	// 画面の高さ
blockNo = 0;	// ブロックの種類保存用
blockNo2 = 0;	// 次のブロックの種類保存用
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 MakeNextBlock( number ) {
	switch ( number ) {
		case 0:
			mojiretu =	"□□■□" + cr +
				  	"□□■□" + cr +
				  	"□□■□" + cr +
				  	"□□■□";
			break;
		case 1:
			mojiretu =	"□□□□" + cr +
					"□□■□" + cr +
					"□□■□" + cr +
					"□■■□";
			break;
		case 2:
			mojiretu =	"□□□□" + cr +
					"□■□□" + cr +
					"□■□□" + cr +
					"□■■□";
			break;
		case 3:
			mojiretu =	"□□□□" + cr +
					"□■■□" + cr +
					"□□■■" + cr +
					"□□□□";
			break;
		case 4:
			mojiretu =	"□□□□" + cr +
					"□■■□" + cr +
					"■■□□" + cr +
					"□□□□";
			break;
		case 5:
			mojiretu =	"□□□□" + cr +
					"□□■□" + cr +
					"□■■■" + cr +
					"□□□□";
			break;
		case 6:
			mojiretu =	"□□□□" + cr +
					"□■■□" + cr +
					"□■■□" + cr +
					"□□□□";
			break;
	}
	document.game.tugi.value = mojiretu;
}


// 初期化用関数 -------------------------------------------------------------------
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;
	
	// 最初に落ちるブロックを決める
	blockNo2 = Math.floor( Math.random() * 7 );
}



// 仮想画面を表示する関数
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:
				// 落下するブロックと、次落下するブロックを設定
				blockNo = blockNo2;
				blockNo2 = Math.floor( Math.random() * 7 );
				
				// 次落下するブロックを描く
				MakeNextBlock( blockNo2 );
				
				break;
		}
	}
	window.setTimeout( "Main()", speed );
}




// -->
</script>


リナ姫
新しく追加する部分に、ブロックの形がそのまま見えるわね。
「その3」で作った初期化処理の、「次画面をクリアする」によく似ているわね。


すかじい
そうじゃ。そのブロックの形がそのまま「次画面」に表示されるのじゃ。
では、詳しくプログラムを見てみよう。


ひろちゃん皇帝
変数が新しく2つ追加されているね。


すかじい
うむ。
blockNo、blockNo2 という変数は、ブロックの形を覚えておく変数じゃ。
blockNoが、現在落ちてくるブロック、
blockNo2が、次画面に表示されているブロック という役割で使っておる。
ちなみに今回は blockNo は登場するのみであまり使われておらん。
「次のブロック」を表示する処理を作っていくので、blockNo2 が使われることになるぞ。

まず初期化用関数 Syokika() を見てみよう。
追加されたのは1行じゃ。


ひろちゃん皇帝
最初に落ちるブロックを決める処理?
blockNo2 = Math.floor( Math.random() * 7 );
なんか難しそうだなあ・・・。
Math.floor()、Math.random() って何? なんで 7 を掛けてるの?


すかじい
少しずつ見ていこう。
まず、Math.random() についてじゃ。
random() という関数は、乱数を作る関数じゃ。


リナ姫
らんすう?


すかじい
でたらめな数のことじゃ。
コンピューターは、決まったことを行うのは大変得意なのじゃが、思いつきやでたらめなことを行うのがすごく苦手なんじゃ。
だから、次に表示されるブロックをでたらめに作ろうと思うとけっこう難しいんじゃな。
そういう時に乱数を使うんじゃ。
random() では、関数が呼ばれるたびに0以上1未満のでたらめな数が作られるんじゃ。
0〜0.999999・・・・までのでたらめな数、ということじゃな。


ひろちゃん皇帝
すかじい、さっきコンピュータはでたらめなことが苦手だって言ったのに、なんででたらめな数が出てくるの?


すかじい
いい質問じゃな。
でたらめになりそうなものを使ってでたらめな数を作っているんじゃ。
簡単に言うとたとえば、random()関数が呼ばれた時パソコンを起動してから何ミリ秒経っているか、なんて誰にも解らないじゃろ。
そういう誰にも予測つかないことをいろいろとからめて、でたらめな数を作っておる。


ひろちゃん皇帝
ふ〜ん。


すかじい
次の floor() というのは、繰り下げの関数じゃ。
3.6 も 3.4 も全部整数の 3 になる。
余談じゃが、-3.6、-3.4 は どちらも -4 になる。
「切り捨て」では無く「繰り下げ」関数と呼ばれる所以じゃな。

random() も floor() も 頭に Math というのが付いておるな。
この Math というのは、数学に関係した関数などが集まったオブジェクトじゃ。
random()もfloor()も、Math という集まりの中の1つ、ということじゃな。
もっとも、難しい話なので、乱数は Math.random() みたいに覚えてしまってOKじゃ。

さて、ここまで解説したが、「最初に落ちるブロックを決める」処理で何をやっているか解るかな?


リナ姫
つまり、0〜0.99999・・・に 7 を掛けているんだから、この値は 0〜0.699999・・・ということね。
それに Math.floor() で繰り下げしているから・・・・。


ひろちゃん皇帝
そっか!
ここでは、0,1,2,3,4,5,6 のどれかが blockNo2 に入るんだね!


すかじい
そのとおりじゃ。この0〜6の7つの数は、7種類のブロック
(長いもの、クランク2つ、L型2つ、T型、四角)
に対応しておる。
どの数字がどのブロックかは、後で説明するぞ。

さて、初期化処理終了後、ユーザーがボタンをどれか押すと、メインルーチンが起動するんじゃったな?
そこでメインルーチンを見てみよう。


ひろちゃん皇帝
ここでもさっきと同じ、乱数を使った計算が出てきているね。


すかじい
そうじゃな。
詳しく見てみよう。
ボタンが押されると、gameflag が true になり、メインルーチンのswitch文の case 0: が実行されるのは前回説明したとおりじゃ。
その次の処理では、「次のブロック」の値を、「落ちるブロック」に設定しておる。
つまり、「次のブロック」が「今落下しているブロック」になってしまったから、その次では新たに「次のブロック」を作っておる。
さっきの乱数の作成部分と全く同じなのは、そういう理由じゃ。


リナ姫
ということは、最初の乱数の計算は、最初に落下させるブロックを「次のブロック」に設定し、メインルーチンが起動した時に「今落ちるブロック」にするためのものだったのね。


すかじい
そういうことじゃ。メインルーチン内の処理の下準備をしていたわけじゃ。

その次は、新たな関数を呼び出しているだけじゃ。


ひろちゃん皇帝
MakeNextBlock()っていう関数だね。
ブロックの形がそのまま描いてあったところだ。


すかじい
そうじゃ。ここで、「次のブロック」の描画を行っておる。
この関数が何をやっているか、なんとなくわかるのではないかな?


リナ姫
switch 文 は、前回教えてもらったわね。
引数の number は blockNo2 のことね。
つまり、blockNo2 の値によって、ブロックを書き分けているのね。


ひろちゃん皇帝
え〜っと、
0 が
□□■□
□□■□
□□■□
□□■□
1が
□□□□
□□■□
□□■□
□■■□
2が
□□□□
□■□□
□■□□
□■■□
3が
□□□□
□■■□
□□■■
□□□□
4が
□□□□
□■■□
■■□□
□□□□
5が
□□□□
□□■□
□■■■
□□□□
6が
□□□□
□■■□
□■■□
□□□□
になるんだ!

すかじい
そのとおりじゃ。
ブロックを選んだあとは、document.game.tugi.value で画面に表示しておる。
それでこの関数の処理は終了じゃ。
またメインルーチンに戻ることになるのだが、この後の処理はどうなるか解るかな?


ひろちゃん皇帝
前回教えてもらったことから考えると、メインルーチンの一番最後の setTimeout() で、1秒ごとにまたメインルーチンが呼ばれるんだよね?


リナ姫
ということは、すかじいが最初に言っていたように、1秒ごとに「次のブロック」が次々と表示される、ということかしら?


すかじい
そういうことじゃ。
実際にボタンを押して確かめるとよいぞ!


ひろちゃん皇帝
うわ、「次のブロック」が次々と表示されるぞ〜。




Next


Level
その6 ブロックを動かそうへ続く・・・