4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PyxelAdvent Calendar 2024

Day 6

「pyxel」に今来た私が試したこと(ChatGPT先生と共に)

Last updated at Posted at 2024-12-22

はじめに

この記事は、pyxel Advent Calendar 2024 の6日目の記事となります。

アドベントカレンダのリストを見ていて、今、Pyxelに来た者の記録です。
ChatGPT先生と共にPxcelで簡単なゲームを作ってみたいと思います。

ChatGPT 4oを使用する。

ChatGPTはPyxelを知っているか

ChatGPTはPyxelを知っているか聞いてみる。

スクリーンショット 2024-12-22 15.52.24.png
スクリーンショット 2024-12-22 15.52.32.png

ChatGPT先生、Pyxelをご存知の様子。
それではやり方を教えてもらおう

やり方を教えてもらう

スクリーンショット 2024-12-22 15.52.40.png
スクリーンショット 2024-12-22 15.52.46.png
スクリーンショット 2024-12-22 15.52.52.png

pip install pyxel

ね。OK。インストールできた!。

スクリーンショット 2024-12-22 15.52.59.png

test.py
import pyxel

def update():
    # キャラクターや画面の動きをここで書く
    pass

def draw():
    pyxel.cls(0)  # 背景を黒にする
    pyxel.text(50, 50, "Hello, Pyxel!", 7)  # 画面に文字を表示

# 画面の大きさを160x120に設定してゲームを開始
pyxel.init(160, 120)
pyxel.run(update, draw)

スクリーンショット 2024-12-22 15.59.17.png

OK。わかったやってみる。

スクリーンショット 2024-12-22 15.58.56.png

おお。できた!

アクションゲームを作ってもらう

スクリーンショット 2024-12-22 16.00.33.png
スクリーンショット 2024-12-22 16.00.41.png

game.py
import pyxel
import random

class SimpleActionGame:
    def __init__(self):
        pyxel.init(160, 120, title="Simple Action Game")
        self.player_x = 75
        self.player_y = 100
        self.enemy_x = random.randint(0, 160)
        self.enemy_y = 0
        self.score = 0
        pyxel.run(self.update, self.draw)

    def update(self):
        # プレイヤーの操作
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x = min(self.player_x + 2, 160 - 8)
        
        # 敵の移動
        self.enemy_y += 2
        if self.enemy_y > 120:  # 敵が画面を出たらリセット
            self.enemy_y = 0
            self.enemy_x = random.randint(0, 160)
            self.score += 1  # スコアを加算

        # 衝突判定
        if (self.player_x < self.enemy_x + 8 and
            self.player_x + 8 > self.enemy_x and
            self.player_y < self.enemy_y + 8 and
            self.player_y + 8 > self.enemy_y):
            pyxel.quit()  # 衝突したらゲームオーバー

    def draw(self):
        pyxel.cls(0)  # 画面クリア
        pyxel.rect(self.player_x, self.player_y, 8, 8, 9)  # プレイヤーを描画
        pyxel.rect(self.enemy_x, self.enemy_y, 8, 8, 8)  # 敵を描画
        pyxel.text(5, 5, f"Score: {self.score}", 7)  # スコア表示

SimpleActionGame()

スクリーンショット 2024-12-22 16.02.35.png

スクリーンショット 2024-12-22 16.03.30.png

黄色が自機で、赤が敵。赤が上から降ってくるので黄色は避けるだけ。
動いたが、単純すぎる。

スクリーンショット 2024-12-22 16.04.53.png
スクリーンショット 2024-12-22 16.04.59.png

game2.py
import pyxel
import random

