本教程涵盖了 Corona 物理引擎的一个重要主题,特别是涉及
首先,我们应该定义什么是
对于物理引擎老手来说,这是老生常谈,但基本上,在 Box2D 中,所有
这对于可以用标准凸多边形定义的刚体来说是可以的,但是对于不能仅用凸角描绘或不能用八条边或更少边精确表示的刚体呢?
解决方案是
如果您以前使用过
多元素刚体具有一些独特的功能,可以帮助您克服各种设计障碍,包括:
各个元素可以具有独特的碰撞过滤器。如果您希望
各个元素可以设置为传感器,允许所有其他对象穿过它们,同时仍然返回碰撞检测事件(此方法在允许跳跃教程中使用)。
在碰撞中,每个元素可以返回一个整数,该整数与其在1
,第二个元素返回 2
,依此类推。这允许您精确定位
一旦为元素或刚体声明了碰撞过滤器,则在运行时无法更改它。
刚体。
虽然敌人可能由几个单独的不同刚体构成,然后使用焊接关节组装,但这会在敌人组装中产生另一个级别的复杂性,并且可能导致某种程度的物理不稳定性,即使使用焊接关节也固有这种不稳定性。
如上所述,
刚体的各个元素可以最初设置为传感器(或不设置为传感器),但在创建它之后,在刚体上使用object.isSensor时,它是
逐元素
刚体。本质上,方法如下:
armorStates
表来跟踪每个盔甲对象的“状态”。这将用于确定特定元素是-- Set up physics engine local physics = require( "physics" ) physics.start() physics.setDrawMode( "normal" ) physics.setGravity( 0,0 ) local armoredSkeleton = display.newImageRect( "skeleton.png", 200, 256 ) armoredSkeleton.x, armoredSkeleton.y = display.contentCenterX, display.contentCenterY local armorPieces = { helmet = { -38,-103,-26,-118,-15,-120,-4,-118,8,-103,8,-63,-38,-63 }, mantle = { -68,-55,-52,-63,20,-63,37,-55,47,-44,55,-20,-89,-20,-80,-44 }, chest = { 44,-44,54,54,-85,54,-76,-44 }, shield = { 88,-10,98,13,86,65,98,42,66,80,41,86,41,-33,66,-28 }, faulds = { 48,54,53,80,-87,80,-85,54 }, legLeft = { -34,80,-34,127,-72,127,-72,80 }, legRight = { 43,80,43,127,5,127,5,80 } } physics.addBody( armoredSkeleton, "dynamic", { shape = armorPieces["helmet"] }, { shape = armorPieces["mantle"] }, { shape = armorPieces["chest"] }, { shape = armorPieces["shield"] }, { shape = armorPieces["faulds"] }, { shape = armorPieces["legLeft"] }, { shape = armorPieces["legRight"] } ) local armorStates = { true, true, true, true, true, true, true }
开启还是关闭 —true
。"hybrid"
(第 4 行)并运行此代码,则骨架将类似于此处的图像。请注意,某些盔甲块与其他盔甲块重叠 — 在这种情况下,这是完全可以接受的,因为玩家仍然需要
逐个
应注意刚体元素的声明顺序
接下来,我们将声明基本的碰撞前监听器。如果我们打算利用物理接触,则必须使用这种类型的监听器,因为我们将告诉 Corona 在碰撞发生之前立即管理碰撞状态,而不是在碰撞发生时管理碰撞状态。
local function skeletonHit( self, event ) print( event.selfElement ) end armoredSkeleton.preCollision = skeletonHit armoredSkeleton:addEventListener( "preCollision" )
此函数只完成基本操作。与骨架碰撞的任何物体都将返回特定刚体元素的相应整数作为 event.selfElement
,根据它们的声明顺序。因此,因为我们将头盔声明为第一个元素,所以涉及头盔的碰撞将返回 1
。与披风的碰撞将返回 2
,与胸甲的碰撞将返回 3
,依此类推。
此时,skeletonHit()
函数将告诉我们哪个特定的盔甲块参与了碰撞,但仅此而已。这没有达到我们的目标,所以让我们扩展它以访问 armorStates
表并确定是否应该发生碰撞。
local function skeletonHit( self, event ) -- Dictate the collision behavior based on the armor element state if ( armorStates[event.selfElement] == false ) then -- Use physics contact to void collision event.contact.isEnabled = false else -- Set the associated armor element state to "destroyed" armorStates[event.selfElement] = false end end armoredSkeleton.preCollision = skeletonHit armoredSkeleton:addEventListener( "preCollision" )
基本上,如果在我们的游戏逻辑中盔甲元素被“摧毁”(第 35 行),我们可以使用物理接触 (event.contact
) 指示 Corona 完全避免碰撞,使其看起来好像该元素根本不存在(我们的最终目的)。相反,如果盔甲元素仍然完好无损,我们允许碰撞自然发生,但我们通过将其在 armorStates
表中的索引设置为 false
来将其状态切换为“被摧毁” — 这将确保盔甲元素在下次碰撞事件中不会引起物理响应。
基本上就是这样!使用此代码,可以将每个盔甲块从活动状态切换到非活动状态,从而让您在
如果您真的想发挥创意,可以考虑将此概念扩展到
一种方法是为 armorStates
表中的每个盔甲块使用整数生命值true
/false
)
local armorStates = { 10, 5, 20, 15, 8, 5, 5 }
接下来,调整 skeletonHit()
函数以处理整数而不是布尔值 true
/false
值。
local function skeletonHit( self, event ) -- Dictate the collision behavior based on the armor element state if ( armorStates[event.selfElement] == 0 ) then -- Use physics contact to void collision event.contact.isEnabled = false else -- Subtract 1 from the armor piece's health value armorStates[event.selfElement] = armorStates[event.selfElement] - 1 end end
本质上,在第 35 行,我们不再检查值是否为 false
,而是检查值是否为0
—1
,而不是像原始版本那样将其设置为 false
。
另一种创造性的选择是检测骨骼盔甲上的碰撞**力**,根据抛射物撞击盔甲部件的力度/速度来造成更多伤害。这种方法在碰撞后处理的独特性教程中有更详细的描述。
正如您在本教程中学到的那样,
本教程中的人物美术由Ponywolf提供,他是优秀的