如何处理多个块的碰撞,就好像它们是一个实体一样?
How can I handle collisions of multiple blocks as if they were a single entity?
我正在使用 Corona SDK 创建一个 2D 平台游戏,但遇到了碰撞问题。
基本上有一个角色在这个由块组成的地面上奔跑。这是因为有时地面上可能会有洞。
游戏是一个无尽的游戏,所以随着角色向前移动,新的方块(和洞)会被动态添加 - 如果它们离开屏幕也会被移除。
它工作得很好,但这种方法对碰撞系统有效,让我解释一下如何。
现在我已经有了地面,我希望角色跳跃,但前提是它接触地面,以避免在空中跳跃。
每当在 character
和 ground
之间检测到碰撞时,都会触发一个事件 - 两次。第一次是角色进入地块,第二次是角色离开地块。因此,当角色降落在地面上时,一个 isGround
布尔值被设置为 true。当 - 在跳跃之后 - 它离开时,标志设置为 false。问题是每次它离开一个街区进入另一个街区——沿着地面行走而不跳跃——旗帜都会更新。这使得基于 isGround 标志的跳转不太可靠。有时会发生无法跳跃的情况,因为 isGround
== false
虽然角色在地上。
地面块创建片段
-- init() method set the sprite of the ground block and physic to that sprite
function GroundBlock:init()
self.sprite = display.newImageRect(self.path, self.width, self.height)
self.sprite.x = self.x
self.sprite.y = self.y
physics.addBody(self.sprite, 'static', {
density = 0,
friction = 0,
bounce = 0,
box = {
halfWidth = self.width / 2,
halfHeight = self.height / 2,
y = 16,
x = 0
}
})
local collisionObj = {
name = 'ground'
}
self._collision = collisionObj
self.sprite._collision = collisionObj
self.isShow = true
end
地面放置 GroundBlocks 片段
-- init() method initialize the ground with a fixed number of blocks
function Ground:init()
self.offsetX = 0
while self.offsetX < self.camera.borderRight * 2 do
self._createBlock(1)
end
self.lastCameraPos = self.camera.borderRight
end
-- update() is called once per frame
function Ground:update()
if (self.camera.borderRight - self.lastCameraPos > self._blockWidth) then
local rand = math.ceil(math.random() * 10) % 2
if self._skippedBlock >= 2 or rand == 0 then
self._createBlock(1)
self._skippedBlock = 0
else
self._createBlock(0)
self._skippedBlock = self._skippedBlock + 1
end
self.lastCameraPos = self.camera.borderRight
end
for i, block in ipairs(self.blocks) do
if block.sprite.x < self.camera.borderLeft - block.width then
table.remove(self.blocks, i)
self.camera:remove(block.sprite)
block:delete()
end
end
end
碰撞检测片段
function Character:collision(event)
if ( event.phase == "began" ) then
if event.other._collision.name == "ground" then
self.isGround = true
end
elseif ( event.phase == "ended" ) then
if event.other._collision.name == "ground" then
self.isGround = false
print('nope')
end
end
end
一种解决方案是将地面作为单个 imgRect,但如何在其中打孔?
您可以通过跟踪角色是否可以跳跃而不是跟踪角色是否在地面上来简化代码并防止此问题发生。
例如,
function jump( event )
if event.phase == "began" then
if canJump then
canJump = false
-- your code that makes the player jump
end
end
end
你应该是通过触摸来判断玩家角色是否跳跃吧?这样,只要角色尚未跳跃,您就会在触摸开始时触发跳跃。
然后您可以通过稍微编辑它来在碰撞函数中重置此值:
function Character:collision(event)
if event.phase == "began" then
if event.other._collision.name == "ground" then
canJump = true
end
end
end
这样一来,角色的跳跃能力取决于玩家是否已经按下跳跃键,以及角色在上次跳跃后是否已经落地。
这种方法还使您能够转向实施双跳等机制。如果您选择使用数字变量而不是使用布尔 canJump
变量,例如jumpsLeft
,你可以减少每次角色跳跃时剩下的跳跃次数,只有当 jumpsLeft
大于 0 时才让角色跳跃。然后你只需将值重置回 1(或其他任何值)你会想要在落地时)。
我正在使用 Corona SDK 创建一个 2D 平台游戏,但遇到了碰撞问题。
基本上有一个角色在这个由块组成的地面上奔跑。这是因为有时地面上可能会有洞。 游戏是一个无尽的游戏,所以随着角色向前移动,新的方块(和洞)会被动态添加 - 如果它们离开屏幕也会被移除。
它工作得很好,但这种方法对碰撞系统有效,让我解释一下如何。
现在我已经有了地面,我希望角色跳跃,但前提是它接触地面,以避免在空中跳跃。
每当在 character
和 ground
之间检测到碰撞时,都会触发一个事件 - 两次。第一次是角色进入地块,第二次是角色离开地块。因此,当角色降落在地面上时,一个 isGround
布尔值被设置为 true。当 - 在跳跃之后 - 它离开时,标志设置为 false。问题是每次它离开一个街区进入另一个街区——沿着地面行走而不跳跃——旗帜都会更新。这使得基于 isGround 标志的跳转不太可靠。有时会发生无法跳跃的情况,因为 isGround
== false
虽然角色在地上。
地面块创建片段
-- init() method set the sprite of the ground block and physic to that sprite
function GroundBlock:init()
self.sprite = display.newImageRect(self.path, self.width, self.height)
self.sprite.x = self.x
self.sprite.y = self.y
physics.addBody(self.sprite, 'static', {
density = 0,
friction = 0,
bounce = 0,
box = {
halfWidth = self.width / 2,
halfHeight = self.height / 2,
y = 16,
x = 0
}
})
local collisionObj = {
name = 'ground'
}
self._collision = collisionObj
self.sprite._collision = collisionObj
self.isShow = true
end
地面放置 GroundBlocks 片段
-- init() method initialize the ground with a fixed number of blocks
function Ground:init()
self.offsetX = 0
while self.offsetX < self.camera.borderRight * 2 do
self._createBlock(1)
end
self.lastCameraPos = self.camera.borderRight
end
-- update() is called once per frame
function Ground:update()
if (self.camera.borderRight - self.lastCameraPos > self._blockWidth) then
local rand = math.ceil(math.random() * 10) % 2
if self._skippedBlock >= 2 or rand == 0 then
self._createBlock(1)
self._skippedBlock = 0
else
self._createBlock(0)
self._skippedBlock = self._skippedBlock + 1
end
self.lastCameraPos = self.camera.borderRight
end
for i, block in ipairs(self.blocks) do
if block.sprite.x < self.camera.borderLeft - block.width then
table.remove(self.blocks, i)
self.camera:remove(block.sprite)
block:delete()
end
end
end
碰撞检测片段
function Character:collision(event)
if ( event.phase == "began" ) then
if event.other._collision.name == "ground" then
self.isGround = true
end
elseif ( event.phase == "ended" ) then
if event.other._collision.name == "ground" then
self.isGround = false
print('nope')
end
end
end
一种解决方案是将地面作为单个 imgRect,但如何在其中打孔?
您可以通过跟踪角色是否可以跳跃而不是跟踪角色是否在地面上来简化代码并防止此问题发生。
例如,
function jump( event )
if event.phase == "began" then
if canJump then
canJump = false
-- your code that makes the player jump
end
end
end
你应该是通过触摸来判断玩家角色是否跳跃吧?这样,只要角色尚未跳跃,您就会在触摸开始时触发跳跃。
然后您可以通过稍微编辑它来在碰撞函数中重置此值:
function Character:collision(event)
if event.phase == "began" then
if event.other._collision.name == "ground" then
canJump = true
end
end
end
这样一来,角色的跳跃能力取决于玩家是否已经按下跳跃键,以及角色在上次跳跃后是否已经落地。
这种方法还使您能够转向实施双跳等机制。如果您选择使用数字变量而不是使用布尔 canJump
变量,例如jumpsLeft
,你可以减少每次角色跳跃时剩下的跳跃次数,只有当 jumpsLeft
大于 0 时才让角色跳跃。然后你只需将值重置回 1(或其他任何值)你会想要在落地时)。