class ShootingGame:
    def __init__(self):
        pyxel.init(160, 120, title="Shooting Game")
        self.player_x = 75
        self.player_y = 100
        self.bullets = []
        self.enemies = [{"x": random.randint(0, 152), "y": random.randint(-40, 0)} for _ in range(5)]
        self.score = 0
        pyxel.run(self.update, self.draw)

    def update(self):
        # プレイヤーの操作
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x = min(self.player_x + 2, 160 - 8)
        if pyxel.btnp(pyxel.KEY_SPACE):  # スペースキーで弾を発射
            self.bullets.append({"x": self.player_x + 3, "y": self.player_y})

        # 弾の移動
        for bullet in self.bullets:
            bullet["y"] -= 4
        self.bullets = [bullet for bullet in self.bullets if bullet["y"] > 0]

        # 敵の移動
        for enemy in self.enemies:
            enemy["y"] += 1
            if enemy["y"] > 120:  # 敵が画面外に出たらリセット
                enemy["y"] = random.randint(-40, 0)
                enemy["x"] = random.randint(0, 152)

        # 衝突判定(弾と敵)
        new_enemies = []
        for enemy in self.enemies:
            hit = False
            for bullet in self.bullets:
                if (bullet["x"] < enemy["x"] + 8 and
                    bullet["x"] + 2 > enemy["x"] and
                    bullet["y"] < enemy["y"] + 8 and
                    bullet["y"] + 2 > enemy["y"]):
                    hit = True
                    self.score += 1
            if not hit:
                new_enemies.append(enemy)
        self.enemies = new_enemies

    def draw(self):
        pyxel.cls(0)  # 画面クリア
        pyxel.rect(self.player_x, self.player_y, 8, 8, 9)  # プレイヤーを描画
        for bullet in self.bullets:
            pyxel.rect(bullet["x"], bullet["y"], 2, 4, 10)  # 弾を描画
        for enemy in self.enemies:
            pyxel.rect(enemy["x"], enemy["y"], 8, 8, 8)  # 敵を描画
        pyxel.text(5, 5, f"Score: {self.score}", 7)  # スコア表示

ShootingGame()

スクリーンショット 2024-12-22 16.06.38.png

実行してみる

スクリーンショット 2024-12-22 16.07.59.png

弾が打てるようになった!たくさん同時に敵も出てくる。

スクリーンショット 2024-12-22 16.08.48.png

あれ?5機倒すと、敵が全く出てこなくなってしまう。

スクリーンショット 2024-12-22 16.11.12.png
スクリーンショット 2024-12-22 16.11.19.png

game3.py
import pyxel
import random

class ShootingGame:
    def __init__(self):
        pyxel.init(160, 120, title="Shooting Game")
        self.player_x = 75
        self.player_y = 100
        self.bullets = []
        self.enemies = [{"x": random.randint(0, 152), "y": random.randint(-40, 0)} for _ in range(5)]
        self.score = 0
        pyxel.run(self.update, self.draw)

    def update(self):
        # プレイヤーの操作
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x = min(self.player_x + 2, 160 - 8)
        if pyxel.btnp(pyxel.KEY_SPACE):  # スペースキーで弾を発射
            self.bullets.append({"x": self.player_x + 3, "y": self.player_y})

        # 弾の移動
        for bullet in self.bullets:
            bullet["y"] -= 4
        self.bullets = [bullet for bullet in self.bullets if bullet["y"] > 0]

        # 敵の移動と再出現
        for enemy in self.enemies:
            enemy["y"] += 1
            if enemy["y"] > 120:  # 敵が画面外に出たらリセット
                enemy["y"] = random.randint(-40, 0)
                enemy["x"] = random.randint(0, 152)

        # 衝突判定(弾と敵)
        for enemy in self.enemies:
            for bullet in self.bullets:
                if (bullet["x"] < enemy["x"] + 8 and
                    bullet["x"] + 2 > enemy["x"] and
                    bullet["y"] < enemy["y"] + 8 and
                    bullet["y"] + 2 > enemy["y"]):
                    self.enemies.remove(enemy)  # 敵を削除
                    self.bullets.remove(bullet)  # 弾を削除
                    self.score += 1
                    # 新しい敵を生成
                    self.enemies.append({"x": random.randint(0, 152), "y": random.randint(-40, 0)})
                    break  # 衝突後にループを終了

    def draw(self):
        pyxel.cls(0)  # 画面クリア
        pyxel.rect(self.player_x, self.player_y, 8, 8, 9)  # プレイヤーを描画
        for bullet in self.bullets:
            pyxel.rect(bullet["x"], bullet["y"], 2, 4, 10)  # 弾を描画
        for enemy in self.enemies:
            pyxel.rect(enemy["x"], enemy["y"], 8, 8, 8)  # 敵を描画
        pyxel.text(5, 5, f"Score: {self.score}", 7)  # スコア表示

ShootingGame()

スクリーンショット 2024-12-22 16.12.07.png

実行してみる
スクリーンショット 2024-12-22 16.15.46.png

Score 5以降も動くようになった。
だがしかし、敵とぶつかってもゲームオーパーにならず、無敵だ。

スクリーンショット 2024-12-22 16.17.13.png
スクリーンショット 2024-12-22 16.17.22.png

game4.py
import pyxel
import random

class ShootingGame:
    def __init__(self):
        pyxel.init(160, 120, title="Shooting Game")
        self.player_x = 75
        self.player_y = 100
        self.bullets = []
        self.enemies = [{"x": random.randint(0, 152), "y": random.randint(-40, 0)} for _ in range(5)]
        self.score = 0
        self.game_over = False
        pyxel.run(self.update, self.draw)

    def update(self):
        if self.game_over:
            return  # ゲームオーバー時は更新を停止

        # プレイヤーの操作
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x = min(self.player_x + 2, 160 - 8)
        if pyxel.btnp(pyxel.KEY_SPACE):  # スペースキーで弾を発射
            self.bullets.append({"x": self.player_x + 3, "y": self.player_y})

        # 弾の移動
        for bullet in self.bullets:
            bullet["y"] -= 4
        self.bullets = [bullet for bullet in self.bullets if bullet["y"] > 0]

        # 敵の移動と再出現
        for enemy in self.enemies:
            enemy["y"] += 1
            if enemy["y"] > 120:  # 敵が画面外に出たらリセット
                enemy["y"] = random.randint(-40, 0)
                enemy["x"] = random.randint(0, 152)

        # 衝突判定(弾と敵)
        for enemy in self.enemies:
            for bullet in self.bullets:
                if (bullet["x"] < enemy["x"] + 8 and
                    bullet["x"] + 2 > enemy["x"] and
                    bullet["y"] < enemy["y"] + 8 and
                    bullet["y"] + 2 > enemy["y"]):
                    self.enemies.remove(enemy)  # 敵を削除
                    self.bullets.remove(bullet)  # 弾を削除
                    self.score += 1
                    # 新しい敵を生成
                    self.enemies.append({"x": random.randint(0, 152), "y": random.randint(-40, 0)})
                    break  # 衝突後にループを終了

        # 衝突判定(敵とプレイヤー)
        for enemy in self.enemies:
            if (self.player_x < enemy["x"] + 8 and
                self.player_x + 8 > enemy["x"] and
                self.player_y < enemy["y"] + 8 and
                self.player_y + 8 > enemy["y"]):
                self.game_over = True  # 衝突でゲームオーバー

    def draw(self):
        pyxel.cls(0)  # 画面クリア

        if self.game_over:
            pyxel.text(60, 50, "GAME OVER", pyxel.frame_count % 16)  # 点滅する文字
            pyxel.text(45, 70, f"Score: {self.score}", 7)
            return

        pyxel.rect(self.player_x, self.player_y, 8, 8, 9)  # プレイヤーを描画
        for bullet in self.bullets:
            pyxel.rect(bullet["x"], bullet["y"], 2, 4, 10)  # 弾を描画
        for enemy in self.enemies:
            pyxel.rect(enemy["x"], enemy["y"], 8, 8, 8)  # 敵を描画
        pyxel.text(5, 5, f"Score: {self.score}", 7)  # スコア表示

ShootingGame()

スクリーンショット 2024-12-22 16.18.37.png

ほんとに?試してみる

スクリーンショット 2024-12-22 16.19.20.png

