このサイトはアフィリエイトリンクを含んでいます

改良版テトリス:新機能と操作性の向上

テトリスをJavascriptで作ってみたバージョンtetris_ver1.3 作ってみた!
テトリス

こんにちは、今回は以前ご紹介したテトリスの改良版についてお話しします。新しい機能や操作性の向上により、さらに楽しく遊べるようになりました。この記事では、改良点や新機能について詳しくご紹介します。

改良版テトリスをやってみて!

【注意】パソコン環境のみで正しく操作できます!
なお、Webページがスクロールしてしまうので、まずはマウスで黒画面を右クリック!

テトリス操作方法

以下は、テトリスゲームの基本的な操作方法です:

  • 左矢印キー: ブロックを左に移動します。
  • 右矢印キー: ブロックを右に移動します。
  • 下矢印キー: ブロックを素早く下に落とします(ハードドロップ)。
  • Qキー: ブロックを左に回転させます。
  • Wキー: ブロックを右に回転させます。

ゲーム中、ブロックを正確に操作してラインを消去し、得点を稼いでください。楽しんでプレイしてください!

tetris_ver1.3.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>テトリスゲーム</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333;
            color: #fff;
            font-family: Arial, sans-serif;
        }
        canvas {
            background-color: #000;
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="game" width="240" height="400"></canvas>
    <div id="score" style="position: absolute; top: 10px; left: 10px;">Score: 0</div>
    <script>
        const canvas = document.getElementById('game');
        const context = canvas.getContext('2d');
        const scale = 20;
        context.scale(scale, scale);

        const arena = createMatrix(12, 20);

        const player = {
            pos: {x: 0, y: 0},
            matrix: null,
            score: 0,
        };

        const colors = [
            null,
            '#FF0D72',
            '#0DC2FF',
            '#0DFF72',
            '#F538FF',
            '#FF8E0D',
            '#FFE138',
            '#3877FF',
        ];

        function createMatrix(w, h) {
            const matrix = [];
            while (h--) {
                matrix.push(new Array(w).fill(0));
            }
            return matrix;
        }

        function createPiece(type) {
            if (type === 'T') {
                return [
                    [0, 0, 0],
                    [1, 1, 1],
                    [0, 1, 0],
                ];
            } else if (type === 'O') {
                return [
                    [2, 2],
                    [2, 2],
                ];
            } else if (type === 'L') {
                return [
                    [0, 3, 0],
                    [0, 3, 0],
                    [0, 3, 3],
                ];
            } else if (type === 'J') {
                return [
                    [0, 4, 0],
                    [0, 4, 0],
                    [4, 4, 0],
                ];
            } else if (type === 'I') {
                return [
                    [0, 5, 0, 0],
                    [0, 5, 0, 0],
                    [0, 5, 0, 0],
                    [0, 5, 0, 0],
                ];
            } else if (type === 'S') {
                return [
                    [0, 6, 6],
                    [6, 6, 0],
                    [0, 0, 0],
                ];
            } else if (type === 'Z') {
                return [
                    [7, 7, 0],
                    [0, 7, 7],
                    [0, 0, 0],
                ];
            }
        }

        function drawMatrix(matrix, offset) {
            matrix.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        context.fillStyle = colors[value];
                        context.fillRect(x + offset.x,
                                         y + offset.y,
                                         1, 1);
                    }
                });
            });
        }

        function draw() {
            context.fillStyle = '#000';
            context.fillRect(0, 0, canvas.width / scale, canvas.height / scale);

            const xOffset = (canvas.width / scale - arena[0].length) / 2;
            drawMatrix(arena, {x: xOffset, y: 0});
            drawMatrix(player.matrix, {x: player.pos.x + xOffset, y: player.pos.y});
        }

        function merge(arena, player) {
            player.matrix.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        arena[y + player.pos.y][x + player.pos.x] = value;
                    }
                });
            });
        }

        function rotate(matrix, dir) {
            for (let y = 0; y < matrix.length; ++y) {
                for (let x = 0; x < y; ++x) {
                    [matrix[x][y], matrix[y][x]] = [matrix[y][x], matrix[x][y]];
                }
            }

            if (dir > 0) {
                matrix.forEach(row => row.reverse());
            } else {
                matrix.reverse();
            }
        }

        function playerDrop() {
            player.pos.y++;
            if (collide(arena, player)) {
                player.pos.y--;
                merge(arena, player);
                playerReset();
                arenaSweep();
                updateScore();
            }
            dropCounter = 0;
        }

        function playerMove(offset) {
            player.pos.x += offset;
            if (collide(arena, player)) {
                player.pos.x -= offset;
            }
        }

        function playerReset() {
            const pieces = 'TJLOSZI';
            player.matrix = createPiece(pieces[pieces.length * Math.random() | 0]);
            player.pos.y = 0;
            player.pos.x = (arena[0].length / 2 | 0) -
                           (player.matrix[0].length / 2 | 0);
            if (collide(arena, player)) {
                arena.forEach(row => row.fill(0));
                player.score = 0;
                updateScore();
            }
        }

        function playerRotate(dir) {
            const pos = player.pos.x;
            let offset = 1;
            rotate(player.matrix, dir);
            while (collide(arena, player)) {
                player.pos.x += offset;
                offset = -(offset + (offset > 0 ? 1 : -1));
                if (offset > player.matrix[0].length) {
                    rotate(player.matrix, -dir);
                    player.pos.x = pos;
                    return;
                }
            }
        }

        function collide(arena, player) {
            const [m, o] = [player.matrix, player.pos];
            for (let y = 0; y < m.length; ++y) {
                for (let x = 0; x < m[y].length; ++x) {
                    if (m[y][x] !== 0 &&
                        (arena[y + o.y] &&
                        arena[y + o.y][x + o.x]) !== 0) {
                        return true;
                    }
                }
            }
            return false;
        }

        function arenaSweep() {
            outer: for (let y = arena.length - 1; y > 0; --y) {
                for (let x = 0; x < arena[y].length; ++x) {
                    if (arena[y][x] === 0) {
                        continue outer;
                    }
                }

                const row = arena.splice(y, 1)[0].fill(0);
                arena.unshift(row);
                ++y;

                player.score += 10;
            }
        }

        let dropCounter = 0;
        let dropInterval = 1000;

        let lastTime = 0;
        function update(time = 0) {
            const deltaTime = time - lastTime;

            dropCounter += deltaTime;
            if (dropCounter > dropInterval) {
                playerDrop();
            }

            lastTime = time;

            draw();
            requestAnimationFrame(update);
        }

        function updateScore() {
            document.getElementById('score').innerText = `Score: ${player.score}`;
        }

        document.addEventListener('keydown', event => {
            if (event.keyCode === 37) {
                playerMove(-1);
            } else if (event.keyCode === 39) {
                playerMove(1);
            } else if (event.keyCode === 40) {
                event.preventDefault(); // ページのスクロールを防ぐ
                playerDrop();
            } else if (event.keyCode === 81) {
                playerRotate(-1);
            } else if (event.keyCode === 87) {
                playerRotate(1);
            }
        });

        playerReset();
        updateScore();
        update();
    </script>
