移動と衝突
プレイ可能なシーンを作成します。
「移動と衝突」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。
位置と速度
LÖVE での移動とは、時間の経過に応じてオブジェクトの位置を変えることです。x と y を保存し、love.update で dt に応じた速度を加算します。
速度を1秒あたりの dx と dy として保持すると、斜め移動や物理演算をすっきり実装でき、フレームレートにも依存しなくなります。
function love.update(dt)
player.x = player.x + player.dx * dt
player.y = player.y + player.dy * dt
end入力による移動
ポーリングと速度を組み合わせて、オブジェクトの進行方向を操作します。love.update で方向キーを読み取り、速度に dt を掛けた値を適用します。
love.keyboard.isDown は毎フレーム確認されるため、キーを押している間、プレイヤーは滑らかに移動します。
function love.update(dt)
if love.keyboard.isDown('left') then player.x = player.x - player.speed*dt end
if love.keyboard.isDown('right') then player.x = player.x + player.speed*dt end
end斜め移動の速度を正規化する
方向キーを2つ同時に押すと、両方の軸に最大速度が加わるため、斜め移動が速くなります。これを修正するには、移動ベクトルを正規化します。
方向をその長さで割って大きさを 1 にし、その後で速度を掛けます。これで斜め移動と直線移動の速さが一致します。
local dx, dy = ix, iy
local len = math.sqrt(dx*dx + dy*dy)
if len > 0 then
player.x = player.x + (dx/len) * player.speed * dt
end画面内に収める
位置をクランプして、オブジェクトが画面内に収まるようにします。love.graphics.getWidth と getHeight でウィンドウサイズを取得し、座標の範囲を制限します。
math.max と math.min を組み合わせると、値を最小値と最大値の間にきれいに収められます。
local w = love.graphics.getWidth()
player.x = math.max(0, math.min(player.x, w - player.size))軸平行境界ボックス
最も単純な衝突判定には、軸平行境界ボックスを意味する AABB と呼ばれる長方形を使います。各オブジェクトは x、y、幅、高さを持ちます。
2つのボックスが水平方向と垂直方向の両方で同時に交差すると、重なっていることになります。この判定は高速で、ほとんどの2Dゲームには十分です。
-- box: { x, y, w, h }AABB の重なり判定
一方の長方形の左端が、どちらの軸でももう一方の右端を越えていない場合、2つの長方形は重なっています。一般的な判定では、4つの比較を組み合わせます。
4つすべてが true なら、ボックスは交差しています。この1つの条件が、2D衝突検出の中心的な処理になります。
function overlaps(a, b)
return a.x < b.x + b.w and
b.x < a.x + a.w and
a.y < b.y + b.h and
b.y < a.y + a.h
end衝突への対応
overlaps が true を返したら、何が起きるかを決めます。コインを拾う、ダメージを受ける、移動を止めるなどです。移動した後、love.update で衝突を確認します。
アイテムの場合は、単に削除するかスコアを増やします。通り抜けられない壁の場合は、プレイヤーを外側へ押し戻します。
function love.update(dt)
movePlayer(dt)
if overlaps(player, coin) then
score = score + 1
coin.dead = true
end
end円の衝突
円形のオブジェクトには、距離に基づく衝突判定のほうが正確です。中心間の距離が半径の合計より小さいとき、2つの円は衝突しています。
距離の2乗を比較すれば、コストの高い平方根計算を避けられます。これは多数のオブジェクトを確認するときによく使われる最適化です。
function circlesHit(a, b)
local dx, dy = a.x - b.x, a.y - b.y
local rsum = a.r + b.r
return dx*dx + dy*dy < rsum*rsum
end壁の衝突を解決する
プレイヤーを壁の位置で止める簡単な方法は、各軸を別々に移動し、重なりを発生させる移動を取り消すことです。
x を移動して確認し、衝突したら x を元に戻します。続けて y についても同じ処理を行います。この軸分離型の解決方法により、角で引っかかるのを防げます。
player.x = player.x + vx * dt
if overlaps(player, wall) then player.x = player.x - vx * dt end
player.y = player.y + vy * dt
if overlaps(player, wall) then player.y = player.y - vy * dt end重力を適用する
プラットフォーマーでは、一定の下向き加速度を追加します。毎フレーム、重力に dt を掛けた値を垂直速度に加え、その後で速度を位置に適用します。
プレイヤーが地面に着地したら、垂直速度を 0 にして落下を止めます。ジャンプでは、負の垂直速度を設定します。
function love.update(dt)
player.dy = player.dy + GRAVITY * dt
player.y = player.y + player.dy * dt
end消滅したオブジェクトを削除する
衝突の後には、オブジェクトを削除することがよくあります。リストを後ろから反復し、table.remove を呼び出すと、削除中もインデックスを有効に保てます。
後ろからの反復は、ループの途中で項目を削除する際に使う安全な Lua の慣用句です。前から反復したときに起きる、項目の読み飛ばしを防げます。
for i = #coins, 1, -1 do
if coins[i].dead then
table.remove(coins, i)
end
end理解度チェック
LÖVE の移動と衝突についての理解度を確認しましょう。
まとめ
移動は、位置、速度、dt を組み合わせて実装します。斜め移動を公平にするには正規化を使い、オブジェクトを画面内に保つにはクランプを使います。衝突判定は AABB の重なり判定から始め、円形のオブジェクトには円間の距離による判定を使います。
壁との衝突は軸ごとの移動を元に戻して解決し、プラットフォーマーには重力を追加します。不要になったオブジェクトは、table.remove と後ろからの反復で削除します。
よくある質問
「移動と衝突」レッスンは無料ですか?
はい。「移動と衝突」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「移動と衝突」で何を学びますか?
プレイ可能なシーンを作成します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「移動と衝突」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。