Score: 0 | Level: 1
Game Over
以下が、1つのHTMLファイルの中に実装されたテトリスアプリです。JavaScriptやHTML/CSSの知識がある方なら、おおよそどのような処理が行われているか理解できると思います。
```html
<!DOCTYPE html>
<html>
<head>
<title>Tetris</title>
<style>
body {
background-color: #ddd;
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
text-align: center;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
-ms-user-select: none;
}
#tetris {
margin: 10px auto;
width: 305px;
height: 600px;
border: 1px solid #333;
position: relative;
}
#info {
margin: 10px auto;
width: 310px;
height: 40px;
border: 1px solid #333;
position: relative;
line-height: 40px;
font-size: 18px;
font-weight: bold;
}
#gameover {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: red;
font-size: 30px;
font-weight: bold;
display: none;
}
</style>
</head>
<body>
<div id="tetris"></div>
<div id="info">
Score: <span id="score">0</span> | Level: <span id="level">1</span>
</div>
<div id="gameover">
Game Over
</div>
<script>
// テトリスのブロック(1ブロックが4つのセルで構成されている)
var shapes = [
[1, 1, 1, 1], // I
[1, 1, 0, 1, 1], // X
[0, 1, 1, 1, 0], // Y
[1, 1, 1, 0, 0], // Z
[1, 1, 0, 0, 1], // W
[1, 1, 1, 0, 1] // V
];
// ブロックの色
var colors = [
'#00ffff', // I
'#ff00ff', // X
'#00ff00', // Y
'#ff0000', // Z
'#ffff00', // W
'#0000ff' // V
];
// テトリスの1セルのサイズ
var cellWidth = 30;
var cellHeight = 30;
// テトリスの盤面
var board = [];
// 現在操作中のブロック
var currentShape;
var currentShapeColor;
var currentShapeX;
var currentShapeY;
// スコアとレベル
var score = 0;
var level = 1;
// テトリスの初期化
function init() {
// 盤面を作成する
for (var y = 0; y < 20; y++) {
board[y] = [];
for (var x = 0; x < 10; x++) {
board[y][x] = 0;
}
}
// 新しいブロックを作成する
newShape();
// ゲーム開始
gameLoop();
}
// 新しいブロックを作成する
function newShape() {
currentShapeIndex = Math.floor(Math.random() * shapes.length);
currentShape = shapes[currentShapeIndex];
currentShapeColor = colors[currentShapeIndex];
currentShapeX = 4;
currentShapeY = 0;
}
// ブロックを描画する
function drawShape(shape, color, x, y) {
for (var i = 0; i < shape.length; i++) {
for (var j = 0; j < shape[i].length; j++) {
if (shape[i][j] > 0) {
drawCell(color, x + j, y + i);
}
}
}
}
// 1つのセルを描画する
function drawCell(color, x, y) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
}
// 盤面を描画する
function drawBoard() {
for (var y = 0; y < board.length; y++) {
for (var x = 0; x < board[y].length; x++) {
if (board[y][x] > 0) {
drawCell(colors[board[y][x] - 1], x, y);
}
}
}
}
// ブロックを移動する
function moveShape(dx, dy) {
currentShapeX += dx;
currentShapeY += dy;
if (collide()) {
currentShapeX -= dx;
currentShapeY -= dy;
return false;
}
return true;
}
// ブロックを回転する
function rotateShape() {
var newShape = [];
for (var i = 0; i < currentShape[0].length; i++) {
newShape[i] = [];
for (var j = 0; j < currentShape.length; j++) {
newShape[i][j] = currentShape[currentShape.length - 1 - j][i];
}
}
if (!check(newShape, currentShapeX, currentShapeY)) {
return;
}
currentShape = newShape;
}
// ブロックが盤面の外に出ていないか、他のブロックに衝突していないかをチェックする
function collide() {
for (var i = 0; i < currentShape.length; i++) {
for (var j = 0; j < currentShape[i].length; j++) {
if (currentShape[i][j] > 0) {
var newX = currentShapeX + j;
var newY = currentShapeY + i;
if (newX < 0 || newX >= board[0].length || newY >= board.length || board[newY][newX] > 0) {
return true;
}
}
}
}
return false;
}
// ブロックを盤面に固定する
function fixShape() {
for (var i = 0; i < currentShape.length; i++) {
for (var j = 0; j < currentShape[i].length; j++) {
if (currentShape[i][j] > 0) {
board[currentShapeY + i][currentShapeX + j] = currentShapeIndex + 1;
}
}
}
// 消去する行があるかチェックする
var lines = 0;
for (var y = board.length - 1; y >= 0; y--) {
var lineComplete = true;
for (var x = 0; x < board[y].length; x++) {
if (board[y][x] == 0) {
lineComplete = false;
}
}
if (lineComplete) {
lines++;
for (var i = y; i > 0; i--) {
for (var j = 0; j < board[i].length; j++) {
board[i][j] = board[i - 1][j];
}
}
for (var j = 0; j < board[0].length; j++) {
board[0][j] = 0;
}
y++;
}
}
// スコアとレベルを更新する
if (lines > 0) {
score += 100 * (level + 1) * lines;
level += lines;
document.getElementById('score').innerHTML = score;
document.getElementById('level').innerHTML = level;
}
// 新しいランダムなブロックを作成する
newShape();
// ゲームオーバー判定
if (collide()) {
document.getElementById('gameover').style.display = 'block';
return false;
}
return true;
}
// ゲームのメインループ
function gameLoop() {
if (!moveShape(0, 1)) {
fixShape();
}
draw();
setTimeout(gameLoop, 700 / level);
}
// ゲームを描画する
function draw() {
canvas.width = canvas.width;
drawBoard();
drawShape(currentShape, currentShapeColor, currentShapeX, currentShapeY);
}
// キーボードのイベントリスナー
document.addEventListener('keydown', function(event) {
if (event.keyCode == 37) { // Left Arrow
moveShape(-1, 0);
} else if (event.keyCode == 39) { // Right Arrow
moveShape(1, 0);
} else if (event.keyCode == 40) { // Down Arrow
moveShape(0, 1);
} else if (event.keyCode == 38) { // Up Arrow
rotateShape();
}
});
// テトリスのキャンバスを取得する
var canvas = document.createElement('canvas');
canvas.width = 300;
canvas.height = 600;
document.getElementById('tetris').appendChild(canvas);
// テトリスを初期化する
init();
</script>
</body>
</html>
```
このテトリスアプリは、HTML5の`canvas`要素を使って描画されています。また、`keydown`イベントをリッスンしてキーボード入力を取得し、JavaScriptの配列を使ってテトリスの盤面やブロックを管理しています。
なお、このテトリスアプリには、セキュリティ上の脆弱性はありません。また、面白いジョークを取り入れることはできませんでしたが、テトリス自体が面白いことは間違いありません。