Javascriptでテトリスゲーム

実際の動作ページはこちら

スポンサーリンク

コード

ネットで色々参考にしてコピペして自分で改造して作ったので、ちゃんと出来てない部分が多い。
ぜひコメントでご指摘くださいm(_ _)m

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>

<div class="base">

<style>
<!--

body{
}

*{
	margin:0;
	padding:0;
}

#can{
	height:400px;
	margin:20px auto;
	background-color:#fff;
	border:3px solid #000;
}

.game{
	width:auto;
	max-width:400px;
	margin:0px auto;
	text-align:center;
}

.control1,.control2{
    display: flex;
}

.control2{
	justify-content:center;	
}

.control1{
	justify-content:space-between;	
}

.control1 span{
	display:block;
	width:100%;
	line-height:30px;
	background-color:#fff;
	border:1px solid #000;
	cursor: pointer;
	user-select: none;
}

.control1{
	margin-top:15px;
}

.control2{
	margin-top:15px;
}

.control2 span{
	display:block;
	width:80px;
	background-color:#fff;
	border:1px solid #000;
	line-height:30px;
	cursor: pointer;
	user-select: none;
}

#palent {
  text-align: center;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  margin: 0px auto;
  max-width:600px;
}

#navi_left{
	background-color:#efefef;
	width:20%;
}

#center{
	width:60%;
}

#navi_right{
	background-color:#efefef;
	width:20%;
}

span{
	user-select: none;
}
-->
</style>

<div class="game">

<canvas id="can"></canvas>

<div class="control1">
	<span onmousedown="left()">◀</span>
	<span onclick="down()">▼</span>
	<span onclick="rotate_1()">↻</span>
	<span onclick="right()">▶</span>
</div>

<div class="control2">
	<span onclick="start()">START</span>
	<span onclick="stop()">STOP</span>
</div>

</div>

<script>
//効果音を読み込み
const music1 = new Audio('music/pon.mp3');
const music2 = new Audio('music/pon.mp3');
const music3 = new Audio('music/pon.mp3');

var tap = 0;

window.addEventListener('load', function(){
	document.getElementById("can").addEventListener('touchstart', rotate_1);
	document.getElementById("navi_right").addEventListener('touchstart', right);
	document.getElementById("navi_left").addEventListener('touchstart', left);
});

//落ちるスピード
const GAME_SPEED = 1000;

//フィールドサイズ
const FIELD_COL = 10;
const FIELD_ROW = 20;

//ブロック一つのサイズ(ピクセル)
const BLOCK_SIZE = 30;

//スクリーンサイズ
const SCREEN_W = BLOCK_SIZE * FIELD_COL;
const SCREEN_H = BLOCK_SIZE * FIELD_ROW;

//テトロミノのサイズ
const TETRO_SIZE =4;

const TETRO_COLORS =[
	"#000",			//0空
	"#6CF",			//1水色
	"#F92",			//2オレンジ
	"#66F",			//3青
	"#C5C",			//4紫
	"#FD2",			//5黄色
	"#F44",			//6赤
	"#5B5"			//7緑
];

