Pico8 Lua平台游戏开发:未修改x却出现p.x为nil错误?
问题描述
我正在使用Pico8学习Lua,开发一款平台跳跃游戏。添加重力功能后,当角色精灵与地图物品碰撞时,触发如下运行时错误:
Runtime Error line 19 tab 0
local x1=p.x/8
Attempt to perform arithmetic on field 'x' (a nil value)
我疑惑的是,并未在重力函数中修改x值,但p.x却变为nil。我尝试过临时修复代码,但想明确问题的根源。
我的代码
function _init() plr = { x=63, y=63, lx=63, ly=63, yv=1, spe=1, f=false } grav = 0.02 end -- collision function -- function collision(p) -- point calculations local x1=p.x/8 local y1=p.y/8 local x2=(p.x+7)/8 local y2=(p.y+7)/8 -- collison checks, flag 0 local a=fget(mget(x1, y1),0) local b=fget(mget(x1, y2),0) local c=fget(mget(x2, y1),0) local d=fget(mget(x2, y2),0) if a or b or c or d then return true else return false end end -- gravity function -- function gravity(p) p.ly=p.y p.yv+=grav for i = 0, flr(p.yv) do if not collision(p) then p.y += 1 else p.y = p.ly end end end -- move function -- function move(p) p.lx=flr(p.x) p.ly=flr(p.y) -- controller -- if btn(➡️) then p.x+=p.spe p.f=true end if btn(⬅️) then p.x-=p.spe p.f=false end if btn(⬆️) then p.y-=p.spe end gravity(p) -- collision -- if collision(p) then p.x=lx p.y=ly end end function _update() move(plr) end function _draw() cls() map() --player draw-- spr(1, plr.x, plr.y, 1,1, plr.f) end
临时修复代码(能阻止错误但不知根源)
if p.x == nil then p.x=p.lx elseif p.y == nil then p.y=p.lx end
问题根源与解决方案
核心原因
p.x变为nil的直接原因是**move函数里的碰撞处理代码写错了变量名**:
-- collision -- if collision(p) then p.x=lx p.y=ly end
这里的lx和ly是未定义的全局变量,Lua中未定义的全局变量默认值为nil。你把p.x直接赋值成了nil,后续调用collision函数时,自然会触发“对nil值执行算术运算”的错误。
另外这段逻辑本身也存在问题:你在调用gravity后直接检测碰撞并重置坐标到lx/ly,但lx/ly是移动前的初始坐标,会导致玩家的移动和重力效果被完全覆盖,完全无法正常移动。
修复方案
1. 修正变量名错误
把lx改成p.lx,ly改成p.ly,确保引用的是玩家对象中存储的上一帧坐标:
if collision(p) then p.x = p.lx p.y = p.ly end
2. 优化碰撞逻辑(可选但推荐)
当前的碰撞处理会同时重置X和Y轴坐标,导致移动和重力的效果互相干扰。建议拆分X轴和Y轴的碰撞检测,分步处理:
function move(p) p.lx = flr(p.x) p.ly = flr(p.y) -- 先处理X轴移动与碰撞 if btn(➡️) then p.x += p.spe p.f = true end if btn(⬅️) then p.x -= p.spe p.f = false end -- X轴碰撞回退 if collision(p) then p.x = p.lx end -- 处理Y轴跳跃 if btn(⬆️) then p.y -= p.spe end -- 应用重力 gravity(p) -- Y轴碰撞回退(如果需要单独处理) -- if collision(p) then -- p.y = p.ly -- end end
3. 修正临时修复代码的小错误
你的临时修复里把p.y赋值成了p.lx,这是笔误,应该改成p.ly:
if p.x == nil then p.x = p.lx elseif p.y == nil then p.y = p.ly end
内容的提问来源于stack exchange,提问作者Yalc06
相关产品推荐
相关产品推荐

