もどる

この記事は「うずら」とAIが協力して作成しました。
なるべく正確さを心がけていますが、最新の公式ドキュメントなどもあわせて確認してみてね!

python2026.3.17

4-7. 戦艦の猛攻:動き出す巨体と弾幕回避

実践:弾幕
回避せよ

皆さん、こんにちは!世界最高に親切な技術講師うずらです。

前回の授業 実践:巨大戦艦接近遭遇 では、画面に巨大な戦艦を出現させるところまで進みました。
ただそこにいるだけのボスも威圧感がありましたが、やはり敵は動いてこそ!
今回は、その巨体に命を吹き込み、プレイヤーを襲う激しい弾幕を実装していきます。

ついにボスが動き出し、激しい攻撃を繰り出すようになります。
「目に見える形でPythonを学ぶ」醍醐味を存分に味わいましょう!

1. 3秒でわかるまとめ

今回のゴールは、巨大戦艦に降下・左右移動といった動きを与え、さらにプレイヤーを狙う扇状の弾幕攻撃を実装することです。

2. 巨大戦艦、戦場に降下!そして左右へ威圧的な移動

まずは、前回の記事 実践:巨大戦艦接近遭遇 で画面上に出現させただけのボスに、動きを加えていきましょう。
ボスが画面上部からゆっくりと降下し、ある位置で停止して左右に移動する、という基本的な行動パターンを実装します。

update() 関数内の if boss: のブロックに以下のコードを追加・変更します。

    # ボスの行動
    if boss:
        # 上から降下
        if boss['y'] < 10:
            boss['y'] += 0.5
        else:
            # 左右移動
            boss['x'] += boss['dir']
            if boss['x'] < 10 or boss['x'] > SCREEN_WIDTH - BOSS_W - 10:
                boss['dir'] *= -1
            
            # 定期的に弾を発射
            # if pyxel.frame_count % 50 == 0:
            #     spawn_boss_bullets(boss['x'] + BOSS_W//2, boss['y'] + BOSS_H)

変更点の解説:

  • boss['y'] < 10 で降下制御:
    • ボスの y 座標が 10 より小さい間は、boss['y'] += 0.5 で少しずつ下に移動させます。
    • 0.5 という値は、ボスの降下速度を表します。この値を大きくすると、より速く降下するようになります。
    • 10 というのは画面上部から 10 ピクセル下の位置で、ここに到達したら降下を停止するという意味です。
  • else ブロックで左右移動:
    • y 座標が 10 に達したら、else ブロックに処理が移り、左右への移動を開始します。
    • boss['x'] += boss['dir'] でボスの x 座標を boss['dir'] の値だけ増減させます。boss['dir']1 または -1 の値を取る変数で、ボスの移動方向を制御します。
    • boss['x'] < 10 (画面左端に近づいた場合) または boss['x'] > SCREEN_WIDTH - BOSS_W - 10 (画面右端に近づいた場合) という条件で boss['dir'] *= -1 を実行し、移動方向を反転させます。
    • これにより、ボスは画面上部で左右に揺れ動くようになります。

補足だよ

SCREEN_WIDTH - BOSS_W - 10 のように、画面の幅からボスの幅と余白を引くことで、ボスが画面の端からはみ出さないように計算しています。

この変更で、巨大戦艦は画面上部に降下し、左右に動く威圧的な存在へと変わります。
しかし、まだ攻撃してきませんね。次は弾幕の生成に進みましょう。

3. 猛攻開始!ボスからの弾幕を生成せよ

ボスがただ動くだけでは物足りません。プレイヤーを追い詰める弾幕を生成させましょう!
まずは、ボス専用の弾を生成する関数 spawn_boss_bullets() を新しく定義します。

# ボスから弾を発射する
def spawn_boss_bullets(bx, by):
    # 5方向への扇状ショット
    for angle in range(-2, 3):
        vx = angle * 0.8
        vy = 1.5
        enemies.append({
            'x': bx, 'y': by,
            'vx': vx, 'vy': vy,
            'hp': 1,
            'type': 'bullet',
            'w': 4, 'h': 4,
            'score': 0
        })

