Love2d中角色重力与爬梯子功能冲突问题求助
问题描述
我正在为开发的游戏实现角色非爬梯状态下的重力效果,但每次添加该功能时,爬梯子功能就会出现异常;修复爬梯问题后,重力效果又失效,陷入循环。我尝试过直接操作x/y坐标、使用dx/dy变量,甚至求助ChatGPT都无法解决,无报错信息,属于逻辑bug。我的代码如下:
-- Initialize the game function love.load() -- Set the window dimensions love.window.setMode(800, 600) -- Set the title of the window love.window.setTitle("Mappy") -- Load the game assets characterImage = love.graphics.newImage("mappy.png") itemImage = love.graphics.newImage("item.png") enemyImage = love.graphics.newImage("enemy.png") -- Check if the image files loaded successfully if not characterImage or not itemImage or not enemyImage then error("Failed to load game assets. Make sure the image files exist and are accessible.") end -- Set the character's initial position characterX = 400 characterY = love.graphics.getHeight() - 180 -- Set the item's initial position itemX = 100 itemY = 100 -- Set the enemy's initial position enemyX = 700 enemyY = 500 -- Create a map map = { "#################################", "# #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "#################################", } -- Set the tile size tileSize = 32 -- Set up the camera camera = { x = 0, y = 0 } -- Set initial ladder interaction state touchingLadder = false end -- Update the game state function love.update(dt) -- Move the character based on user input local dx, dy = 0, 0 if love.keyboard.isDown("up") and touchingLadder then dy = -200 end if love.keyboard.isDown("down") and touchingLadder then dy = 200 end if love.keyboard.isDown("left") then dx = -200 end if love.keyboard.isDown("right") then dx = 200 end -- Check for collision with walls local wallCollision = checkWallCollision(characterX + dx * dt, characterY + dy * dt, characterImage:getWidth(), characterImage:getHeight()) -- Move the character only if there is no collision with walls if not wallCollision then characterX = characterX + dx * dt characterY = characterY + dy * dt end -- Update the camera position to follow the character camera.x = characterX - love.graphics.getWidth() / 2 camera.y = characterY - love.graphics.getHeight() / 2 -- Check for collision between character and item if checkCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight(), itemX, itemY, itemImage:getWidth(), itemImage:getHeight()) then -- Respawn the item at a new random position itemX = love.math.random(100, 700) itemY = love.math.random(100, 500) end -- Check for collision between character and enemy if checkCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight(), enemyX, enemyY, enemyImage:getWidth(), enemyImage:getHeight()) then -- Game over love.event.quit() end -- Update ladder interaction state touchingLadder = checkLadderCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight()) end -- Draw the game state function love.draw() -- Set the drawing transformation based on the camera position love.graphics.push() love.graphics.translate(-camera.x, -camera.y) -- Draw the map for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "#" then love.graphics.rectangle("fill", (x - 1) * tileSize, (y - 1) * tileSize, tileSize, tileSize) elseif char == "^" then love.graphics.rectangle("line", (x - 1) * tileSize, (y - 1) * tileSize, tileSize, tileSize) end end end -- Draw the character love.graphics.draw(characterImage, characterX, characterY) -- Draw the item love.graphics.draw(itemImage, itemX, itemY) -- Draw the enemy love.graphics.draw(enemyImage, enemyX, enemyY) -- Reset the drawing transformation love.graphics.pop() end -- Check collision between two rectangles function checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) return x1 < x2 + w2 and x2 < x1 + w1 and y1 < y2 + h2 and y2 < y1 + h1 end -- Check collision with walls function checkWallCollision(x, y, width, height) -- Calculate the character's bounding box local characterLeft = x local characterRight = x + width local characterTop = y local characterBottom = y + height -- Check for collision with walls for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "#" then local wallLeft = (x - 1) * tileSize local wallRight = x * tileSize local wallTop = (y - 1) * tileSize local wallBottom = y * tileSize -- Check if the character's bounding box intersects with the wall if characterRight > wallLeft and characterLeft < wallRight and characterBottom > wallTop and characterTop < wallBottom then return true end end end end return false end -- Check collision with ladders function checkLadderCollision(x, y, width, height) -- Calculate the character's bounding box local characterLeft = x local characterRight = x + width local characterTop = y local characterBottom = y + height -- Check for collision with ladders for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "^" then local ladderLeft = (x - 1) * tileSize local ladderRight = x * tileSize local ladderTop = (y - 1) * tileSize local ladderBottom = y * tileSize -- Check if the character's bounding box intersects with the ladder if characterRight > ladderLeft and characterLeft < ladderRight and characterBottom > ladderTop and characterTop < ladderBottom then return true end end end end return false end
解决方案
核心问题是重力与爬梯逻辑未做互斥处理——当角色接触梯子时,重力会强制下拉角色,干扰爬梯操作;而如果为了修复爬梯禁用重力,又会导致非爬梯状态下重力失效。以下是修复后的完整代码及关键改动说明:
修改后的完整代码
-- Initialize the game function love.load() -- Set the window dimensions love.window.setMode(800, 600) -- Set the title of the window love.window.setTitle("Mappy") -- Load the game assets characterImage = love.graphics.newImage("mappy.png") itemImage = love.graphics.newImage("item.png") enemyImage = love.graphics.newImage("enemy.png") -- Check if the image files loaded successfully if not characterImage or not itemImage or not enemyImage then error("Failed to load game assets. Make sure the image files exist and are accessible.") end -- Set the character's initial position characterX = 400 characterY = love.graphics.getHeight() - 180 -- Set the item's initial position itemX = 100 itemY = 100 -- Set the enemy's initial position enemyX = 700 enemyY = 500 -- Create a map map = { "#################################", "# #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "# ##### ^ ######### ^ ##### #", "# ^ ^ #", "# ^ ^ #", "#################################", } -- Set the tile size tileSize = 32 -- Set up the camera camera = { x = 0, y = 0 } -- Set initial ladder interaction state touchingLadder = false -- 新增重力参数,可根据游戏手感调整 gravity = 500 end -- Update the game state function love.update(dt) -- 提前更新梯子接触状态,确保当前帧逻辑使用最新状态 touchingLadder = checkLadderCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight()) -- Move the character based on user input local dx, dy = 0, 0 if love.keyboard.isDown("up") and touchingLadder then dy = -200 elseif love.keyboard.isDown("down") and touchingLadder then dy = 200 else -- 非爬梯状态下应用重力 dy = gravity end if love.keyboard.isDown("left") then dx = -200 end if love.keyboard.isDown("right") then dx = 200 end -- 分别处理水平和垂直方向的碰撞,避免互相干扰 -- 先处理水平移动碰撞 local horizontalCollision = checkWallCollision(characterX + dx * dt, characterY, characterImage:getWidth(), characterImage:getHeight()) if not horizontalCollision then characterX = characterX + dx * dt end -- 再处理垂直移动碰撞(包含重力和爬梯移动) local verticalCollision = checkWallCollision(characterX, characterY + dy * dt, characterImage:getWidth(), characterImage:getHeight()) if not verticalCollision then characterY = characterY + dy * dt end -- Update the camera position to follow the character camera.x = characterX - love.graphics.getWidth() / 2 camera.y = characterY - love.graphics.getHeight() / 2 -- Check for collision between character and item if checkCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight(), itemX, itemY, itemImage:getWidth(), itemImage:getHeight()) then -- Respawn the item at a new random position itemX = love.math.random(100, 700) itemY = love.math.random(100, 500) end -- Check for collision between character and enemy if checkCollision(characterX, characterY, characterImage:getWidth(), characterImage:getHeight(), enemyX, enemyY, enemyImage:getWidth(), enemyImage:getHeight()) then -- Game over love.event.quit() end end -- Draw the game state function love.draw() -- Set the drawing transformation based on the camera position love.graphics.push() love.graphics.translate(-camera.x, -camera.y) -- Draw the map for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "#" then love.graphics.rectangle("fill", (x - 1) * tileSize, (y - 1) * tileSize, tileSize, tileSize) elseif char == "^" then love.graphics.rectangle("line", (x - 1) * tileSize, (y - 1) * tileSize, tileSize, tileSize) end end end -- Draw the character love.graphics.draw(characterImage, characterX, characterY) -- Draw the item love.graphics.draw(itemImage, itemX, itemY) -- Draw the enemy love.graphics.draw(enemyImage, enemyX, enemyY) -- Reset the drawing transformation love.graphics.pop() end -- Check collision between two rectangles function checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) return x1 < x2 + w2 and x2 < x1 + w1 and y1 < y2 + h2 and y2 < y1 + h1 end -- Check collision with walls function checkWallCollision(x, y, width, height) -- Calculate the character's bounding box local characterLeft = x local characterRight = x + width local characterTop = y local characterBottom = y + height -- Check for collision with walls for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "#" then local wallLeft = (x - 1) * tileSize local wallRight = x * tileSize local wallTop = (y - 1) * tileSize local wallBottom = y * tileSize -- Check if the character's bounding box intersects with the wall if characterRight > wallLeft and characterLeft < wallRight and characterBottom > wallTop and characterTop < wallBottom then return true end end end end return false end -- Check collision with ladders function checkLadderCollision(x, y, width, height) -- Calculate the character's bounding box local characterLeft = x local characterRight = x + width local characterTop = y local characterBottom = y + height -- Check for collision with ladders for y = 1, #map do local row = map[y] for x = 1, #row do local char = row:sub(x, x) if char == "^" then local ladderLeft = (x - 1) * tileSize local ladderRight = x * tileSize local ladderTop = (y - 1) * tileSize local ladderBottom = y * tileSize -- Check if the character's bounding box intersects with the ladder if characterRight > ladderLeft and characterLeft < ladderRight and characterBottom > ladderTop and characterTop < ladderBottom then return true end end end end return false end
关键改动说明
- 新增重力参数:在
love.load中添加gravity = 500,统一管理重力加速度,方便调整手感。 - 提前更新梯子状态:将
touchingLadder = checkLadderCollision(...)移到love.update开头,确保当前帧的移动逻辑使用最新的梯子接触状态,避免状态滞后导致的逻辑错误。 - 互斥处理重力与爬梯:在垂直移动逻辑中,使用
else分支确保只有未接触梯子且未按下爬梯方向键时,才应用重力;爬梯时完全禁用重力,避免两者互相干扰。 - 拆分碰撞检测:将水平和垂直方向的碰撞检测分开处理,避免水平移动的碰撞影响垂直方向的重力/爬梯移动,提升碰撞逻辑的稳定性。
内容的提问来源于stack exchange,提问作者TriggerFox Games
相关产品推荐
相关产品推荐

