ChatGPTを使って簡単なゲームを作る④: ChatGPTに「ちーかわ」ゲームを作ってもらう編

# ChatGPTで簡単な迷路ゲームを作ろう！


こんにちは、みなさん！今日はChatGPTを使って簡単な迷路ゲームを作成する方法を紹介します。このガイドでは、ChatGPTとCodePenを使用して、楽しく学びながらゲームを作成できるようにサポートします。




# 準備するもの

- ChatGPT: ゲームのコード生成に使用します。、ぉお0ぽ0000ー
- CodePen: コードを貼り付けて、ゲームを実行するためのオンラインエディタです。


ステップ 1: ゲームのアイデアをChatGPTに入力する

まずは、ChatGPTにゲームのアイデアを入力します。今回作るのは簡単な迷路ゲームです。


例: ChatGPTへのプロンプト

```PROMPT: プロンプト例

「簡単な迷路ゲームをJavaScriptで作成してください。」
```

これで以下のコードを得ることができますが・・・？？

````HTML:sample
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Maze Game</title>
    <style>
        body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f0f0f0; }
        canvas { background: white; border: 1px solid black; }
    </style>
</head>
<body>
    <canvas id="maze" width="400" height="400"></canvas>
    <script>
        const canvas = document.getElementById('maze');
        const ctx = canvas.getContext('2d');
        const cellSize = 40;
        const cols = canvas.width / cellSize;
        const rows = canvas.height / cellSize;

        let grid = [];
        let stack = [];

        class Cell {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.walls = [true, true, true, true];
                this.visited = false;
            }

            draw() {
                const x = this.x * cellSize;
                const y = this.y * cellSize;

                ctx.strokeStyle = 'black';
                ctx.lineWidth = 2;

                if (this.walls[0]) ctx.strokeRect(x, y, cellSize, 0); // Top
                if (this.walls[1]) ctx.strokeRect(x + cellSize, y, 0, cellSize); // Right
                if (this.walls[2]) ctx.strokeRect(x, y + cellSize, cellSize, 0); // Bottom
                if (this.walls[3]) ctx.strokeRect(x, y, 0, cellSize); // Left

                if (this.visited) {
                    ctx.fillStyle = 'lightblue';
                    ctx.fillRect(x, y, cellSize, cellSize);
                }
            }

            checkNeighbors() {
                const neighbors = [];
                const top = grid[index(this.x, this.y - 1)];
                const right = grid[index(this.x + 1, this.y)];
                const bottom = grid[index(this.x, this.y + 1)];
                const left = grid[index(this.x - 1, this.y)];

                if (top && !top.visited) neighbors.push(top);
                if (right && !right.visited) neighbors.push(right);
                if (bottom && !bottom.visited) neighbors.push(bottom);
                if (left && !left.visited) neighbors.push(left);

                if (neighbors.length > 0) {
                    const r = Math.floor(Math.random() * neighbors.length);
                    return neighbors[r];
                } else {
                    return undefined;
                }
            }
        }

        function index(x, y) {
            if (x < 0 || y < 0 || x >= cols || y >= rows) return -1;
            return x + y * cols;
        }

        function setup() {
            for (let y = 0; y < rows; y++) {
                for (let x = 0; x < cols; x++) {
                    const cell = new Cell(x, y);
                    grid.push(cell);
                }
            }

            const start = grid[0];
            start.visited = true;
            stack.push(start);

            draw();
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            grid.forEach(cell => cell.draw());

            const current = stack[stack.length - 1];
            const next = current.checkNeighbors();

            if (next) {
                next.visited = true;
                stack.push(next);

                // Remove walls
                const x = current.x - next.x;
                const y = current.y - next.y;

                if (x === 1) {
                    current.walls[3] = false;
                    next.walls[1] = false;
                } else if (x === -1) {
                    current.walls[1] = false;
                    next.walls[3] = false;
                }

                if (y === 1) {
                    current.walls[0] = false;
                    next.walls[2] = false;
                } else if (y === -1) {
                    current.walls[2] = false;
                    next.walls[0] = false;
                }
            } else if (stack.length > 0) {
                stack.pop();
            }

            if (stack.length > 0) {
                requestAnimationFrame(draw);
            }
        }

        setup();
    </script>
