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

Lua复刻吃豆人固定瓦片移动故障修复求助

Hey there! Let's tackle those frustrating movement bugs in your Mrs. Pac-Man Lua remake. I’ve gone through your code and pinpointed a few key issues causing the reverse freeze and wall-clipping/position glitches. Let's break down the problems and fix them step by step.

Key Issues in Your Current Code
  1. 1-based vs 0-based Map Indexing: Lua uses 1-indexed arrays, but your Pac-Man coordinates are likely 0-based (matching the nodemap layout). This means accessing nodemap[mrspacman.y - ...][mrspacman.x + ...] can lead to invalid indices (like 0), which Lua treats as nil—breaking your collision checks and allowing wall-clipping.
  2. No Instant Reverse Handling: In classic Pac-Man, players can reverse direction immediately, even if not centered on a tile. Your current code only allows direction changes at tile centers, causing the freeze when pressing reverse mid-move.
  3. Precision Problems with Tile Center Checks: Using math.floor(mrspacman.x*10)/10 introduces floating-point precision errors. Values that should be exact integers (like 1.0) might become 0.999999999, making your tile center check fail and locking Pac-Man in a moving state.
  4. Unchecked Mid-Tile Movement: When moving between tiles, you don't check if the next tile is a wall—this lets Pac-Man clip through walls when changing angles.
Fixes to Implement

1. Fix Map Indexing

Convert your 0-based player coordinates to 1-based when accessing the nodemap to avoid invalid indices:

-- When checking a target tile, add 1 to x/y to match Lua's 1-indexed arrays
local targetTileY = math.floor(mrspacman.y - math2.sin(targetDir)) + 1
local targetTileX = math.floor(mrspacman.x + math2.cos(targetDir)) + 1
if nodemap[targetTileY][targetTileX] ~= 1 then
  -- Tile is walkable
end

2. Allow Instant Reverse Direction

Add a check for reverse direction presses—let Pac-Man flip immediately without waiting for a tile center:

if mrspacman.nextDirection then
  local targetDir = mrspacman.nextDirection
  -- Check if the queued direction is exactly opposite to current
  local isReverse = math.abs(targetDir - mrspacman.dz) == 180

  if isReverse then
    -- Instantly switch to reverse
    mrspacman.dz = targetDir
    mrspacman.nextDirection = false
  else
    -- Original logic: only switch non-reverse directions at tile centers
    local epsilon = 0.01
    local isAtCenter = (math.abs(mrspacman.x - math.floor(mrspacman.x)) < epsilon) and 
                       (math.abs(mrspacman.y - math.floor(mrspacman.y)) < epsilon)
    
    if isAtCenter then
      local targetTileY = math.floor(mrspacman.y - math2.sin(targetDir)) + 1
      local targetTileX = math.floor(mrspacman.x + math2.cos(targetDir)) + 1
      if nodemap[targetTileY][targetTileX] ~= 1 then
        mrspacman.dz = targetDir
        mrspacman.nextDirection = false
      end
    end
  end
end

3. Improve Tile Center Precision

Replace exact equality checks with a small "epsilon" value to account for floating-point errors:

local epsilon = 0.01 -- Adjust based on your speed (0.1 works here)
local isAtTileCenter = (math.abs(mrspacman.x - math.floor(mrspacman.x)) < epsilon) and 
                       (math.abs(mrspacman.y - math.floor(mrspacman.y)) < epsilon)

This avoids missing tile center checks due to tiny precision gaps.

4. Block Mid-Tile Wall Clipping

Check if the next tile is walkable before moving into it, even mid-tile:

if not isAtTileCenter then
  local nextX = mrspacman.x + (math2.cos(mrspacman.dz)*mrspacman.speed)
  local nextY = mrspacman.y - (math2.sin(mrspacman.dz)*mrspacman.speed)

  local currentTileX = math.floor(mrspacman.x)
  local currentTileY = math.floor(mrspacman.y)
  local nextTileX = math.floor(nextX)
  local nextTileY = math.floor(nextY)

  -- If we're entering a new tile, check if it's a wall
  if nextTileX ~= currentTileX or nextTileY ~= currentTileY then
    if nodemap[nextTileY + 1][nextTileX + 1] == 1 then
      -- Hit a wall: snap back to current tile center
      mrspacman.x = currentTileX
      mrspacman.y = currentTileY
      return -- Skip this movement step
    end
  end

  -- Safe to move
  mrspacman.x = nextX
  mrspacman.y = nextY
end
Full Fixed Movement Code

Here’s the combined, updated code incorporating all fixes:

-- Helper: Check if Pac-Man is at a tile center (with precision tolerance)
local epsilon = 0.01
local isAtTileCenter = (math.abs(mrspacman.x - math.floor(mrspacman.x)) < epsilon) and 
                       (math.abs(mrspacman.y - math.floor(mrspacman.y)) < epsilon)

-- Handle queued direction changes
if mrspacman.nextDirection then
  local targetDir = mrspacman.nextDirection
  local isReverse = math.abs(targetDir - mrspacman.dz) == 180

  if isReverse then
    -- Instant reverse direction
    mrspacman.dz = targetDir
    mrspacman.nextDirection = false
  else
    -- Only switch non-reverse directions at tile centers
    if isAtTileCenter then
      local targetTileY = math.floor(mrspacman.y - math2.sin(targetDir)) + 1
      local targetTileX = math.floor(mrspacman.x + math2.cos(targetDir)) + 1
      if nodemap[targetTileY][targetTileX] ~= 1 then
        mrspacman.dz = targetDir
        mrspacman.nextDirection = false
      end
    end
  end
end

-- Handle movement
if isAtTileCenter then
  -- Check if forward tile is walkable before moving
  local targetTileY = math.floor(mrspacman.y - math2.sin(mrspacman.dz)) + 1
  local targetTileX = math.floor(mrspacman.x + math2.cos(mrspacman.dz)) + 1
  if nodemap[targetTileY][targetTileX] ~= 1 then
    mrspacman.x = mrspacman.x + (math2.cos(mrspacman.dz)*mrspacman.speed)
    mrspacman.y = mrspacman.y - (math2.sin(mrspacman.dz)*mrspacman.speed)
  end
else
  -- Calculate next position
  local nextX = mrspacman.x + (math2.cos(mrspacman.dz)*mrspacman.speed)
  local nextY = mrspacman.y - (math2.sin(mrspacman.dz)*mrspacman.speed)

  local currentTileX = math.floor(mrspacman.x)
  local currentTileY = math.floor(mrspacman.y)
  local nextTileX = math.floor(nextX)
  local nextTileY = math.floor(nextY)

  -- Check if entering a new wall tile
  if nextTileX ~= currentTileX or nextTileY ~= currentTileY then
    if nodemap[nextTileY + 1][nextTileX + 1] == 1 then
      -- Snap to current tile center and stop
      mrspacman.x = currentTileX
      mrspacman.y = currentTileY
    else
      -- Move to next position
      mrspacman.x = nextX
      mrspacman.y = nextY
    end
  else
    -- Stay in current tile, continue moving
    mrspacman.x = nextX
    mrspacman.y = nextY
  end
end
Quick Notes to Verify
  • Make sure your mrspacman.nextDirection is set correctly (e.g., left = 180°, right = 0°, up = 90°, down = 270°) to match your math2 table.
  • Remove the math.floor(mrspacman.x*10)/10 lines—they’re causing unnecessary precision loss. Let Pac-Man’s coordinates stay as raw floats, using the epsilon check instead.

内容的提问来源于stack exchange,提问作者crazicrafter1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:07:37