PuyoPuyoChap31
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[目次へもどる>PuyoPuyo]]
* 対戦しよう [#d133e914]
#contents
ゲームモードが作れるようになったので早速新しいゲームモー...
ここはやはりプレイヤー同士の対戦が作りたいところだ.
幸い2プレイヤーのためのフィールドコントローラーはすでに作...
今回作るべきはフィールドコントローラー間のやり取りである.
** 新しいゲームモード [#y0331ef0]
まずは新しいゲームモードのためのシーンを作ってしまおう.
SceneTwoPlayer((SceneTwoPlayersにするべきだった))は二人の...
対戦するゲームモードである.
とはいっても多人数プレイを意識した設計になっているので特...
ひとつシングルモードと異なるのはrivalsだろう.
ここに敵となるフィールドコントローラーの配列をセットする...
自動的にジャマーが相手に発生するようになる予定だ.
#sh(ruby){{
class SceneTwoPlayer < ScenePuyoPuyo
def start
super
player1 = Player1.new(16,16,6,12,16)
player2 = Player2.new(32 + 16 *6,16,6,12,16)
player1.rivals = [player2]
player2.rivals = [player1]
@players.push(player1)
@players.push(player2)
end
def gameover
GameMain.scene_change SceneTwoPlayer
end
end
}}
** ジャマーの発生と相殺 [#r812e95c]
フィールドコントローラーでセットするライバルの配列は
フィールドクラスを経てジャマーマネージャーの@rivalsにセッ...
このとき登録される配列の中身はライバルのジャマーマネージ...
ここで再びジャマーに関する考察を行おう.
まずあくまで個人的意見なのだが初代ぷよぷよの相殺なしルー...
ぷよぷよと認めていないので相殺は必須だろう.
また,フィーバーのように相殺している限りジャマーは降らな...
フィーバーモードがあるから活きるわけである.
よって今回は素直にぷよぷよ通のルールを採用しよう.~
すなわち
- ブロックを消すとライバルにジャマーが発生する
- 連鎖中に蓄積されているジャマーはその連鎖が終了するまで...
-- この状態のジャマーはジャマーバッファにたまる
-- 連鎖が終わるとバッファのジャマーは以前つくった確定ジャ...
- ジャマーが蓄積している場合ブロックを消すことで相殺する...
- ジャマー落下フェーズに移行した時,確定ジャマーが存在す...
#sh(ruby){{
class JammerManager
attr_accessor :rivals_buf
def initialize(row_s, line_s)
(略)
@rivals_buf = {}
@rivals = []
init_order
end
def rivals=(rivals)
@rivals = rivals.map{|rival| rival.field.jm }
@rivals_buf = {}
@rivals.each do |rival|
@rivals_buf[rival] = 0
end
end
def total_jammers
self.jammers + self.total_rivals_buf
end
def total_rivals_buf
@rivals_buf.inject(0){|sum,(rival,num)| sum + num}
end
def offset_rivals_buf(num)
return num if @rivals.empty?
offset_per = [num / @rivals.size, 1].max
rest = num
@rivals.shuffle.each do |rival|
return 0 if rest == 0
if rest >= offset_per && @rivals_buf[rival] >= offs...
@rivals_buf[rival] -= offset_per
rest -= offset_per
elsif @rivals_buf[rival] >= rest
@rivals_buf[rival] -= rest
rest = 0
else
rest -= @rivals_buf[rival]
@rivals_buf[rival] = 0
end
end
rest = offset_rivals_buf(num) if rest < num
rest
end
def store_buf(num)
# offset certain jammers
rest = num - self.jammers
self.jammers -= num
return if rest <= 0
# offset buffered jammers
rest = offset_rivals_buf(rest)
# attack
@rivals.each do |rival|
next if rival.rivals_buf[self].nil?
rival.rivals_buf[self] += rest
end
end
def establish_rival_buf(rival)
return if @rivals_buf[rival].nil?
@jammers += @rivals_buf[rival]
@rivals_buf[rival] = 0
end
def establish_jammers
@rivals.each do |rival|
rival.establish_rival_buf(self)
end
end
end
}}
ジャマーマネージャーが新しく持つ要素として@rivalsと@rival...
@rivalsは先程説明した通り敵となるフィールドコントローラー...
@rivals_bufはライバルの連鎖によって発生したジャマーをため...
ライバルごとにジャマー数が管理される.
ライバルが連鎖をするとこのバッファにジャマーが蓄積され,...
これらの処理はライバル側のジャマーマネージャーからsore_bu...
この処理により,あとは今までの設計のままでうまくジャマー...
相殺については,まずは確定ジャマーが存在すれば優先的に数...
ライバルのバッファにジャマーが存在すればバッファから数を...
このときどのライバルのバッファからどのくらい減らすかがよ...
ひとまず以下の再帰的な戦略をとることにした.
- 減らすことのできるジャマー数の合計をrestとする
- ライバル一人あたり減少させるジャマー数を求める(単純に等...
- ライバルごとにバッファの数を減らす
-- このとき減少した分をrestから減らしておく
- restが0ならもう減らせないので終了,0を返す
- restが減少していなければそもそもバッファにジャマーがな...
- それ以外ならまだ減らせるバッファがあるかもしれないので...
これを実装したのがoffset_rivals_bufメソッドである.
そしてこれら相殺を行った後,それでも余ったジャマーがライ...
に加算される.~
ライバルが複数いたときジャマーをどう分散するかといった問...
とりあえず等分などは行わずにライバル全員に発生したジャマ...
#sh(ruby){{
class Field
attr_reader :jm
def rivals=(rivals)
@jm.rivals = rivals
end
def eliminate
(略)
unless @connect_table.empty?
jammers = @jm.calc_jammer(@sm.chain_score, @jammer_...
@jm.store_buf(jammers)
end
(略)
end
end
}}
#sh(ruby){{
class FieldController
attr_reader :field
def rivals=(rivals)
@field.rivals = rivals
end
def init_phase
(略)
@phase.add_end_handler(:eliminate, :fall_jammer,
method(:end_eliminate_to_fall_...
(略)
end
def end_eliminate_to_fall_jammer
# establish jammers
@field.jm.establish_jammers
end
end
}}
*** 実行 [#y0bc4101]
デバッグ表示の右側がジャマーに関する情報である.
合計ジャマー = 確定ジャマー + ジャマーバッファ
という形式になっている.
プレイヤー2が連鎖中はジャマーバッファに蓄積されてジャマー...
その後プレイヤー1が相殺し連鎖が終わるとプレイヤー2の確定...
ジャマーが降っている様子がわかる.
#media(PuyoPuyoChap31/PuyoPuyoChap31_1.flv)
一人二役でいい相殺の例はとても無理なので,久しぶりにset_t...
** ゲームオーバーの処理 [#jca7e88f]
これでほぼ対戦のゲームモードは完成したわけだが,
今のままではどちらかがゲームオーバーになってももう一方が...
限りゲームが終了しない.負けたら暇である.~
そこでゲームオーバーに関してもうまくフィールドコントロー...
この機能のためには何が必要かといえばフェーズが終了してい...
この場フィールドコントローラーに関して
- 死んでいるか((dead?がtrue))
- フェーズがgameoverか~
この二点を調べるメソッドを作ればなんとかなりそうだ.
#sh(ruby){{
class FieldController
def initialize(x,y,row_s, line_s, block_s)
(略)
@rivals = []
(略)
end
def rivals=(rivals)
@rivals = rivals
@field.rivals = rivals
end
def init_phase
(略)
# added :win handler
@phase.add_condition_handler(:win, method(:win_cond))
@phase.change :control_block
end
def gameover?
@phase.phase == :gameover
end
def rivals_gameover?
return false if @rivals.empty?
@rivals.all? {|rival| rival.dead? || rival.gameover? }
end
def update_control_block
inputs = [input_move_row?,input_rotate?,
input_fastfall?,input_momentfall?]
active = @field.update_control_block(*inputs)
if active
@phase.change :win if rivals_gameover?
else
@phase.change :falldown
end
end
def update_eliminate
eliminated = @field.eliminate
if eliminated
@phase.change :falldown
else
@phase.change rivals_gameover? ? :win : :fall_jammer
end
end
def update_win
@phase.wait(60)
@phase.change :term
end
def win_cond
@phase.kill
end
end
}}
rivalsのセットメソッドにフィールドへライバルを伝達する前...
あとは次の状態のときライバル全員がゲームオーバーであれば
winフェーズへと移行すれば完成である.
- 連鎖が終了した時((eliminateフェーズの終了時))
- control_blockフェーズの時
連鎖中はwinフェーズへ移行しない仕様になっている.これは一...
winフェーズはgameoverフェーズと全く同じなので説明は不要だ...
*** 実行 [#k14971a3]
これでどちらかがゲームオーバーになればゲームが終了するよ...
#media(PuyoPuyoChap31/PuyoPuyoChap31_2.flv)
終了行:
[[目次へもどる>PuyoPuyo]]
* 対戦しよう [#d133e914]
#contents
ゲームモードが作れるようになったので早速新しいゲームモー...
ここはやはりプレイヤー同士の対戦が作りたいところだ.
幸い2プレイヤーのためのフィールドコントローラーはすでに作...
今回作るべきはフィールドコントローラー間のやり取りである.
** 新しいゲームモード [#y0331ef0]
まずは新しいゲームモードのためのシーンを作ってしまおう.
SceneTwoPlayer((SceneTwoPlayersにするべきだった))は二人の...
対戦するゲームモードである.
とはいっても多人数プレイを意識した設計になっているので特...
ひとつシングルモードと異なるのはrivalsだろう.
ここに敵となるフィールドコントローラーの配列をセットする...
自動的にジャマーが相手に発生するようになる予定だ.
#sh(ruby){{
class SceneTwoPlayer < ScenePuyoPuyo
def start
super
player1 = Player1.new(16,16,6,12,16)
player2 = Player2.new(32 + 16 *6,16,6,12,16)
player1.rivals = [player2]
player2.rivals = [player1]
@players.push(player1)
@players.push(player2)
end
def gameover
GameMain.scene_change SceneTwoPlayer
end
end
}}
** ジャマーの発生と相殺 [#r812e95c]
フィールドコントローラーでセットするライバルの配列は
フィールドクラスを経てジャマーマネージャーの@rivalsにセッ...
このとき登録される配列の中身はライバルのジャマーマネージ...
ここで再びジャマーに関する考察を行おう.
まずあくまで個人的意見なのだが初代ぷよぷよの相殺なしルー...
ぷよぷよと認めていないので相殺は必須だろう.
また,フィーバーのように相殺している限りジャマーは降らな...
フィーバーモードがあるから活きるわけである.
よって今回は素直にぷよぷよ通のルールを採用しよう.~
すなわち
- ブロックを消すとライバルにジャマーが発生する
- 連鎖中に蓄積されているジャマーはその連鎖が終了するまで...
-- この状態のジャマーはジャマーバッファにたまる
-- 連鎖が終わるとバッファのジャマーは以前つくった確定ジャ...
- ジャマーが蓄積している場合ブロックを消すことで相殺する...
- ジャマー落下フェーズに移行した時,確定ジャマーが存在す...
#sh(ruby){{
class JammerManager
attr_accessor :rivals_buf
def initialize(row_s, line_s)
(略)
@rivals_buf = {}
@rivals = []
init_order
end
def rivals=(rivals)
@rivals = rivals.map{|rival| rival.field.jm }
@rivals_buf = {}
@rivals.each do |rival|
@rivals_buf[rival] = 0
end
end
def total_jammers
self.jammers + self.total_rivals_buf
end
def total_rivals_buf
@rivals_buf.inject(0){|sum,(rival,num)| sum + num}
end
def offset_rivals_buf(num)
return num if @rivals.empty?
offset_per = [num / @rivals.size, 1].max
rest = num
@rivals.shuffle.each do |rival|
return 0 if rest == 0
if rest >= offset_per && @rivals_buf[rival] >= offs...
@rivals_buf[rival] -= offset_per
rest -= offset_per
elsif @rivals_buf[rival] >= rest
@rivals_buf[rival] -= rest
rest = 0
else
rest -= @rivals_buf[rival]
@rivals_buf[rival] = 0
end
end
rest = offset_rivals_buf(num) if rest < num
rest
end
def store_buf(num)
# offset certain jammers
rest = num - self.jammers
self.jammers -= num
return if rest <= 0
# offset buffered jammers
rest = offset_rivals_buf(rest)
# attack
@rivals.each do |rival|
next if rival.rivals_buf[self].nil?
rival.rivals_buf[self] += rest
end
end
def establish_rival_buf(rival)
return if @rivals_buf[rival].nil?
@jammers += @rivals_buf[rival]
@rivals_buf[rival] = 0
end
def establish_jammers
@rivals.each do |rival|
rival.establish_rival_buf(self)
end
end
end
}}
ジャマーマネージャーが新しく持つ要素として@rivalsと@rival...
@rivalsは先程説明した通り敵となるフィールドコントローラー...
@rivals_bufはライバルの連鎖によって発生したジャマーをため...
ライバルごとにジャマー数が管理される.
ライバルが連鎖をするとこのバッファにジャマーが蓄積され,...
これらの処理はライバル側のジャマーマネージャーからsore_bu...
この処理により,あとは今までの設計のままでうまくジャマー...
相殺については,まずは確定ジャマーが存在すれば優先的に数...
ライバルのバッファにジャマーが存在すればバッファから数を...
このときどのライバルのバッファからどのくらい減らすかがよ...
ひとまず以下の再帰的な戦略をとることにした.
- 減らすことのできるジャマー数の合計をrestとする
- ライバル一人あたり減少させるジャマー数を求める(単純に等...
- ライバルごとにバッファの数を減らす
-- このとき減少した分をrestから減らしておく
- restが0ならもう減らせないので終了,0を返す
- restが減少していなければそもそもバッファにジャマーがな...
- それ以外ならまだ減らせるバッファがあるかもしれないので...
これを実装したのがoffset_rivals_bufメソッドである.
そしてこれら相殺を行った後,それでも余ったジャマーがライ...
に加算される.~
ライバルが複数いたときジャマーをどう分散するかといった問...
とりあえず等分などは行わずにライバル全員に発生したジャマ...
#sh(ruby){{
class Field
attr_reader :jm
def rivals=(rivals)
@jm.rivals = rivals
end
def eliminate
(略)
unless @connect_table.empty?
jammers = @jm.calc_jammer(@sm.chain_score, @jammer_...
@jm.store_buf(jammers)
end
(略)
end
end
}}
#sh(ruby){{
class FieldController
attr_reader :field
def rivals=(rivals)
@field.rivals = rivals
end
def init_phase
(略)
@phase.add_end_handler(:eliminate, :fall_jammer,
method(:end_eliminate_to_fall_...
(略)
end
def end_eliminate_to_fall_jammer
# establish jammers
@field.jm.establish_jammers
end
end
}}
*** 実行 [#y0bc4101]
デバッグ表示の右側がジャマーに関する情報である.
合計ジャマー = 確定ジャマー + ジャマーバッファ
という形式になっている.
プレイヤー2が連鎖中はジャマーバッファに蓄積されてジャマー...
その後プレイヤー1が相殺し連鎖が終わるとプレイヤー2の確定...
ジャマーが降っている様子がわかる.
#media(PuyoPuyoChap31/PuyoPuyoChap31_1.flv)
一人二役でいい相殺の例はとても無理なので,久しぶりにset_t...
** ゲームオーバーの処理 [#jca7e88f]
これでほぼ対戦のゲームモードは完成したわけだが,
今のままではどちらかがゲームオーバーになってももう一方が...
限りゲームが終了しない.負けたら暇である.~
そこでゲームオーバーに関してもうまくフィールドコントロー...
この機能のためには何が必要かといえばフェーズが終了してい...
この場フィールドコントローラーに関して
- 死んでいるか((dead?がtrue))
- フェーズがgameoverか~
この二点を調べるメソッドを作ればなんとかなりそうだ.
#sh(ruby){{
class FieldController
def initialize(x,y,row_s, line_s, block_s)
(略)
@rivals = []
(略)
end
def rivals=(rivals)
@rivals = rivals
@field.rivals = rivals
end
def init_phase
(略)
# added :win handler
@phase.add_condition_handler(:win, method(:win_cond))
@phase.change :control_block
end
def gameover?
@phase.phase == :gameover
end
def rivals_gameover?
return false if @rivals.empty?
@rivals.all? {|rival| rival.dead? || rival.gameover? }
end
def update_control_block
inputs = [input_move_row?,input_rotate?,
input_fastfall?,input_momentfall?]
active = @field.update_control_block(*inputs)
if active
@phase.change :win if rivals_gameover?
else
@phase.change :falldown
end
end
def update_eliminate
eliminated = @field.eliminate
if eliminated
@phase.change :falldown
else
@phase.change rivals_gameover? ? :win : :fall_jammer
end
end
def update_win
@phase.wait(60)
@phase.change :term
end
def win_cond
@phase.kill
end
end
}}
rivalsのセットメソッドにフィールドへライバルを伝達する前...
あとは次の状態のときライバル全員がゲームオーバーであれば
winフェーズへと移行すれば完成である.
- 連鎖が終了した時((eliminateフェーズの終了時))
- control_blockフェーズの時
連鎖中はwinフェーズへ移行しない仕様になっている.これは一...
winフェーズはgameoverフェーズと全く同じなので説明は不要だ...
*** 実行 [#k14971a3]
これでどちらかがゲームオーバーになればゲームが終了するよ...
#media(PuyoPuyoChap31/PuyoPuyoChap31_2.flv)
ページ名: