You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:07:54