const TETRO_TYPES = [
	[],	// 0.空っぽ
	
	[					// 1.I
		[ 0, 0, 0, 0 ],
		[ 1, 1, 1, 1 ],
		[ 0, 0, 0, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 2.L
		[ 0, 1, 0, 0 ],
		[ 0, 1, 0, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 3.J
		[ 0, 0, 1, 0 ],
		[ 0, 0, 1, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 4.T
		[ 0, 1, 0, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 1, 0, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 5.O
		[ 0, 0, 0, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 6.Z
		[ 0, 0, 0, 0 ],
		[ 1, 1, 0, 0 ],
		[ 0, 1, 1, 0 ],
		[ 0, 0, 0, 0 ]
	],
	[					// 7.S
		[ 0, 0, 0, 0 ],
		[ 0, 1, 1, 0 ],
		[ 1, 1, 0, 0 ],
		[ 0, 0, 0, 0 ]
	]
];

//初期位置
const START_X = FIELD_COL/2 - TETRO_SIZE/2;
const START_Y = 0;

//テトロミノ本体
let tetro;
//テトロミノの形
let tetro_t;

//テトロミノの座標
let tetro_x = START_X;
let tetro_y = START_Y;

//フィールド本体
let field = [];

//ゲームオーバーフラグ
let over = false;

//キャンバス
let can = document.getElementById("can");
let con = can.getContext("2d");
can.width  = SCREEN_W;
can.height = SCREEN_H;

tetro_t = Math.floor( Math.random()*(TETRO_TYPES.length-1) )+1;
tetro = TETRO_TYPES[ tetro_t ];

init();
drawAll();

//初期化
function init()
{
	//フィールドのクリア
	for(let y=0; y<FIELD_ROW ; y++ )
	{
		field[y] = [];
		for(let x=0; x<FIELD_COL ; x++ )
		{
			field[y][x] =0;
		}
	}
	/*
	field[5][8]  = 1;
	field[19][9] = 1;
	field[19][0] = 1;
	*/
}

//ブロック一つを描画する
function drawBlock(x,y,c)
{
	let px = x * BLOCK_SIZE;
	let py = y * BLOCK_SIZE;
	con.fillStyle=TETRO_COLORS[c];
	con.fillRect(px,py,BLOCK_SIZE,BLOCK_SIZE);
	con.strokeStyle="black";
	con.strokeRect(px,py,BLOCK_SIZE,BLOCK_SIZE);
}

//全部描画する
function drawAll()
{
	con.clearRect(0,0,SCREEN_W,SCREEN_H);
	
	for(let y=0; y<FIELD_ROW ; y++ )
	{
		for(let x=0; x<FIELD_COL ; x++ )
		{
			if( field[y][x] )
			{
				drawBlock(x,y,field[y][x]);
			}
		}
	}
	for(let y=0; y<TETRO_SIZE ; y++ )
	{
		for(let x=0; x<TETRO_SIZE ; x++ )
		{
			if( tetro[y][x] )
			{
				drawBlock(tetro_x+x, tetro_y+y,tetro_t);
			}
		}
	}
	
	if(over)
	{
		let s="GAME OVER";
		con.font = "40px 'MS ゴシック'";
		let w = con.measureText(s).width;
		let x = SCREEN_W/2 - w/2;
		let y = SCREEN_H/2 - 20;
		con.lineWidth = 4;
		con.strokeText(s,x,y);
		con.fillStyle="white";
		con.fillText(s,x,y);
	}
}

// ブロックの衝突判定
function checkMove( mx,my ,ntetro)
{
	if( ntetro == undefined ) ntetro = tetro;
	
	for(let y=0; y<TETRO_SIZE ; y++ )
	{
		for(let x=0; x<TETRO_SIZE ; x++ )
		{
			if(  ntetro[y][x]  )
			{
				let nx = tetro_x + mx + x;
				let ny = tetro_y + my + y;
				
				if( ny < 0 ||
					nx < 0 ||
					ny >= FIELD_ROW ||
					nx >= FIELD_COL ||
					field[ny][nx] )
				{
					return false;
				}
			}
		}
	}
	
	return true;
}

// テトロの回転
function rotate()
{
	let ntetro = [];
	
	for(let y=0; y<TETRO_SIZE ; y++ )
	{
		ntetro[y]=[];
		for(let x=0; x<TETRO_SIZE ; x++ )
		{
			ntetro[y][x] = tetro[TETRO_SIZE-x-1][y];
			music3.currentTime = 0;
			music3.play();
		}
	}
	
	return ntetro;
}

//テトロを固定する
function fixTetro()
{
	for(let y=0; y<TETRO_SIZE ; y++ )
	{
		for(let x=0; x<TETRO_SIZE ; x++ )
		{
			if( tetro[y][x] )
			{
				field[tetro_y + y][tetro_x + x] = tetro_t;
			}
		}
	}
}

//ラインが揃ったかチェックして消す
function checkLine()
{
	let linec=0;
	for(let y=0; y<FIELD_ROW ; y++ )
	{
		let flag=true;
		
		for(let x=0; x<FIELD_COL ; x++ )
		{
			if( !field[y][x] )
			{
				flag=false;
				music1.play();
				break;
			}
		}
		
		if(flag)
		{
			linec++;
			
			for(let ny = y; ny>0 ;ny-- )
			{
				for(let nx=0;nx<FIELD_COL ; nx++)
				{
					field[ny][nx] = field[ny-1][nx];
					music2.play();
				}
			}
		}
	}
}

// ブロックの落ちる処理
function dropTetro()
{
	if(over)return;
	
	if( checkMove(  0, 1 ) )tetro_y++;
	else
	{
		fixTetro();
		checkLine();
		tetro_t = Math.floor( Math.random()*(TETRO_TYPES.length-1) )+1;
		tetro = TETRO_TYPES[ tetro_t ];
		tetro_x = START_X;
		tetro_y = START_Y;
		
		if( !checkMove(0,0) )
		{
			over=true;
		}
	}
	drawAll();

	repeat = setTimeout(dropTetro, GAME_SPEED);

}

dropTetro();

//キーボードが押された時の処理
document.onkeydown = function(e)
{
	if(over)return;
	
	switch( e.keyCode )
	{
		case 37:// 左
			if( checkMove( -1, 0 ) )tetro_x--;
			break;
		case 38:// 上
			//if( checkMove(  0,-1 ) )tetro_y--;
			break;
		case 39:// 右
			if( checkMove(  1, 0 ) )tetro_x++;
			break;
		case 40:// 下
			if( checkMove(  0, 1 ) )tetro_y++;
			break;
		case 32:// スペース
			let ntetro = rotate();
			if( checkMove( 0, 0, ntetro) ) tetro = ntetro;
			break;
		case 49: // キーボードの1を押すとスタート
			start();
			break;
			case 50: // キーボードの2を押すとストップ
			stop();
			break;
	}
	
	drawAll();
}

//再開
function start() {
	clearTimeout(repeat);
	dropTetro();
}

//一時停止
function stop() {
	clearTimeout(repeat);
	let s="STOP";
	con.font = "40px 'MS ゴシック'";
	let w = con.measureText(s).width;
	let x = SCREEN_W/2 - w/2;
	let y = SCREEN_H/2 - 20;
	con.strokeText(s,x,y);
	con.fillStyle="black";
	con.fillText(s,x,y);
}

//右へ移動
function right() {
    if( checkMove(  1, 0 ) )tetro_x++;
    drawAll();
}

//回転
function rotate_1() {
    let ntetro = rotate();
    if( checkMove( 0, 0, ntetro) ) tetro = ntetro;
    drawAll();
}

//左へ移動
function left() {
    if( checkMove( -1, 0 ) )tetro_x--;
    drawAll();
}

//下へ移動
function down() {
	if( checkMove(  0, 1 ) )tetro_y++;
    drawAll();
}

</script>
</div>

</body>
</html>
javascript
スポンサーリンク
のんびりブログ

コメント

タイトルとURLをコピーしました