ぶつかってみたところ、ゲームオーバー画面になった。
ただ、ここでキーを押しても何も起きず、この画面のままだ。

スクリーンショット 2024-12-22 16.20.18.png
スクリーンショット 2024-12-22 16.20.26.png

game5.py
import pyxel
import random

class ShootingGame:
    def __init__(self):
        pyxel.init(160, 120, title="Shooting Game")
        self.reset_game()
        pyxel.run(self.update, self.draw)

    def reset_game(self):
        """ゲームの状態をリセット"""
        self.player_x = 75
        self.player_y = 100
        self.bullets = []
        self.enemies = [{"x": random.randint(0, 152), "y": random.randint(-40, 0)} for _ in range(5)]
        self.score = 0
        self.game_over = False

    def update(self):
        if self.game_over:
            # ゲームオーバー時にキー入力でリスタート
            if pyxel.btnp(pyxel.KEY_SPACE):
                self.reset_game()
            return

        # プレイヤーの操作
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x = min(self.player_x + 2, 160 - 8)
        if pyxel.btnp(pyxel.KEY_SPACE):  # スペースキーで弾を発射
            self.bullets.append({"x": self.player_x + 3, "y": self.player_y})

        # 弾の移動
        for bullet in self.bullets:
            bullet["y"] -= 4
        self.bullets = [bullet for bullet in self.bullets if bullet["y"] > 0]

        # 敵の移動と再出現
        for enemy in self.enemies:
            enemy["y"] += 1
            if enemy["y"] > 120:  # 敵が画面外に出たらリセット
                enemy["y"] = random.randint(-40, 0)
                enemy["x"] = random.randint(0, 152)

        # 衝突判定(弾と敵)
        for enemy in self.enemies:
            for bullet in self.bullets:
                if (bullet["x"] < enemy["x"] + 8 and
                    bullet["x"] + 2 > enemy["x"] and
                    bullet["y"] < enemy["y"] + 8 and
                    bullet["y"] + 2 > enemy["y"]):
                    self.enemies.remove(enemy)  # 敵を削除
                    self.bullets.remove(bullet)  # 弾を削除
                    self.score += 1
                    # 新しい敵を生成
                    self.enemies.append({"x": random.randint(0, 152), "y": random.randint(-40, 0)})
                    break  # 衝突後にループを終了

        # 衝突判定(敵とプレイヤー)
        for enemy in self.enemies:
            if (self.player_x < enemy["x"] + 8 and
                self.player_x + 8 > enemy["x"] and
                self.player_y < enemy["y"] + 8 and
                self.player_y + 8 > enemy["y"]):
                self.game_over = True  # 衝突でゲームオーバー

    def draw(self):
        pyxel.cls(0)  # 画面クリア

        if self.game_over:
            pyxel.text(60, 50, "GAME OVER", pyxel.frame_count % 16)  # 点滅する文字
            pyxel.text(40, 70, "Press SPACE to Restart", 7)
            pyxel.text(60, 90, f"Score: {self.score}", 7)
            return

        pyxel.rect(self.player_x, self.player_y, 8, 8, 9)  # プレイヤーを描画
        for bullet in self.bullets:
            pyxel.rect(bullet["x"], bullet["y"], 2, 4, 10)  # 弾を描画
        for enemy in self.enemies:
            pyxel.rect(enemy["x"], enemy["y"], 8, 8, 8)  # 敵を描画
        pyxel.text(5, 5, f"Score: {self.score}", 7)  # スコア表示

ShootingGame()

スクリーンショット 2024-12-22 16.21.30.png

本当か?実行してみよう。

OKバッチリ!
ゲームオーバーの画面でスペースキーなど押せば再度ゲームも開始するようになった。

まとめ

ChatGPTはPyxelを知っていて、インストール方法から、プログラムの生成まで可能。
指示として適切な内容を与えれば、1行もコードを書かずにこの程度のものは作れた。

以上、「pyxel」に今来た私が試したこと(ChatGPT先生と共に)でした。

最後までご覧いただきましてありがとうございました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?