</body>
</html>

````


これだと、まあ動かなくはないのですが、モバイルではちょっと物足りないです。
ということで、汎用的に使っているプロンプトで、コードを再作成してみます。

```PROMPT: プロンプト例

あなたは、ゲームプログラマーとして振る舞ってください。
これからHTMLゲームを作成します。HTMLファイル内部にCSS、Javascript全て書いてください。ゲームの仕様はこちらからインプットするのでその情報に基づいて作成してください。簡単・簡潔なコードを作成してください。仕様は以下の通りです。

ゲームタイトル：　ちーかわ
ゲーム概要：　ちーかわが迷路を脱出する迷路ゲームです。迷路は多少ランダムに変わりますが小学生でもできるくらい簡単です。ゴールに辿り着くと、ゲームが終わります。ユーザーは移動方向を入力することで、主人公の「ちーかわ」を動かすことができます。ちーかわは、アイコンの画像があります。正方形の画像です。画像のリンクは、外部の画像URLを埋め込んでください
プラットフォーム：　HTML、スマートフォン
モバイルでの操作方法：ボタンを配置。タップすると操作できるコントローラーのボタンを、ファミコンみたいな形で、配置。それを、タップする。
停止（ゲームを停止）と開始（初期化して初めからやり直し）のボタンを画面の下部につける

```


# おまけ：プロンプトを考察して、簡単なものと詳しいものを比較してみる。2個目のプロンプトの特徴や利点の説明

1. 役割がはっきりしている:
    - 具体的なプロンプト: 「ゲームプログラマーとして振る舞ってください」と指定しているので、ChatGPTが何をすればいいかすぐにわかります。
    - 簡単なプロンプト: 何をすべきかがあまり明確ではありません。
1. 詳しい指示がある:
    - 具体的なプロンプト: ゲームのタイトル、内容、キャラクター、操作方法などが詳しく書かれているので、ChatGPTが具体的なコードを作りやすいです。
    - 簡単なプロンプト: 詳しい情報がないので、曖昧な結果になるかもしれません。
1. ユーザーインターフェースの指示がある:
    - 具体的なプロンプト: モバイルでの操作方法やボタン配置などが具体的に書かれているので、使いやすいゲームが作れます。
    - 簡単なプロンプト: どう操作するのかが書かれていないので、使いにくいかもしれません。
1. 目的が明確:
    - 具体的なプロンプト: 迷路を脱出するというはっきりした目的があるので、何をすればいいかがわかりやすいです。
    - 簡単なプロンプト: 目的が曖昧で、どんなゲームになるか不明確です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60530/901083e0-10f3-9c18-2253-6c6ee90172a3.png)



### 結果のゲームと、改善したコードはこちら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60530/9cfed257-5e82-b4f8-3ea4-a3360f1c7332.png)

![uploading...0]()


