• TOP
  • NEWS
  • ABOUT
  • SERVICE
  • WORKS
  • PROJECT
  • BLOG
  • CONTACT
taziku
  • TOP
  • NEWS
  • ABOUT
  • SERVICE
  • WORKS
  • PROJECT
  • BLOG
  • CONTACT

「ぼうけんうさぎ」のシューティングゲームをChatGPTと創る

2023年3月29日
AI BLOG Creative Technology

Tazikuのイラストレーションプロジェクト「どうくつたんけん」のキャラクターの一人、「ぼうけんうさぎ」。このキャラクターを使って、今度はシューティングゲームを創ってみます。

ゴールは簡単なカジュアルゲームだけど、オリジナルのイラストと世界観をもった簡易ブラウザゲームを目指します。

ChatGPT4に与えた条件

「どうくつたんけん」という物語の中に出てくる、「ぼうけんうさぎ」のシューティングゲームを創りたいです。うさぎは人参を飛ばしてモンスターをやっつけていきます。
以下の前提条件を踏まえた上で、制作してください。

・HTML+JS+CSSで完結する
・極力シンプルなコード
・スコアを競うゲーム

初期のコード

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>どうくつたんけん - ぼうけんうさぎシューティングゲーム</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="game">
        <div id="player"></div>
    </div>
    <script src="script.js"></script>
</body>
</html>
body {
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: skyblue;
}

#game {
    position: relative;
    width: 800px;
    height: 600px;
    border: 2px solid black;
    overflow: hidden;
}

#player {
    position: absolute;
    width: 50px;
    height: 50px;
    background-image: url('usagi.png');
    background-size: cover;
    bottom: 10px;
    left: 375px;
}
.monster {
    position: absolute;
    width: 30px;
    height: 30px;
    background-image: url('monster.png');
    background-size: cover;
    top: 0;
}

.carrot {
    position: absolute;
    width: 10px;
    height: 20px;
    background-image: url('carrot.png');
    background-size: cover;
}
const game = document.getElementById("game");
const player = document.getElementById("player");
let score = 0;

document.addEventListener("keydown", (event) => {
    if (event.key === "ArrowLeft" && player.offsetLeft > 0) {
        player.style.left = player.offsetLeft - 10 + "px";
    } else if (event.key === "ArrowRight" && player.offsetLeft < game.clientWidth - player.clientWidth) {
        player.style.left = player.offsetLeft + 10 + "px";
    } else if (event.key === " ") {
        shoot();
    }
});

function shoot() {
    const carrot = document.createElement("div");
    carrot.className = "carrot";
    carrot.style.left = player.offsetLeft + player.clientWidth / 2 - 5 + "px";
    carrot.style.top = player.offsetTop - 20 + "px";
    game.appendChild(carrot);

    const shootInterval = setInterval(() => {
        carrot.style.top = carrot.offsetTop - 10 + "px";

        if (carrot.offsetTop < 0) {
            game.removeChild(carrot);
            clearInterval(shootInterval);
        }
    }, 100);
}

setInterval(() => {
    const monster = document.createElement("div");
    monster.className = "monster";
    monster.style.left = Math.random() * (game.clientWidth - 30) + "px";
    game.appendChild(monster);

    const monsterInterval = setInterval(() => {
        monster.style.top = monster.offsetTop + 10 + "px";

        if (monster.offsetTop > game.clientHeight) {
            game.removeChild(monster);
            clearInterval(monsterInterval);
        } else {
            const carrots = document.getElementsByClassName("carrot");
            for (let carrot of carrots) {
                const isColliding = carrot.offsetLeft < monster.offsetLeft + 30 &&
                    carrot.offsetLeft + 10 > monster.offsetLeft &&
                    carrot.offsetTop < monster.offsetTop + 30 &&
                    carrot.offsetTop + 20 > monster.offsetTop;

                if (isColliding) {
                    game.removeChild(monster);
                    game.removeChild(carrot);
                    clearInterval(monsterInterval);
                    score++;
                    console.log("スコア:", score);
                    break;
                }
            }
        }
    }, 100);
}, 2000);

取り急ぎノーチェックでも動作しました。ただプレイしていて色々修正したい点がでてきましたので、要望をまとめてChatGPTへ投げます。

