移动与碰撞
创建可玩的场景。
移动与碰撞 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。
位置与速度
在 LÖVE 中,移动意味着随时间改变对象的位置。请保存 x 和 y,然后在 love.update 中将按 dt 缩放后的速度加到位置上。
将速度表示为每秒的 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规范化对角线速度
同时按下两个方向键会让对角线移动更快,因为两个轴都会加上完整速度。要解决这个问题,请将移动向量规范化。
将方向除以其长度,使其大小为 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、宽度和高度。
当两个盒子同时在水平轴和垂直轴上相交时,它们就会重叠。这种检查速度快,足以满足大多数二维游戏的需求。
-- box: { x, y, w, h }AABB 重叠测试
当两个矩形在任一轴上都没有彼此完全分离时,它们就会重叠。经典测试会组合四个比较条件。
如果这四个条件都成立,两个盒子就相交了。这个单一条件是二维碰撞检测的核心。
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圆形碰撞
对于圆形对象,基于距离的碰撞检测更加准确。当两个圆心之间的距离小于它们半径之和时,两个圆就会发生碰撞。
比较距离的平方可以避免代价较高的平方根运算。在检查大量对象时,这是一种常见的优化方法。
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 后加到垂直速度上,然后根据速度更新位置。
玩家落地时,将垂直速度清零,使其停止下落。跳跃时则将垂直速度设为负值。
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 移除失效对象。
常见问题解答
「移动与碰撞」课时是免费的吗?
是的 — 「移动与碰撞」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。
「移动与碰撞」这节课中我会学到什么?
创建可玩的场景。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Lua Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「移动与碰撞」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Lua Academy 课中编写并运行代码吗?
能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。