允许跳跃

对于一个允许角色跳跃的 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 )

碰撞处理程序

最后一个方面是碰撞处理函数。这里,我们只需要检查以下内容

  1. 碰撞体元素索引 (event.selfElement) 为 2 —— 这表明**脚部传感器**已注册碰撞事件,而不是角色的主体元素。

  2. 地形元素是地面物体objType"ground",在这种情况下,角色可以安全地跳离它。

在此条件子句中,我们执行以下操作之一

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 游戏工作室通过创建免费游戏资产和高质量的学习资料来支持其他开发者。