pyglet でプレイヤーから弾を撃つ

移動も出来たら、次は弾でも撃ってみましょうか。

キーボードでプレイするなら [SPACE] キーで撃つのが普通っぽい(pyglet のサンプルもそうですし)ので、真似するとして。

絵を用意するのも手間ですし、とりあえずはまたテキストでやりましょう。大文字の I とか出しておけば弾っぽく見えます。たぶん。

動いていたらもうちょっと弾に見えるんですけれど…。静止画だとなんだか、なんだこれみたいな…。

ちょこちょこと追加してきて、だいぶソースが長くなってきてしまいました。もう100行。そろそろ先送りにしてきた git 管理を考える頃かもしれません。

  • ‘<->’ の文字はプレイヤーだ! というのを強調するために変数名を player に変更
  • on_key_press にスペースキー判定を追加
  • スペースキーが押されたら fire() を呼び出して、テキストラベルをプレイヤーの位置に作成
  • 新しく出現した弾は bullets[] に入れて管理して、あとで draw や update から呼び出せるように対応
  • update では上方向に常に移動するように対応
  • ついでに、弾が画面外に出たら消えるように対応

などなどやってみました。プログラムで書いたら短いけれど、言葉で書く方が長くなるくらいな感じです。

import pyglet
from pyglet.window import key
from collections import defaultdict
import math

window = pyglet.window.Window()

player = pyglet.text.Label('<->',
                          font_name='Courier New',
                          font_size=12,
                          x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')


bullets = []

def fire():
    bullet = pyglet.text.Label('I', font_name='Courier New', font_size=12,
                               x=window.width//2, y=window.height//2,
                               anchor_x='center', anchor_y='center')
    bullet.x = player.x
    bullet.y = player.y
    bullets.append(bullet)

@window.event
def on_draw():
    window.clear()
    player.draw()
    for bullet in bullets:
        bullet.draw()

key_status = defaultdict(bool)

@window.event
def on_key_press(symbol, modifiers):
    key_status[symbol] = True
    if symbol == key.SPACE:
        fire()

@window.event
def on_key_release(symbol, modifiers):
    key_status[symbol] = False

# プレイヤー移動速度(1 秒あたりのピクセル数)
MOVE_SPEED = 320
# 弾の速度
BULLET_SPEED = 480

# 上下左右ボタンの定義
BUTTON_UP       = 0x01
BUTTON_RIGHT    = 0x02
BUTTON_LEFT     = 0x04
BUTTON_DOWN     = 0x08

def update(dt):
    dx = 0
    dy = 0
    d = dt * MOVE_SPEED
    bit_count = 0

    button = 0
    if key_status[key.W]: # up
        button |= BUTTON_UP
        bit_count += 1
        dy = d
    elif key_status[key.S]: # down
        button |= BUTTON_DOWN
        bit_count += 1
        dy = -d
    
    if key_status[key.A]: # left
        button |= BUTTON_LEFT
        bit_count += 1
        dx = -d
    elif key_status[key.D]: # right
        button |= BUTTON_RIGHT
        bit_count += 1
        dx = d

    # 同時にキーが複数押されているなら斜め移動なので、速度を下げる。
    # Python 3.10 なら bit_count が使える
    # bit_count = button.bit_count()
    if bit_count == 1:
        player.x += dx
        player.y += dy
    elif bit_count == 2:
        player.x += dx / math.sqrt(2)
        player.y += dy / math.sqrt(2)

    # bullet 位置を更新し、範囲外のオブジェクトは削除
    dead_objects = []
    for bullet in bullets:
        bullet.y += dt * BULLET_SPEED
        if bullet.y > window.height:
            dead_objects.append(bullet)
    for to_remove in dead_objects:
        bullets.remove(to_remove)


pyglet.clock.schedule_interval(update, 1 / 120.0)

pyglet.app.run()
タイトルとURLをコピーしました