ガタガタする †ここで少し気になった部分があった. サイクルブロックだが,回転するときにガタガタするときがある. それは以下のような場合である. b1 b2 b0 b3 B0 ----- 上記の様な状態で右に回転させると, rowはすぐに反映され,lineはアニメーションに基づいて決定される. よって回転操作直後は一時的に以下のようなブロックの配置になる. [ ] b1/b2
b0/b3 [ ]
B0
-----------
このため,コントロールブロックが1ブロック分だけ落下できる事になり,数フレーム下がる. その後,回転アニメーションが進み,回転後の配置になるためめり込み修正が入り, コントロールブロックが上昇する. この現象によって回転時にガタガタしてしまう. これを回避するために,サイクルブロックについて落下可能判定時にある種のバウンディングボックスを考える. すなわち,サイクルブロックは常にブロック4個分の正方形からなるコントロールブロックなので,ブロック1個単位のあたり判定で落下可能か判断するのではなく, 最も下にあるブロックのlineをコントロールブロック全体のあたり判定として判定する. そんじゃまあ実装しましょう. class CycleControlBlock < ControlBlock
def can_falldown?(table, block_s)
min_y = [@blocks[0], @blocks[3]].min_by{|block|
block.draw_pos[1]
}.draw_pos[1]
row = @blocks[0].row
fall_ys = [row, row + 1].map{|row|
min_y >= 0 ? min_y - table[row].size * block_s : min_y
}
# fall_ys == 0 : can not fall
# > 0 : fall y
# < 0 : dent y
return fall_ys.min
end
end
サイクルブロックの下にあるのはb0とb3なのでそいつらだけを取り出し,小さい方のy座標を取得する*1. そしたらそれを基準にしてコントロールブロックの左側と右側両方のfall_ysを取得し,小さい方を返す*2. あとは横移動に関しても同様にバウンディングボックスの概念をもちいて改造. class CycleControlBlock < ControlBlock
def can_move_row?(imr, table, row_s)
return false if imr == 0 # no move
min_line = [@blocks[0], @blocks[3]].min_by{|block|
block.draw_pos[1]
}.line
row_left = @blocks[0].row; row_right = @blocks[3].row
[min_line, min_line + 1].each do |line|
if imr > 0 # move right
return false if row_right >= row_s - 1
return false if table[row_right + 1][line]
else # move left
return false if row_left <= 0
return false if table[row_left - 1][line]
end
end
return true
end
end
一番下のlineを元にバウンディングボックスを作る. rowは特に問題ないので,左右で決め打ちできる. 実行 †おおガタガタしない. Loading the player ...
|