2Dキャラクターと壁ブロックの衝突判定&押し返しのロジックを考える
前提
キャラクターは8方向(平面上の任意方向)に移動できるとする。
キャラクターは
壁ブロックはグリッド上に配置されているとする。
壁ブロックのサイズはグリッドの大きさに等しいとする。
基本プログラム
code:lua
version 42
__lua__
GRID_SIZE = 8
MAP_WALL_ID = 3
function _init()
x = GRID_SIZE * 8
y = GRID_SIZE * 8
end
function wallcheck(x, y, dx, dy)
local mapx = (x + dx) \ 8
local mapy = (y + dy) \ 8
if mget(mapx, mapy) == MAP_WALL_ID then
dx = 0
dy = 0
end
return dx, dy
end
function _update()
local dx = 0
local dy = 0
if btn(0) then dx = -1 * GRID_SIZE end
if btn(1) then dx = 1 * GRID_SIZE end
if btn(2) then dy = -1 * GRID_SIZE end
if btn(3) then dy = 1 * GRID_SIZE end
local ndx, ndy = wallcheck(x, y, dx, dy)
x += ndx
y += ndy
end
function _draw()
cls()
map(0, 0, 0, 0, 16, 16)
print("x:" .. x, 0, 0, 0)
print("y:" .. y, 0, 8, 0)
spr(1, x, y)
end
__gfx__
00000000000880009aaaaaaa66666666000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000088000aaa9aaaa6dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0070070000888800aaaaaa9a6dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0007700008088080aa9aaaaa6dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0007700008088080aaaaaaaa6dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0070070000088000aaaaa9aa6dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000800800aaaaaaa96dddddd5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000800800a9aaaaaa65555555000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
0303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020202020202020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020202020202020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020303020203020302030302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020302020203020202020302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202030202020203020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020302020302020302020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020202020202030302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020303020202020202020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020302020302020302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202030202020203020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020302020202030202020302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020303020302030202030302020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020202020202020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0302020202020202020202020202020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
キャラクターの位置が常にグリッド上にあり、移動量がグリッドサイズと等しい場合
プレイヤーが移動したい先の位置の壁の存在を調べる。
壁が存在しなければ、移動できる。
壁が存在すれば、移動できない。(移動量をゼロにする)
code:lua
function wallcheck(x, y, dx, dy)
local mapx = (x + dx) \ 8
local mapy = (y + dy) \ 8
if mget(mapx, mapy) == MAP_WALL_ID then
dx = 0
dy = 0
end
return dx, dy
end
function _update()
local dx = 0
local dy = 0
if btn(0) then dx = -1 * GRID_SIZE end
if btn(1) then dx = 1 * GRID_SIZE end
if btn(2) then dy = -1 * GRID_SIZE end
if btn(3) then dy = 1 * GRID_SIZE end
local ndx, ndy = wallcheck(x, y, dx, dy)
x += ndx
y += ndy
end
移動量が可変(ただしブロックサイズを超えない)場合
移動先座標のブロックを調べてブロックがあった場合の処理が「移動しない」だけでは不十分。ブロックに接触しない状態で止まってしまう可能性があるからである。人<- すきま ->■
処理としては、移動先の座標が壁の中であった場合、「壁に接触する位置」までキャラクター座標を押し戻す(見かけ上は「壁際で止まる」)必要がある。
移動量がブロックサイズを超えるかもしれない場合]
一度の移動で壁ブロックを飛び越え(すり抜け)てしまう可能性がある。この場合、キャラクターの移動前と移動後の線上にブロックが存在したかのチェックが必要になる。