[[目次へもどる>PuyoPuyo]]
* 終止符を打とう [#d648c53c]
#contents

さて,今のままでは延々とブロックが降ってきて無限の恐怖を感じるので
そろそろゲームオーバーを作ろう.

** ゲームオーバーのチェック [#nac25f5c]

ゲームオーバーのために必要な情報は
- ブロックがあったらだめな位置~
これである.ここではこの位置のことをダメポイントと呼ぶ.
また,フィーバーではこのダメポイントは2カ所存在する.
そこで,フィールドコントローラーがフィールドを作る際,
ゲームオーバーになるフィールドの位置の配列drown_areaを引数として渡すことにする.
これでダメポイントを任意の位置に任意の数設定することができる.
このフィールド上のダメポイントすべてをダメエリアと呼ぶことにしよう.

#sh(ruby){{
class FieldController
  def initialize(x,y,row_s, line_s, block_s)
    @x = x; @y = y
    @colors = [:r, :g, :b, :y]
    @row_s = row_s; @line_s = line_s; @block_s = block_s
    @drown_area = [[2,11]]
    init_control_block_manager
    init_score_manager
    init_field
    init_phase
  end
  def init_field
    @field = Field.new(@row_s, @line_s, @block_s, @drown_area, @cbm, @sm)
  end
end
}}

そしてフィールドは受け取ったダメポイントの配列を描画などの拡張を考えたDrownPosのインスタンスの配列に変換する.
これが実際に使用するダメエリアの情報である.~
check_gameoverメソッドではダメエリアにブロックがあればtrueを返す.

#sh(ruby){{
class Field
  def initialize(row_s, line_s, block_s, drown_area, cbm, sm)
    @row_s = row_s
    @line_s = line_s
    @block_s = block_s
    @drown_area = drown_area.map{|pos| DrownPos.new(*pos,@block_s)}
    @fallen = false
    @eliminated = false
    @cbm = cbm
    @sm = sm
    @chain = 0
    @jammer_rate = 70
    init_table
    init_jammer_manager
    init_blocklist
    init_connect_table
  end
  def draw_field(x,y)
    y = @line_s * @block_s + y
    # draw drown area
    @drown_area.each do |drown_pos|
      drown_pos.draw(x,y)
    end

    # draw blocks
    all_blocks.each do |block|
      block.draw(x,y)
    end
  end
  def check_gameover
    (@active_blocks + @jamming_blocks).any? do |block|
      m = block.row; n = block.line
      @drown_area.map{|pos| pos.to_a }.include? [m,n]
    end
  end
end
}}

DrownPosクラスはダメポイントの位置と描画のためにブロックサイズを保持するだけの
シンプルなクラスである.

#sh(){{
class DrownPos
  def initialize(m, n, block_s)
    @row = m; @line = n
    @block_s = block_s
  end

  def draw(ox,oy)
    x = ox + @row * @block_s
    y = oy - @line * @block_s
    screen = GameMain.screen
    screen.render_rect(x, y, @block_s, @block_s, StarRuby::Color.new(255,0,0,180))
  end

  def to_a
    [@row, @line]
  end
end
}}

** ゲームオーバーフェーズ [#z07f3d5a]
ゲームオーバーかどうかのチェックはできるようになったので,
あとは実際にゲームオーバーにする処理を加えよう.

#sh(ruby){{
class FieldController
  def init_phase
    @phase = Phase.new
    (略)
    # added :gameover handler
    @phase.add_condition_handler(:gameover, method(:gameover_cond))

    @phase.change :control_block
  end
  def update
    update_blocks
    draw_field
    return if @phase.dead?
    return if @phase.waiting
    case @phase.phase
    when :phase_trans
      @phase.trans_condition_check
    when :control_block
      update_control_block
    when :falldown
      update_falldown
    when :eliminate
      update_eliminate
    when :fall_jammer
      update_fall_jammer
    when :gameover
      update_gameover
    end
  end
  def update_gameover
    @phase.wait(60)
    @phase.change :term
  end
  def gameover_cond
    @phase.kill
  end
  def dead?
    @phase.dead?
  end
end
}}

いつものようにフェーズを追加する.
いつもとことなるのはゲームオーバーフェーズのupdate_gameoverとgameover_condにある
@phase.change :termと@phase.killだろう.~
前者はなんのことはなく,ここでフェーズの処理が終了するので遷移先に
ダミーのフェーズを与えているだけである.~
後者はフェーズを殺すメソッドである.
これが呼ばれるとupdateメソッドにある@phase.dead?がtrueを返すようになり,
以後フェーズの処理は行われなくなる.

#sh(ruby){{
class Phase
  def initialize
    (略)
    @death = false                # phase termination flag
  end
  def kill
    @death = true
  end
  def dead?
    @death
  end
end
}}

あとはフェイスが死んだら(フィールドコントローラーが死んだら)シーンを終了すれば良い.
今はとりあえず再び同じシーンを呼び出しているが・・・.
#sh(ruby){{
class ScenePuyoPuyo < SceneBase
  def update
    super
    @players.each do |controller|
      controller.update
      GameMain.scene_change ScenePuyoPuyo if controller.dead?
    end

    @playtime += 1
  end
end
}}

** 実行 [#p643d00d]
ダメポイントにブロックが乗るとしばしの沈黙ののち淡々と次のゲームが始まる・・・.
#media(PuyoPuyoChap29/PuyoPuyoChap29.flv)


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS