ピボットブロックの細かいとこ †上るような回転 †ピボットブロックを回転させたとき,上に乗るような回転をするときがある. b p B B B --- pはピボット,bはピボット周囲のブロック,Bはステーブルブロックである. 上記の様な場合,現在の使用では右に回転させると以下のようになる. p b B B B ----- ピボットの右側にブロックがあるのでシフトが発生し,ピボットが左にずれて回転が行われる. しかし,実際のぷよぷよでは以下のようになる. p b B B B --- この仕様を実現するにはどうすればよいか? 答えはピボットの斜め上も空いているときはシフト無しに回転OKとするである. どういうことかというと,上の例では,ピボットの右にはブロックがあるが,右上にはブロックがない.この場合もシフト0のまま回転を許可してしまう. すると,ピボットの上のブロックが回転しようとしてステーブルブロックにめり込むが, 落下処理時のめり込み処理によってコントロールブロック全体が上に移動する. 結果として望みの状態となるわけである. class PivotControlBlock < ControlBlock def can_rotate?(ir, table, row_s) return false if ir == 0 # no rotate r = @pivot.row; l = @pivot.line max_cond = r < row_s - 1 min_cond = r > 0 @belongs.each.with_index do |block,i| next if !block || i % 2 != 0 row_dir = ir * (1 - i) if (row_dir > 0 ? max_cond : min_cond) && (!table[r+row_dir][l] || !table[r+row_dir][l+1]) # OK return {:dir => ir, :shift => 0} elsif (row_dir > 0 ? min_cond : max_cond) && !table[r-row_dir][l] # OK: shift return {:dir => ir, :shift => -row_dir} end # NG return false end return {:dir => ir, :shift => 0} end end マスが空いているかの条件に一つ上のマスもチェック対象になっている. 実行 †おお上った上った. Loading the player ...
狭いとこの回転 †両側がステーブルブロックで挟まれた状態では,現状の仕様では回転できない. しかしぷよぷよでは回転ボタンを二回押す度に180度ブロックが回転する. B b B B b B B B B p B B p B B p B B B =input=> B B =input=> B b B B B B B B B ----- ----- ----- これを満たすために次の機能を実装した.
class PivotControlBlock < ControlBlock def clear_turn_counter @turn_counter = 1 end def can_rotate?(ir, table, row_s) return false if ir == 0 # no rotate r = @pivot.row; l = @pivot.line max_cond = r < row_s - 1 min_cond = r > 0 @belongs.each.with_index do |block,i| next if !block || i % 2 != 0 row_dir = ir * (1 - i) if (row_dir > 0 ? max_cond : min_cond) && (!table[r+row_dir][l] || !table[r+row_dir][l+1]) # OK return {:dir => ir, :shift => 0} elsif (row_dir > 0 ? min_cond : max_cond) && !table[r-row_dir][l] # OK: shift return {:dir => ir, :shift => -row_dir} end # turn if @turn_counter == 0 clear_turn_counter return {:dir => ir, :shift => 0, :turn => true} end @turn_counter -= 1 # NG return false end return {:dir => ir, :shift => 0} end def rotate_turn(dir, time) @belongs.rotate!(2) @belongs.each.with_index do |block, i| next unless block # set animation to = 90 * (1 - i) block.set_rotate(to + 180 * dir, to, time, 0, 0) end end def rotate(rotate, time) if rotate[:turn] # turn rotate_turn(rotate[:dir], time) return end (略:以下以前の定義と同様) end end can_rotate?メソッドではターンを行う時のみハッシュに:turnというキーを追加している. そして,rotateメソッドでもし:turnが有効ならrotate_turnをセットしている. rotate_turnメソッドはまず通常のターンと同様に配列を循環させて配列上での位置を更新している. そして次に回転アニメーションをセットしているが,右回転の時と左回転の時で結果として同じ位置にくるがアニメーションは異なることに注意. 実行 †おお回った回った. Loading the player ...
|