top of page

北尾崇氏の講演中に完成!Pyxelで30分シューティングゲーム開発チャレンジ(pythonコード付き)


先日、AICUで開催された「AICU Creators Talk 5 Pythonをゲーム開発で楽しく学ぶ 書籍出版記念ワークショップ」に参加してきました。このイベントでは、Pyxelの開発者である北尾崇さん(@kitao)が「ゲーム開発少年からの30年を30分で!」というタイトルで講演されていました。



実は私、その講演を聴きながら「じゃあ私も30分でゲーム作れるんじゃね?」と思い立ち、その場でシューティングゲームを開発してみることにしました。今回はその開発過程と成果を紹介します!


Pyxelとは?

Pyxelは北尾さんが開発したPython向けのレトロゲームエンジンです。16色のカラーパレットや同時再生音数の制限など、あえてレトロな制約を設けることで、初心者でも取り組みやすく、また創造性を引き出すことを目的としています。



Pyxelは、開発者の北尾氏により、Pyxelを使ったゲーム開発方法をまとめた書籍として販売されています。



私自身、Pythonは使ったことがあるものの、Pyxelは今回が初めての挑戦。「30分でゲームが作れるのか?」という疑問を抱きながらも、思い切って挑戦することにしました。


開発環境の準備

今回は以下のような環境で開発を行いました:


  • エディタ:Windsurf


  • 開発支援:Claude 3.5 Sonnet(AI)


  • 参考資料:PyxelのREADMEとサンプルコード


プロジェクトのファイル構成はこんな感じです。


pyxel-test/

├── docs/ - プロジェクトのドキュメントが含まれるディレクトリ

│ ├── pyxel-manual.md - Pyxel のREADMEとサンプルコードをまとめたファイル

│ ├── ゲーム仕様書.md - ゲームの仕様書(日本語)

├── assets.pyxres - Pyxelのリソースファイル(画像、タイルマップ、サウンドなど)

├── main.py - プロジェクトのメインのPythonスクリプトファイル

└── README.md - プロジェクトの概要や使用方法を記載したドキュメント


Pyxel Editorでリソース作成


ゲーム開発の最初のステップとして、Pyxel Editorを使ってゲームで使用する画像リソースを作成しました。コマンドラインで以下のコマンドを実行すると、Pyxel Editorが起動します。


pyxel edit assets.pyxres



Pyxel Editorには以下の4つの編集モードがあります。


  1. Image Editor: 各イメージバンクの画像を編集するモード


  2. Tilemap Editor: イメージバンクの画像をタイルパターンで配置するモード


  3. Sound Editor: メロディやサウンドエフェクトに使用するサウンドを編集するモード


  4. Music Editor: サウンドを再生順に配置した音楽を編集するモード


今回は主にImage Editorを使用して、プレイヤー、敵、ボス、弾などのスプライトを作成しました。ドット絵を描くのは初めてでしたが、Pyxel Editorのシンプルなインターフェースのおかげで直感的に操作できました。


作成したスプライトは以下の通りです。


  • プレイヤーの宇宙船 (8x8ピクセル)



  • 敵の小型機 (8x8ピクセル)



  • 中ボス (16x16ピクセル)



  • ラスボス (16x16ピクセル)



  • 弾 (8x2ピクセル)



リソースファイルが完成したら、「pyxel.load("assets.pyxres")」でゲーム内に読み込むことができます。


AIの力を借りた開発プロセス

実は今回、開発をスピードアップするためにClaude 3.5 Sonnetの力を借りました。具体的には、PyxelのREADMEとサンプルコードをAIに読み込ませ、シューティングゲームの基本構造を提案してもらいました。


AIとの対話例

私:「Pyxelを使って簡単なシューティングゲームを作りたいです。プレイヤーが移動して弾を撃ち、敵を倒すゲームの基本構造を教えてください。」


Claude:「Pyxelでシューティングゲームを作るなら、まずはゲームのメインループを作成し、そこにプレイヤーの移動、弾の発射、敵の生成と移動、当たり判定などの機能を実装していきます。以下に基本構造を示します...」


こうしたやり取りを通じて、徐々にゲームの骨格を作り上げていきました。最終的に出力されたゲームの仕様は以下の通りです。


# シューティングゲーム仕様書


## 1. ゲーム概要

横スクロールシューティングゲームで、プレイヤーは宇宙船を操作して敵を倒しながら、中ボスとラスボスに挑戦します。


### 1.1 ゲームの目的

- 敵を倒してスコアを獲得

- 中ボス(スコア10)とラスボス(スコア30)を倒す

- ラスボスを倒すとゲームクリア


## 2. ゲームシステム


### 2.1 基本操作

- 矢印キー: 上下左右移動

- スペースキー: 弾を発射


### 2.2 プレイヤーキャラクター

- スプライト: assets.pyxres (0, 0)から8x8の領域

- 3機のライフ

- 敵や弾に当たるとライフが減少

- 被弾後は一時的な無敵時間あり(点滅で表示)


### 2.3 弾システム

- スプライト: assets.pyxres (8, 0)から8x2の領域

- スペースキー長押しで連射可能(10フレームごとに発射)

- 直線的に右方向へ移動

- 画面外に出ると消滅


### 2.4 通常の敵

- スプライト: assets.pyxres (16, 0)から8x8の領域

- 画面右から左へ移動

- ランダムな速度(1.0-2.0の範囲)

- 30フレームごとにランダムな高さから出現

- 弾に当たると消滅し、スコア+1


## 3. ボスキャラクター


### 3.1 中ボス(スコア10で出現)

- スプライト: assets.pyxres (40, 0)から16x16の領域

- HP: 20

- 倒すとスコア+10

- 移動パターン:

- 画面右側で上下に揺れる

- 左右にも小さく移動

- 攻撃パターン:

- 3方向に弾を発射

- 30フレームごとに攻撃


### 3.2 ラスボス(スコア30で出現)

- スプライト: assets.pyxres (24, 0)から16x16の領域

- HP: 40

- 倒すとスコア+20とゲームクリア

- 4つのフェーズを180フレームごとに切り替え

- 移動パターン:

1. 8の字移動(振幅20px)

2. ジグザグ移動(振幅15px)

3. 円運動(半径15px)

4. 急速な直線移動(振幅10px)

- 攻撃パターン:

1. 扇状の弾幕(8方向)

2. プレイヤー追尾弾(3方向)

3. 螺旋状の弾幕(4方向)

4. 全方向ランダム弾(6発)


## 4. ゲームの状態


### 4.1 ゲームオーバー条件

- プレイヤーのライフが0になる

- 「GAME OVER」表示

- Rキーでリスタート可能


### 4.2 ゲームクリア条件

- ラスボスを倒す

- 「GAME CLEAR!」表示

- Rキーでリスタート可能


### 4.3 画面表示

- ゲーム画面サイズ: 160x120ピクセル

- スコア表示: 左上

- 残機表示: スコアの下


## 5. エフェクト


### 5.1 爆発エフェクト

- キャラクターが破壊されると発生

- パーティクルが四方八方に飛び散る

- パーティクルの色: 8-10番の色を使用

- パーティクルの寿命: 30フレーム


### 5.2 その他のエフェクト

- 無敵時間中のプレイヤー点滅

- ボスのHPバー表示

- ボスの弾は通常の弾より大きく表示


## 6. 技術仕様

- 開発言語: Python

- 使用ライブラリ: Pyxel

- アセット管理: assets.pyxres

- フレームレート: 30FPS(Pyxelのデフォルト)


ゲームの実装

シューティングゲームの基本的な要素は以下の通りです:


  1. プレイヤーの移動と弾の発射


  2. 敵の生成と移動


  3. 当たり判定の実装


  4. ボス戦の実装


  5. ゲームオーバー/クリア条件の設定


プレイヤーの実装

プレイヤーは矢印キーで上下左右に移動でき、スペースキーで弾を発射します。連射も可能で、ホールド中は一定間隔で弾が出ます。


# プレイヤーの移動

if pyxel.btn(pyxel.KEY_UP):

self.player_y = max(self.player_y - self.player_speed, 0)

if pyxel.btn(pyxel.KEY_DOWN):

self.player_y = min(self.player_y + self.player_speed, pyxel.height - 8)

if pyxel.btn(pyxel.KEY_LEFT):