</body>
</html>

テトリス改良版の概要

今回の改良版テトリスでは、ゲームの操作性、画面配置、バランス調整など、多くの点で改良が施されています。これにより、プレイヤーがよりスムーズにゲームを楽しむことができるようになりました。

操作性の向上

改良版では、操作性を向上させるためのいくつかの変更が行われました。

矢印キーによる操作の最適化

下矢印キーを押すとブロックが早く落ちますが、ページがスクロールしないように設定しました。これにより、ゲーム中に画面がずれる心配がなくなりました。具体的には、event.preventDefault()を使用してスクロールを防ぎました。

ブロックの回転と移動

QキーとWキーを使ってブロックを左回転、右回転させることができます。また、左矢印キーと右矢印キーでブロックを左右に移動させることができます。この操作性の改善により、プレイヤーは直感的にゲームを楽しむことができます。

スムーズな操作感

操作のレスポンスを改善し、ブロックの動きがスムーズになるように調整しました。これにより、プレイヤーがより自然な感覚でゲームをプレイできるようになりました。

画面の最適化

ゲーム画面も大幅に改良されました。これにより、視覚的な楽しさが増しました。

中央に配置されたゲーム画面

テトリスのゲーム画面が黒画面の中央に表示されるようになり、プレイしやすくなりました。これにより、ゲームの視認性が向上しました。具体的には、キャンバスのスケーリングと描画位置を調整しました。

黒画面の下端までブロックが落ちる

ブロックが黒画面の下端まで正常に落ちるように調整しました。これにより、ゲームのバランスが改善されました。プレイヤーがブロックを最後まで操作できるようになり、ゲームの戦略性が増しました。

視覚的な改善

色彩やブロックのデザインにも手を加え、見た目の美しさが向上しました。これにより、プレイヤーが長時間楽しめるようになりました。

ゲームバランスの調整

ゲームバランスも大幅に改善されました。これにより、プレイヤーがより公平に楽しめるようになりました。

スコアシステムの改善

スコアシステムも見直し、プレイヤーが達成感を感じやすくなりました。具体的には、ブロックが消えるたびに10点が加算されるシンプルなシステムに改良しました。これにより、ゲームのリプレイ価値が向上しました。

今後の改良点やアップデート予定

改良版テトリスにはまだまだ改善の余地があります。今後のアップデートでは、さらなる機能追加や調整を予定しています。

オンラインランキングの追加

自分のスコアを他のプレイヤーと競えるオンラインランキング機能を追加する予定です。これにより、競争心が刺激され、さらに楽しめるようになります。

ブロックデザインのカスタマイズ

ブロックの見た目をカスタマイズできる機能を追加する予定です。これにより、プレイヤーが自分好みのデザインでゲームを楽しむことができます。

さらに直感的な操作の調整

プレイヤーがよりスムーズにゲームを楽しめるよう、操作のレスポンスをさらに向上させる予定です。これにより、直感的な操作感が一層高まります。

まとめ

改良版テトリスは、操作性、視覚的な改善、ゲームバランスの調整など、多くの点で改良が加えられました。これにより、プレイヤーがより楽しく、長く遊べるようになりました。今後もさらなるアップデートを予定しており、皆様からのフィードバックをお待ちしています。ぜひお楽しみください!

あんちゃん
あんちゃん

テトリス制作の各リンクはこちらだよ!

コメント

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