・60秒の時間制限をつけて、制限時間を超えたらGAMEOVERと表示されスコアが出る
・Gameoverした時はゲームが止まるようにしたいです。またその時、再スタートのボタンを付けたい
・うさぎがモンスターに衝突するとゲームオーバーになるようにしたい
・残り時間はゲームオーバーした時に止めたい
・もう少しデザインを洗練させたい。 スコアや残り時間はプレイエリア内に入れ込みたい。

ChatGPTに修正依頼

修正されたjavascriptは以下

const game = document.getElementById("game");
let player = document.getElementById("player");
let score = 0;
let timeLeft = 60;
let timer;
let isGameOver = false;
const timeLimit = 60;

document.addEventListener("keydown", (event) => {
    if (event.key === "ArrowLeft" && player.offsetLeft > 0) {
        player.style.left = player.offsetLeft - 10 + "px";
    } else if (event.key === "ArrowRight" && player.offsetLeft < game.clientWidth - player.clientWidth) {
        player.style.left = player.offsetLeft + 10 + "px";
    } else if (event.key === " ") {
        shoot();
    }
});

function shoot() {
    const carrot = document.createElement("div");
    carrot.className = "carrot";
    carrot.style.left = player.offsetLeft + player.clientWidth / 2 - 5 + "px";
    carrot.style.top = player.offsetTop - 10 + "px"; // ここを修正
    game.appendChild(carrot);

    const carrotInterval = setInterval(() => {
        carrot.style.top = carrot.offsetTop - 10 + "px";

        if (carrot.offsetTop < 0) {
            game.removeChild(carrot);
            clearInterval(carrotInterval);
        }
    }, 100);
}

function isCollidingWithPlayer(monster, player) {
    return monster.offsetLeft < player.offsetLeft + player.clientWidth &&
        monster.offsetLeft + monster.clientWidth > player.offsetLeft &&
        monster.offsetTop < player.offsetTop + player.clientHeight &&
        monster.offsetTop + monster.clientHeight > player.offsetTop;
}

function gameOver() {
    isGameOver = true;
    game.innerHTML = "";

    const gameOverText = document.createElement("div");
    gameOverText.innerText = "GAME OVER\nスコア: " + score;
    gameOverText.style.position = "absolute";
    gameOverText.style.top = "50%";
    gameOverText.style.left = "50%";
    gameOverText.style.transform = "translate(-50%, -50%)";
    gameOverText.style.color = "red";
    gameOverText.style.fontSize = "24px";
    gameOverText.style.textAlign = "center";
    game.appendChild(gameOverText);

    const restartButton = document.createElement("button");
    restartButton.innerText = "再スタート";
    restartButton.style.position = "absolute";
    restartButton.style.top = "60%";
    restartButton.style.left = "50%";
    restartButton.style.transform = "translate(-50%, -50%)";
    restartButton.style.fontSize = "16px";
    restartButton.onclick = restartGame;
    game.appendChild(restartButton);
}

function restartGame() {
    isGameOver = false;
    timeLeft = timeLimit;
    score = 0;
    game.innerHTML = '<div id="player"></div><div class="score-timer-container"><div id="score">スコア: 0</div><div id="timer">残り時間: 60秒</div></div>';
    player = document.getElementById("player");
    player.style.left = "50%";
    player.style.transform = "translateX(-50%)";

    timer = setInterval(() => {
        timeLeft--;
        document.getElementById("timer").innerText = "残り時間: " + timeLeft + "秒";

        if (timeLeft <= 0) {
            clearInterval(timer);
            gameOver();
        }
    }, 1000);

    generateMonsters();
}

function generateMonsters() {
    setInterval(() => {
        if (isGameOver) return;

        const monster = document.createElement("div");
        monster.className = "monster";
        monster.style.left = Math.random() * (
        game.clientWidth - 30) + "px";
        game.appendChild(monster);

        const monsterInterval = setInterval(() => {
            monster.style.top = monster.offsetTop + 10 + "px";

            if (monster.offsetTop > game.clientHeight) {
                game.removeChild(monster);
                clearInterval(monsterInterval);
            } else {
                const carrots = document.getElementsByClassName("carrot");
                for (let carrot of carrots) {
                    const isColliding = carrot.offsetLeft < monster.offsetLeft + 30 &&
                        carrot.offsetLeft + 10 > monster.offsetLeft &&
                        carrot.offsetTop < monster.offsetTop + 30 &&
                        carrot.offsetTop + 20 > monster.offsetTop;

                    if (isColliding) {
                        game.removeChild(carrot);
                        game.removeChild(monster);
                        clearInterval(monsterInterval);
                        score++;
                        document.getElementById("score").innerText = "スコア: " + score;
                    }
                }

                if (!isGameOver && isCollidingWithPlayer(monster, player)) {
                    clearInterval(monsterInterval);
                    clearInterval(timer);
                    gameOver();
                }
            }
        }, 100);
    }, 2000);
}