self.player_x = max(self.player_x - self.player_speed, 0)

if pyxel.btn(pyxel.KEY_RIGHT):

self.player_x = min(self.player_x + self.player_speed, pyxel.width - 8)


# 弾の発射(連射対応)

if pyxel.btn(pyxel.KEY_SPACE):

self.shoot_timer += 1

if self.shoot_timer == 1 or self.shoot_timer % 5 == 0: # 初回か5フレームごとに発射

self.bullets.append({

"x": self.player_x + 8,

"y": self.player_y + 3,

"speed": 4

})

else:

self.shoot_timer = 0 # スペースキーを離したらタイマーをリセット



敵の実装

敵は画面右から一定間隔で出現し、左に向かって移動します。ボスは特定のスコアに達すると出現します。


# 敵の生成

self.enemy_timer += 1

if self.enemy_timer >= 30 and not self.boss:

self.enemies.append({

"x": pyxel.width,

"y": pyxel.rndi(0, pyxel.height - 8),

"speed": pyxel.rndf(1, 2)

})

self.enemy_timer = 0



ボス戦の実装

ゲームには中ボスとラスボスの2種類のボスが登場します。それぞれ異なる移動パターンと攻撃パターンを持っています。


def spawn_boss(self, boss_type):

if boss_type == "mid":

self.boss = {

"type": "mid",

"x": pyxel.width - 40,

"y": pyxel.height // 2 - 8,

"width": 16,

"height": 16,

"hp": 20,

"score": 10,

# 他のパラメータ...

}

else: # final boss

self.boss = {

"type": "final",

"x": pyxel.width - 48,

"y": pyxel.height // 2 - 8,

"width": 16,

"height": 16,

"hp": 40,

"score": 20,

# 他のパラメータ...

}



開発中に直面した課題

当たり判定の実装

当たり判定は単純な矩形同士の衝突検出で実装しましたが、プレイヤーが死亡した後の処理や無敵時間の実装に少し手間取りました。


# プレイヤーと敵の当たり判定

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.create_explosion(self.player_x + 4, self.player_y + 4)

self.is_alive = False

self.explosion_timer = 30

self.lives -= 1

if self.lives <= 0:

self.game_over = True

break



ボスの攻撃パターン設計

特にラスボスの複雑な攻撃パターンの実装には時間がかかりました。4つのフェーズを作り、それぞれ異なる弾幕パターンを実装しています。


# ラスボスの攻撃(フェーズに応じて変化)

if boss["attack_phase"] == 0:

# 扇状の弾幕

for i in range(8):

angle = i * 0.785 + pyxel.sin(boss["move_timer"] * 0.1)

self.boss_bullets.append({

"x": boss["x"] + boss["width"]/2,

"y": boss["y"] + boss["height"]/2,

"dx": -4 * pyxel.cos(angle),

"dy": 4 * pyxel.sin(angle)

})



完成したゲームの特徴

完成したゲームは以下になります。プレイ映像の一部になりますが、ボス戦までの様子をご覧いただけます(動画は4倍速になります)。



細かく画面を確認していきます。左に自機がおり、右から左に向かって敵キャラが向かってきます。左上にはスコアと自機数が表示され、3回やられるとゲームオーバーです。敵キャラを倒すと、火花が散るようにしています。



以下は中ボスとの戦闘シーンです。ボスキャラの上部には緑色の体力バーが表示されており、これを0にすると撃破です。



以下は大ボスです。大ボスを撃破するとゲームクリアです。



大ボスを撃破し、無事ゲームクリアになります。



30分という短時間で開発したにも関わらず、以下のような機能を実装することができました。


  1. プレイヤーの移動と連射機能


  2. 敵の自動生成と移動


  3. 2種類のボスバトル(中ボスとラスボス)


  4. 複数の攻撃パターンと移動パターン


  5. 爆発エフェクト


  6. スコア表示とライフシステム


  7. ゲームオーバー/クリア画面


最終的なコードは以下になります。


★本稿はアイキューマガジンVol.10に収録予定です、お楽しみに!



この記事の続きはこちらから https://note.com/aicu/n/n4ed8d9da3f80

Originally published at note.com/aicu on March 5, 2025.


Comments


bottom of page