はじめに
この記事は、pyxel Advent Calendar 2024 の6日目の記事となります。
アドベントカレンダのリストを見ていて、今、Pyxelに来た者の記録です。
ChatGPT先生と共にPxcelで簡単なゲームを作ってみたいと思います。
ChatGPT 4oを使用する。
ChatGPTはPyxelを知っているか
ChatGPTはPyxelを知っているか聞いてみる。
ChatGPT先生、Pyxelをご存知の様子。
それではやり方を教えてもらおう
やり方を教えてもらう
pip install pyxel
ね。OK。インストールできた!。
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)
OK。わかったやってみる。
おお。できた!
アクションゲームを作ってもらう
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()
黄色が自機で、赤が敵。赤が上から降ってくるので黄色は避けるだけ。
動いたが、単純すぎる。
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()
実行してみる
弾が打てるようになった!たくさん同時に敵も出てくる。
あれ?5機倒すと、敵が全く出てこなくなってしまう。
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()
Score 5以降も動くようになった。
だがしかし、敵とぶつかってもゲームオーパーにならず、無敵だ。
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()
ほんとに?試してみる
ぶつかってみたところ、ゲームオーバー画面になった。
ただ、ここでキーを押しても何も起きず、この画面のままだ。
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()
本当か?実行してみよう。
Pyxelの実験 pic.twitter.com/3BM4oNdRAS
— toss (@MakeTOSS) December 22, 2024
OKバッチリ!
ゲームオーバーの画面でスペースキーなど押せば再度ゲームも開始するようになった。
まとめ
ChatGPTはPyxelを知っていて、インストール方法から、プログラムの生成まで可能。
指示として適切な内容を与えれば、1行もコードを書かずにこの程度のものは作れた。
以上、「pyxel」に今来た私が試したこと(ChatGPT先生と共に)でした。
最後までご覧いただきましてありがとうございました。