関数の解説:

  • spawn_boss_bullets(bx, by):
    • ボスの x 座標 (bx) と y 座標 (by) を引数として受け取ります。
    • for angle in range(-2, 3): で、-2, -1, 0, 1, 2 の計5回ループします。これにより、5方向への弾を生成します。
    • vx = angle * 0.8vy = 1.5 で、弾の横方向 (vx) と縦方向 (vy) の速度を決定します。
      • angle を使うことで、vx の値が -1.6, -0.8, 0, 0.8, 1.6 と変化し、弾が扇状に広がる動きを作り出します。
      • vy は常に 1.5 なので、弾はまっすぐ下に進行しながら、横に少しずつずれていきます。
    • enemies.append(...) で、この弾を通常の敵と同じ enemies リストに追加します。
      • 'type': 'bullet' とすることで、これがボスの弾であることを区別しています。
      • 弾の幅('w')と高さ('h')は 4 に設定しています。

この関数を update() 関数内のボスの行動ロジックに追加します。

    # ボスの行動
    if boss:
        # 上から降下
        if boss['y'] < 10:
            boss['y'] += 0.5
        else:
            # 左右移動
            boss['x'] += boss['dir']
            if boss['x'] < 10 or boss['x'] > SCREEN_WIDTH - BOSS_W - 10:
                boss['dir'] *= -1
            
            # 定期的に弾を発射  <--- ここに追記
            if pyxel.frame_count % 50 == 0:
                spawn_boss_bullets(boss['x'] + BOSS_W//2, boss['y'] + BOSS_H)
  • if pyxel.frame_count % 50 == 0::
    • pyxel.frame_count はゲームが開始してからのフレーム数を数える変数です。
    • この条件式は、「ゲーム開始から50フレームごとに一度」True になることを意味します。つまり、50フレーム(約0.8秒)ごとにボスが弾を撃つようになります。
  • spawn_boss_bullets(boss['x'] + BOSS_W//2, boss['y'] + BOSS_H):
    • ボスの弾は、ボスの中心の x 座標 (boss['x'] + BOSS_W//2) と、ボスの下端の y 座標 (boss['y'] + BOSS_H) から発射されるように指定しています。これにより、ボスの下から弾が飛び出すように見えます。

豆知識

vxvyの値、range()の範囲を調整するだけで、ボスの弾が扇状に広がったり、まっすぐ飛んだり、特定の方向に集中したりと、さまざまな弾幕パターンを作り出すことができます。ゲームの難易度や面白さを変える重要な要素です。

4. 迫りくる弾を回避せよ!ボス弾との当たり判定

ボスが弾を撃つようになったので、次はその弾が画面上を移動し、プレイヤーに当たったらゲームオーバーになる処理を実装しましょう。

4-1. ボス弾の移動処理

ボスの弾は enemies リストに追加されています。そのため、既存の敵の更新ループの中で、弾の種類に応じて移動処理を分岐させる必要があります。
update() 関数内の 敵の更新 の部分を以下のように変更します。

    # 敵の更新
    surviving_enemies = []
    for e in enemies:
        if e['type'] == 'bullet': # <--- 追加
            e['x'] += e['vx']     # <--- 追加
            e['y'] += e['vy']     # <--- 追加
        else:
            e['y'] += e['vy']
            
        # ... (中略) ...

        if e['y'] > SCREEN_HEIGHT:
            continue

        hit_w = ENEMY_W if e['type'] != 'bullet' else 4 # <--- 変更
        if check_collision(player_x, player_y, PLAYER_W, PLAYER_H, e['x'], e['y'], hit_w, hit_w):
            game_over = True
            
        hit = False
        if e['type'] != 'bullet': # <--- 変更
            for b_idx in reversed(range(len(bullets))):
                bx, by = bullets[b_idx][0], bullets[b_idx][1]
                if (e['x'] < bx < e['x'] + ENEMY_W and
                    e['y'] < by < e['y'] + ENEMY_H):
                    del bullets[b_idx]
                    hit = True
                    break
        
        # ... (後略) ...

変更点の解説:

  • if e['type'] == 'bullet'::
    • 敵(e)がボスの弾タイプであれば、e['x']e['y']e['vx']e['vy'] を加算して移動させます。
    • それ以外の通常敵であれば、これまで通り e['y'] のみ加算して下に移動させます。
  • hit_w = ENEMY_W if e['type'] != 'bullet' else 4:
    • プレイヤーとの当たり判定で使う、敵の横幅 hit_w を計算しています。
    • もし敵が弾ではない ('type' != 'bullet') なら通常の敵の幅 ENEMY_W を、弾であれば弾の幅 4 を使います。
    • これにより、弾とプレイヤーの当たり判定が正確になります。
  • if e['type'] != 'bullet'::
    • プレイヤーの弾(bullets)が敵に当たった際の処理において、ボスの弾(e['type'] == 'bullet')はプレイヤーの弾では破壊されないようにしました。弾幕を撃ち返すゲームにする場合はこの条件を削除してください。

4-2. ボス弾の描画処理

最後に、ボスの弾が画面に表示されるように draw() 関数を修正しましょう。
draw() 関数内の の描画ループを以下のように変更します。

    # 敵
    for e in enemies:
        if e['type'] == 'bullet': # <--- 追加
            pyxel.circ(e['x'], e['y'], 2, COL_YELLOW) # <--- 追加
        else:
            col = e['color']
            pyxel.rect(e['x'], e['y'], e['w'], e['h'], col)
            if e['type'] == 'zako':
                pyxel.rect(e['x']+2, e['y']+2, 4, 4, COL_NAVY)
            else:
                pyxel.pset(e['x']+3, e['y']+3, COL_WHITE)

変更点の解説:

  • if e['type'] == 'bullet'::
    • 敵がボスの弾タイプであれば、pyxel.circ(e['x'], e['y'], 2, COL_YELLOW) を使って、黄色の丸として弾を描画します。
    • 2 は丸の半径です。
    • それ以外の通常敵は、これまで通り四角形で描画します。

これで、ボスが画面上を動き、弾幕を放ち、その弾に当たるとゲームオーバーになるまでが実装できました!
プレイヤーはボスの弾を避けながら、反撃していくことになりますね。

5. 今回のまとめと完成コード

今回は、巨大戦艦に命を吹き込み、動きと攻撃パターンを与えることに成功しました。

  • ボスが画面上部に降下し、左右に移動するロジックを実装しました。
  • ボスの位置とフレーム数に応じて、扇状に広がる弾幕を生成する spawn_boss_bullets 関数を作成しました。
  • ボスの弾がプレイヤーに衝突するとゲームオーバーになる判定を追加し、迫力あるボス戦の基礎が完成しました。

これで、いよいよゲームはクライマックスへと向かいますね!
次の授業 実践:決戦モード変化 では、ボスのHPに応じて攻撃パターンが変化する「モードチェンジ」を実装し、さらに戦略性の高いボス戦を作り上げていきましょう!

それでは、今回の完成コードです。

  <div class="my-16 max-w-full">
    <div class="bg-gradient-to-br from-purple-50 to-blue-50 border-4 border-purple-200 rounded-2xl p-6 md:p-8 shadow-xl">
      <div class="flex items-center gap-3 mb-6">
        <img src="/icons/icon-denkyu.png" alt="" class="w-8 h-8 flex-shrink-0" />
        <h4 class="font-black text-purple-900 text-xl">実際に動かしてみよう!</h4>
      </div>
      <div class="bg-white rounded-xl overflow-hidden border-2 border-purple-100 shadow-inner">
        <iframe 
          src="/dev-snapshots/run/4-7_boss_battle"
          class="w-full aspect-[4/3] border-0"
          title="Pyxel Game: 4-7_boss_battle.py"
          loading="lazy"
        ></iframe>
      </div>
      <p class="text-sm text-purple-700 font-bold mt-4 text-center">
        矢印キーで自機を移動、スペースキーでショット、ZキーまたはBキーでボムです。

巨大戦艦の猛攻を回避してください!



import pyxel
import random

# =========================================================
#  ASTRO SURVIVOR
#  - 宇宙シューティングゲーム -
# =========================================================

# --- 定数設定 ---
SCREEN_WIDTH = 160
SCREEN_HEIGHT = 120
STAR_COUNT = 40
GAME_TITLE = "ASTRO SURVIVOR"

# キャラクターのサイズ
PLAYER_W = 8
PLAYER_H = 8
PLAYER_SPEED = 3

ENEMY_W = 8
ENEMY_H = 8

BOSS_W = 24
BOSS_H = 24

# 色の定義
COL_BLACK   = 0
COL_NAVY    = 1
COL_PURPLE  = 2
COL_GREEN   = 3
COL_BROWN   = 4
COL_DBLUE   = 5
COL_LBLUE   = 6
COL_WHITE   = 7
COL_RED     = 8
COL_ORANGE  = 9
COL_YELLOW  = 10
COL_L_GREEN = 11
COL_CYAN    = 12
COL_GRAY    = 13
COL_PINK    = 14
COL_PEACH   = 15


# --- Pyxelの初期化と音の定義 ---
pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT, title=GAME_TITLE)

# --- 変数の初期化 ---
# プレイヤー
player_x = SCREEN_WIDTH // 2 - PLAYER_W // 2
player_y = SCREEN_HEIGHT - 20

# ゲームオブジェクト
bullets   = [] # [x, y, vx, vy]
enemies   = [] # Dictionary {'x', 'y', 'type', ...}
particles = [] # Dictionary
items     = [] # [x, y, kind]
stars     = [] # [x, y, speed]

# 星空の準備
for _ in range(STAR_COUNT):
    stars.append([
        random.randint(0, SCREEN_WIDTH),
        random.randint(0, SCREEN_HEIGHT),
        random.randint(1, 3)
    ])

# ゲーム進行状況
score = 0
game_over = False
boss_active = False

# パワーアップ & ボム
power_level = 1
power_timer = 0
num_bombs = 1
is_bomb_active = False
bomb_radius = 0

# ボスデータ
boss = None


# =========================================================
#  関数定義 (エフェクト生成など)
# =========================================================

# 爆発エフェクトなどを生成する
def spawn_particles(x, y, count, color):
    for _ in range(count):
        particles.append({
            'x': x, 
            'y': y,
            'vx': random.uniform(-2.0, 2.0),
            'vy': random.uniform(-2.0, 2.0),
            'life': random.randint(10, 20),
            'color': color
        })

# ボムを発動する
def trigger_bomb():
    global num_bombs, is_bomb_active, bomb_radius
    if num_bombs > 0 and not is_bomb_active:
        num_bombs -= 1
        is_bomb_active = True
        bomb_radius = 5

# 敵を出現させる
def spawn_enemy():
    is_fast = random.random() < 0.3
    kind = 'fast' if is_fast else 'zako'

    enemies.append({
        'x': random.randint(0, SCREEN_WIDTH - ENEMY_W),
        'y': -10,
        'vx': 0,
        'vy': random.uniform(1.5, 2.5) if is_fast else random.uniform(0.5, 0.8),
        'hp': 1,
        'type': kind,
        'w': ENEMY_W, 'h': ENEMY_H,
        'score': 20 if is_fast else 10,
        'color': COL_RED if is_fast else COL_GRAY
    })

# ボスから弾を発射する
def spawn_boss_bullets(bx, by):
    # 5方向への扇状ショット
    for angle in range(-2, 3):
        vx = angle * 0.8
        vy = 1.5
        enemies.append({
            'x': bx, 'y': by,
            'vx': vx, 'vy': vy,
            'hp': 1,
            'type': 'bullet',
            'w': 4, 'h': 4,
            'score': 0
        })

# アイテムを出現させる
def drop_item(x, y, kind):
    items.append([x, y, kind])

# 矩形同士の当たり判定
def check_collision(x1, y1, w1, h1, x2, y2, w2, h2):
    return (x1 < x2 + w2 and x1 + w1 > x2 and
            y1 < y2 + h2 and y1 + h1 > y2)


# =========================================================
#  メインループ (Update & Draw)
# =========================================================

# 毎フレーム実行される更新処理 (計算などはここで行う。描画は禁止)
def update():
    global player_x, player_y, score, game_over
    global power_level, power_timer, num_bombs, is_bomb_active, bomb_radius
    global boss, boss_active
    global bullets, enemies, particles, items

    # --- 1. ゲームオーバー / クリアチェック ---
    if game_over:
        return

    # --- 2. システム更新 (ボム & パワーアップ) ---
    if is_bomb_active:
        bomb_radius += 4
        if bomb_radius > 200:
            is_bomb_active = False
            bomb_radius = 0
            
    if power_timer > 0:
        power_timer -= 1
        if power_timer <= 0:
            power_level = 1

    # --- 3. プレイヤー操作 ---
    if pyxel.btn(pyxel.KEY_LEFT):  player_x = max(player_x - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_RIGHT): player_x = min(player_x + PLAYER_SPEED, SCREEN_WIDTH - PLAYER_W)
    if pyxel.btn(pyxel.KEY_UP):    player_y = max(player_y - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_DOWN):  player_y = min(player_y + PLAYER_SPEED, SCREEN_HEIGHT - PLAYER_H)

    # 弾の発射
    if pyxel.btnp(pyxel.KEY_SPACE):
        # 通常弾
        if power_level == 1:
            bullets.append([player_x + 3, player_y - 4, 0, -5])
        # パワーアップ弾 (3方向)
        elif power_level >= 2:
            bullets.append([player_x + 3, player_y - 4, 0, -5])
            bullets.append([player_x + 3, player_y - 4, -2, -4])
            bullets.append([player_x + 3, player_y - 4,  2, -4])

    # ボム発動
    if pyxel.btnp(pyxel.KEY_Z) or pyxel.btnp(pyxel.KEY_B):
        trigger_bomb()

    # --- 4. オブジェクト更新 ---
    # 弾の移動
    surviving_bullets = []
    for b in bullets:
        b[0] += b[2] # vx
        b[1] += b[3] # vy
        # 画面外でなければ残す
        if b[1] >= -10 and b[0] >= -10 and b[0] <= SCREEN_WIDTH + 10:
            surviving_bullets.append(b)
    bullets = surviving_bullets

    # 敵の出現
    if not boss_active:
        # 【一時的】ボスの動作確認のため、最初からボスを出現させる
        # 本来は if score >= 500: の条件
        if True:
            boss_active = True
            boss = {
                'x': SCREEN_WIDTH // 2 - BOSS_W // 2,
                'y': -40,
                'hp': 125,
                'max_hp': 125,
                'dir': 1
            }
        elif pyxel.frame_count % 30 == 0:
            spawn_enemy()

    # ボスの行動
    if boss:
        # 上から降下
        if boss['y'] < 10:
            boss['y'] += 0.5
        else:
            # 左右移動
            boss['x'] += boss['dir']
            if boss['x'] < 10 or boss['x'] > SCREEN_WIDTH - BOSS_W - 10:
                boss['dir'] *= -1
            
            # 定期的に弾を発射
            if pyxel.frame_count % 50 == 0:
                spawn_boss_bullets(boss['x'] + BOSS_W//2, boss['y'] + BOSS_H)

        # ボス vs プレイヤー
        if check_collision(player_x, player_y, PLAYER_W, PLAYER_H, boss['x'], boss['y'], BOSS_W, BOSS_H):
            game_over = True

        # ボス vs 弾
        for b_idx in reversed(range(len(bullets))):
            bx, by = bullets[b_idx][0], bullets[b_idx][1]
            if (boss['x'] < bx < boss['x'] + BOSS_W and
                boss['y'] < by < boss['y'] + BOSS_H):
                
                boss['hp'] -= 1
                spawn_particles(bx, by, 5, COL_YELLOW)

                del bullets[b_idx]
                
                if boss['hp'] <= 0:
                    boss = None
                    score += 1000
                    boss_active = False
                    spawn_particles(player_x, player_y - 20, 100, COL_RED) 
                    break

    # 敵の更新
    surviving_enemies = []
    for e in enemies:
        if e['type'] == 'bullet':
            e['x'] += e['vx']
            e['y'] += e['vy']
        else:
            e['y'] += e['vy']
            
        destroyed = False
        if is_bomb_active:
             # ボムの範囲 (中心座標から左上座標を計算)
             bomb_x = player_x + 4 - bomb_radius
             bomb_y = player_y + 4 - bomb_radius
             bomb_size = bomb_radius * 2
             
             if check_collision(bomb_x, bomb_y, bomb_size, bomb_size, e['x'], e['y'], ENEMY_W, ENEMY_H):
                 destroyed = True

        if destroyed:
            spawn_particles(e['x'], e['y'], 5, COL_WHITE)
            if e['type'] != 'bullet': score += 10
            continue # del せずにループ続行 (appendされないので消える)

        if e['y'] > SCREEN_HEIGHT:
            continue

        hit_w = ENEMY_W if e['type'] != 'bullet' else 4
        if check_collision(player_x, player_y, PLAYER_W, PLAYER_H, e['x'], e['y'], hit_w, hit_w):
            game_over = True
            
        hit = False
        if e['type'] != 'bullet':
            for b_idx in reversed(range(len(bullets))):
                bx, by = bullets[b_idx][0], bullets[b_idx][1]
                if (e['x'] < bx < e['x'] + ENEMY_W and
                    e['y'] < by < e['y'] + ENEMY_H):
                    del bullets[b_idx]
                    hit = True
                    break
        
        if hit:
            spawn_particles(e['x'], e['y'], 5, e['color'])
            score += e['score']
            
            dice = random.random()
            if dice < 0.08: drop_item(e['x'], e['y'], 'bomb')
            elif dice < 0.18: drop_item(e['x'], e['y'], 'power')
            continue
        
        surviving_enemies.append(e)
    enemies = surviving_enemies

    # アイテム更新
    surviving_items = []
    for item in items:
        item[1] += 1
        ix, iy, kind = item
        
        if check_collision(player_x, player_y, PLAYER_W, PLAYER_H, ix, iy, 4, 4):
            if kind == 'power':
                power_level = 2
                power_timer = 300
            elif kind == 'bomb':
                num_bombs += 1
            continue # 取得したのでリストに追加しない (消える)

        if iy <= SCREEN_HEIGHT:
            surviving_items.append(item)
    items = surviving_items

    # パーティクル更新
    surviving_particles = []
    for p in particles:
        p['x'] += p['vx']
        p['y'] += p['vy']
        p['life'] -= 1
        if p['life'] > 0:
            surviving_particles.append(p)
    particles = surviving_particles



# 毎フレーム実行される描画処理 (結果を画面に表示する。計算はしない)
def draw():
    pyxel.cls(COL_BLACK)
    
    # 背景
    for star in stars:
        pyxel.pset(star[0], star[1], COL_WHITE if star[2] > 1 else COL_GRAY)

    # 衝撃波
    if is_bomb_active:
        pyxel.circb(player_x + 4, player_y + 4, bomb_radius, COL_WHITE)
        pyxel.circb(player_x + 4, player_y + 4, bomb_radius - 2, COL_LBLUE)

    # ゲームオーバー
    if game_over:
        pyxel.text(55, 50, "GAME OVER", COL_RED)
        pyxel.text(45, 60, f"SCORE: {score}", COL_WHITE)
        return
        
    # プレイヤー
    col = COL_ORANGE
    if power_level >= 2:
        if power_timer < 90 and pyxel.frame_count % 4 < 2: col = COL_ORANGE
        else: col = COL_CYAN
    pyxel.rect(player_x, player_y, PLAYER_W, PLAYER_H, col)
    pyxel.rect(player_x+3, player_y-2, 2, 2, COL_YELLOW)

    # 弾
    for b in bullets:
        pyxel.rect(b[0], b[1], 2, 4, COL_L_GREEN)

    # 敵
    for e in enemies:
        if e['type'] == 'bullet':
            pyxel.circ(e['x'], e['y'], 2, COL_YELLOW)
        else:
            col = e['color']
            pyxel.rect(e['x'], e['y'], e['w'], e['h'], col)
            if e['type'] == 'zako':
                pyxel.rect(e['x']+2, e['y']+2, 4, 4, COL_NAVY)
            else:
                pyxel.pset(e['x']+3, e['y']+3, COL_WHITE)
            
    # ボス
    if boss:
        if boss['hp'] > 20 or pyxel.frame_count % 4 < 2:
            pyxel.rect(boss['x'], boss['y'], BOSS_W, BOSS_H, COL_PINK)
            bar_w = (boss['hp'] / boss['max_hp']) * BOSS_W
            pyxel.rect(boss['x'], boss['y'] - 3, bar_w, 2, COL_RED)

    # アイテム
    for item in items:
        char = "P" if item[2] == 'power' else "B"
        col  = COL_YELLOW if item[2] == 'power' else COL_CYAN
        pyxel.text(item[0], item[1], char, col)

    # UI
    pyxel.text(5, 5, f"SCORE:{score}", COL_WHITE)
    pyxel.text(120, 5, f"BOMB:{num_bombs}", COL_CYAN)
    if boss and boss_active:
        pyxel.text(60, 5, "WARNING: BOSS", COL_RED)

pyxel.run(update, draw)

最後まで読んでくれてありがとう!🌱
ノートみたいに、いつでも見返してね。