[[目次へもどる>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)