コマンド呼び出しコマンド

このあいだのやつに:call_commandを追加してみた。
回数指定で別のコマンド列を呼び出すことができる。
コマンド列が終わったら元の場所に戻る必要があるし、無制限にネストができるようにもしたかったから、@stackを追加した。

class Sprite
  attr_accessor :x, :y, :wait, :dx, :dy
  attr_reader :angle, :speed, :delete
  TO_RADIAN = 1 / 180.0 * Math::PI

  def initialize(x, y, angle, speed, image, command)
    @x = x
    @y = y
    @angle = angle
    @speed = speed
    @image = image
    @pc = 0
    @wait = 0
    @dx = Math.cos(@angle * TO_RADIAN) * @speed
    @dy = Math.sin(@angle * TO_RADIAN) * @speed
    @command = command
    @delete = false
    @width = @image.width
    @height = @image.height
    @stack = []
  end

  def update
    while(@wait == 0) do
      c = @command[@pc]
      if c.size == 2
        self.__send__ c[0], c[1]
      elsif c.size == 1
        self.__send__ c[0]
      else
        self.__send__ c[0], *c[1..-1]
      end
      @pc += 1
      if @pc == @command.size
        if @stack.size == 0
          @pc = 0
        else
          @count -= 1
          if @count == 0
            @command = @stack.pop
            @pc = @stack.pop
          else
            @pc = 0
          end
        end
      end
    end
    @x += @dx
    @y += @dy
    self.out_screen if @x + @width < 0 or @x > 639 or @y + @height < 0 or @y > 479
    @wait -= 1
  end

  def call_command(com, count)
    @stack.push(@pc + 1 == @command.size ? 0 : @pc + 1)
    @stack.push(@command)
    @command = com
    @pc = -1
    @count = count
  end

#以下同じなので略

これができると、例えばこんな感じで

  action1 = [
    [:rotation, 5],
    [:fire],
    [:wait=, 1]
  ]
  action2 = [
    [:rotation, -5],
    [:fire],
    [:wait=, 1]
  ]
  @@command = [
    [:call_command, action1, 72],
    [:call_command, action2, 72],
  ]

左右にぐるぐる回りながら弾をばらまくとかができるようになる。


敵のキャラの移動と攻撃開始指定は同期が取れないとまずいが、移動制御と弾をばらまく処理の同期は一つのコマンド列で行うのは難しい。
従って、敵のオブジェクトが複数のコマンド列(移動用と攻撃用)を実行できるようにするか、常に敵と同じ座標になる描画しない隠しオブジェクト(バレットジェネレータ)を生成するか、になる。
複数のコマンド列を実行すると、保持するパラメータが増えるし、複数の弾幕を同時生成する(砲台が2個あるとか)などができるようにすると大変なことになるから、バレットジェネレータ式にするのがよいのではないかと思う。
ジェネレータは弾幕の生成が終わったら消えないといけない。コマンドに:vanishが必要だ。消えるのは上位の配列からの削除になって、上の制御部分も作りこんで連携させる必要がある。