```HTML: 改善したHTML
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ちーかわ迷路ゲーム</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            margin: 0;
            height: 100vh;
            background-color: #f0f0f0;
        }
        canvas {
            background-color: #fff;
            border: 1px solid #000;
        }
        #controls {
            display: flex;
            justify-content: center;
            margin-top: 10px;
        }
        .controller {
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .controller button {
            padding: 20px;
            margin: 5px;
            font-size: 16px;
        }
        .controller .horizontal {
            display: flex;
            justify-content: center;
        }
        #startPauseButtons {
            margin-top: 10px;
        }
        button {
            padding: 10px 20px;
            margin: 5px;
            font-size: 16px;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <div id="controls">
        <div class="controller">
            <button onclick="move('up')">↑</button>
            <div class="horizontal">
                <button onclick="move('left')">←</button>
                <button onclick="move('right')">→</button>
            </div>
            <button onclick="move('down')">↓</button>
        </div>
    </div>
    <div id="startPauseButtons">
        <button onclick="startGame()">開始</button>
        <button onclick="pauseGame()">停止</button>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const chiikawaImgUrl = 'https://stat.ameba.jp/user_images/20231222/08/kobato00/f6/4d/j/o0580058015379909166.jpg';
        const chiikawaImg = new Image();
        chiikawaImg.src = chiikawaImgUrl;

        let maze = [];
        let mazeSize = 10;
        let cellSize = canvas.width / mazeSize;
        let chiikawa = { x: 0, y: 0 };
        let goal = { x: mazeSize - 1, y: mazeSize - 1 };
        let paused = true;

        function generateMaze() {
            maze = Array.from({ length: mazeSize }, () => Array(mazeSize).fill(0));
            for (let i = 0; i < mazeSize; i++) {
                for (let j = 0; j < mazeSize; j++) {
                    maze[i][j] = Math.random() > 0.2 ? 0 : 1;
                }
            }
            maze[0][0] = 0;
            maze[mazeSize - 1][mazeSize - 1] = 0;
        }

        function drawMaze() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for (let i = 0; i < mazeSize; i++) {
                for (let j = 0; j < mazeSize; j++) {
                    if (maze[i][j] === 1) {
                        ctx.fillStyle = '#000';
                        ctx.fillRect(j * cellSize, i * cellSize, cellSize, cellSize);
                    }
                }
            }
            ctx.drawImage(chiikawaImg, chiikawa.x * cellSize, chiikawa.y * cellSize, cellSize, cellSize);
            ctx.fillStyle = 'red';
            ctx.fillRect(goal.x * cellSize, goal.y * cellSize, cellSize, cellSize);
        }

        function move(direction) {
            if (paused) return;
            let newX = chiikawa.x;
            let newY = chiikawa.y;
            switch (direction) {
                case 'up':
                    newY = Math.max(0, chiikawa.y - 1);
                    break;
                case 'down':
                    newY = Math.min(mazeSize - 1, chiikawa.y + 1);
                    break;
                case 'left':
                    newX = Math.max(0, chiikawa.x - 1);
                    break;
                case 'right':
                    newX = Math.min(mazeSize - 1, chiikawa.x + 1);
                    break;
            }
            if (maze[newY][newX] === 0) {
                chiikawa.x = newX;
                chiikawa.y = newY;
                if (chiikawa.x === goal.x && chiikawa.y === goal.y) {
                    alert('ゴールしました！');
                    paused = true;
                }
                drawMaze();
            }
        }

        function startGame() {
            generateMaze();
            chiikawa = { x: 0, y: 0 };
            paused = false;
            drawMaze();
        }

        function pauseGame() {
            paused = true;
        }

        chiikawaImg.onload = drawMaze;
    </script>
</body>
</html>

```





## リンク
今日の、箸休めコンテンツ：ゲーム制作をChatGPTでやってみるシリーズです。
 

### ChatGPTを使って簡単なゲームを作る①: ゲーム作成・全体概要
https://qiita.com/dms-matthew/items/ecd447bf7ae10468f41e


###  ChatGPTを使って簡単なゲームを作る②: CodePenの利用開始
https://qiita.com/dms-matthew/items/e97eb3d9ffe9d36a765a



###  ChatGPTを使って簡単なゲームを作る③: ChatGPTにブロック崩しゲームを作ってもらう編
https://qiita.com/dms-matthew/items/ac8f2b5086f710d20b98


###  ChatGPTを使って簡単なゲームを作る④: ChatGPTに「ちーかわ」ゲームを作ってもらう編
https://qiita.com/dms-matthew/items/e635d57597ddd87a9b5b　


###  ChatGPTを使って簡単なゲームを作る⑤: ChatGPTに「ベンゼン環・神経衰弱」ゲームを作ってもらう編
https://qiita.com/dms-matthew/items/631111698f7d322194da