generateMonsters();

JSはかなり壁打ちが必要でした。一発ではなかなか細部の修正はまだ難しいようです。ある程度挙動はそれらしくなったので、ここからはイラストレーターに依頼していきます。

イラストレーターにパーツデザインを依頼

うさぎの、人参、モンスター、プレイエリア背景を依頼、cssの画像の名前にリネームして作成しアップロードします。

それなりになりましたね!

最終成果物

どうくつたんけん – ぼうけんうさぎシューティングゲーム
https://taziku.co.jp/app/usagi_game_v1/

前回のブロック崩しよりは遥かに精度の高いものができました。AIに指示を与えるコツも分かってきました。

さらにこのゲームも、もう1段階ブラッシュアップしたいと思います。また改善したV2をお届けします!

※当サイトに掲載されている商標、一部画像、スクリ-ンショット、文章に置いては著作権侵害を目的に利用しておらず、第三十二条で定められる引用の範囲で使用しています。万が一問題があれば、お問い合わせからご連絡ください。即刻削除いたします。また、本ブログは業務の研究開発のためのものとなり、一部、弊社に関連性が無いものも掲載しております。

AIの最新情報を随時発信中

Xやnoteでは、AI・生成AI・LLMなどの最新情報や、ChatGPTやMidjourneyのプロンプトテクニックを連載中!フォローよろしくお願いします。

生成AI・AIの導入・研修・DXの支援はtazikuへ

生成AI・LLMなど、AIを活用したAIの導入・DXコンサルティング、AI領域の研修・講演などのご相談はお気軽にお問い合わせフォーム、もしくは生成AIソリューションAI CREATIVE BASEから、ご相談・お問い合せください。

PREV 今日の料理アプリ「DaD」のプログラムをChatGPT4と改善
NEXT AdobeのジェネレーティブAI「Adobe Firefly」を試す
Related Post
進化するMidjourney v7が描く次世代のAI画像生成
【随時更新】DALL-E3(ダリ スリー)関連記事まとめ
画像生成AIでホテルの部屋をコーディネートする
Midjourney v5.1の特性や新パラメータを検証
日本語に対応したBardにジェネレーティブAIについて色々質問してきた
Stable Diffusionのモデルデータの拡張子と種類についてのまとめ
Related Post
進化するMidjourney v7が描く次世代のAI画像生成
Claude 3.5の新機能 新モデル登場とPC操作機能
Claude 3 の連鎖プロンプト「プロンプトチェーン」を試す
Claude 3 で画像をピクセル化するプログラムを生成
Claude 3で登場人物の会話を生成する
Claude 3 でXMLタグを利用する

« PREV

Back to list

NEXT »

  • 投稿検索

  • ABOUT US?

    tazikuは東京・名古屋を拠点に活動するクリエイティブスタジオです。
    AI・生成AI・LLMとクリエイティブを掛け合わせ、新しいクリエイティブを提供します。
    Works
    Service
    Contact
  • AI CREATIVE BASE

    デザイン、ビジュアル、音声、空間演出。生成AIでクリエイティブワークフローに革新を与え、ビジネスの成果を最大化します。

    詳細を見る

  • MENU

    • BLOG
      • Think
      • Creative
      • Technology
        • AI
        • メタバース
    • Project
      • AIアニメプロジェクト
      • どうくつたんけん
  • NEW POST

    • 進化するMidjourney v7が描く次世代のAI画像生成
    • Claude 3.5の新機能 新モデル登場とPC操作機能
    • Claude 3 の連鎖プロンプト「プロンプトチェーン」を試す
    • Claude 3 で画像をピクセル化するプログラムを生成
    • Claude 3で登場人物の会話を生成する
© 2021 taziku / 株式会社タジク Based in Tokyo and Nagoya | プライバシーポリシー