对于一个允许角色跳跃的 2D 平台游戏,你几乎总是希望确保你的玩家角色**只能**在站在坚实地面上时跳跃。即使在允许流行的“二段跳”或“空中跳跃”的游戏中,几乎总是期望玩家站在坚实的基础上进行**初始**跳跃。
游戏开发者往往会以不同的方式处理这种情况。一种选择是检查角色的垂直速度是否足够低,以表明它在地面上——换句话说,如果角色没有向下坠落或已经向上移动(跳跃),则角色很可能站在坚实的地面上。另一种选择是在跳跃后使用一个短计时器并设置一个布尔标志,以便角色在返回地面之前无法再次跳跃。虽然这些都是有效的方法,但它们比必要的更复杂,它们可能不可靠,并且可能会引入其他跳跃处理问题。

一种更简洁、更可靠的方法——尽管它需要更多
因为此元素将被设置为**传感器**类型的对象,所以它不会与坚实地面发生物理交互,而只是与其重叠,当该重叠发生在地面对象上时,我们可以假设角色稳稳地站在坚实地面上并且可以安全地跳跃。
可选地,如图所示,该传感器的宽度可以比角色的整体身体宽度更窄,以防止在平台边缘摇摇欲坠时跳跃。但是,这以及您对传感器元素的宽度/相对于角色主体元素的位置做出的其他具体决定,在很大程度上取决于您独特的游戏设计。
地形可以通过多种方式构建。在本教程中,我们将简单地使用一个应用了静态物理实体的矢量矩形。我们还将向对象添加一个 objType 属性,值为 "ground" —— 这将允许我们仅限制玩家从坚实地面跳跃,而不是从其他水平物体(如液体池或尖刺坑)跳跃(显然,这些游戏元素需要单独且不同地处理)。
-- Set up physics engine
local physics = require( "physics" )
physics.start()
physics.setDrawMode( "hybrid" )
-- Create ground object
local cw, ch = display.actualContentWidth, display.actualContentHeight
local ground = display.newRect( display.contentCenterX, ch-64, cw, 64 )
ground:setFillColor( 0.4, 0.4, 0.8 )
ground.objType = "ground"
physics.addBody( ground, "static", { bounce=0.0, friction=0.3 } )
角色可以由**两个**身体元素构成,如下所示。请注意,第二个身体元素是一个传感器,它使用 box 形状方法声明,该方法允许我们将其从主体的中心点垂直偏移
-- Create character
local character = display.newRect( display.contentCenterX, ground.y-150, 80, 120 )
character:setFillColor( 1, 0.2, 0.4 )
physics.addBody( character, "dynamic",
{ density=1.0, bounce=0.0 }, -- Main body element
{ box={ halfWidth=30, halfHeight=10, x=0, y=60 }, isSensor=true } -- Foot sensor element
)
character.isFixedRotation = true
character.sensorOverlaps = 0
请注意,脚部传感器元素声明2 将在碰撞检测器函数中用于检查**传感器**
请注意,我们还向角色添加了一个 sensorOverlaps **计数器**来管理其跳跃能力。计数器true/false)true/false 布尔属性而不是计数器会导致意外行为,因为当传感器退出一个地面物体并更改为 false 时,即使物理上角色站在第二个地面物体上并且可以合法跳跃。因此,我们可以使用一个计数器,当传感器与一个或多个地面物体交互时,该计数器会递增和递减。
跳跃过程非常简单——当触摸最初注册时,我们只需检查 sensorOverlaps 计数器是否大于 0 并跳跃。为了简化本教程,我们使用全局 Runtime 触摸检测来触发跳跃,跳跃本身是在角色的线性 **y** 速度重置为 0 之后立即向上的基本线性脉冲。
local function touchAction( event )
if ( event.phase == "began" and character.sensorOverlaps > 0 ) then
-- Jump procedure here
local vx, vy = character:getLinearVelocity()
character:setLinearVelocity( vx, 0 )
character:applyLinearImpulse( nil, -75, character.x, character.y )
end
end
Runtime:addEventListener( "touch", touchAction )
最后一个方面是碰撞处理函数。这里,我们只需要检查以下内容
碰撞体元素索引 (event.selfElement) 为 2 —— 这表明**脚部传感器**已注册碰撞事件,而不是角色的主体元素。
地形元素是地面物体objType 为 "ground")
在此条件子句中,我们执行以下操作之一
在 "began" 阶段(脚部传感器已**进入**地面物体),我们**递增** sensorOverlaps 计数器。
在 "ended" 阶段(脚部传感器已**退出**地面物体),我们**递减** sensorOverlaps 计数器。
local function sensorCollide( self, event )
-- Confirm that the colliding elements are the foot sensor and a ground object
if ( event.selfElement == 2 and event.other.objType == "ground" ) then
-- Foot sensor has entered (overlapped) a ground object
if ( event.phase == "began" ) then
self.sensorOverlaps = self.sensorOverlaps + 1
-- Foot sensor has exited a ground object
elseif ( event.phase == "ended" ) then
self.sensorOverlaps = self.sensorOverlaps - 1
end
end
end
-- Associate collision handler function with character
character.collision = sensorCollide
character:addEventListener( "collision" )

现在,如果您运行此代码,您将看到脚部传感器与地面的重叠状态如何控制 character 是否可以跳跃。本质上,脚部传感器充当永久的“基础”,您可以使用它来测试角色是否站在坚实的地面上。
本教程中使用的方法只是处理“允许跳跃”问题的几种方法之一,绝不是每款游戏的**唯一**解决方案,甚至不是最佳解决方案。但是,希望这种简单的方法可以针对您的游戏进行调整和定制,让您可以放弃垂直速度检查、跳跃计时器和其他
本教程中的人物美术由 Kenney 提供。Kenney 游戏工作室通过创建免费游戏资产和高质量的学习资料来支持其他开发者。