【问题标题】:How can I handle collisions of multiple blocks as if they were a single entity?如何处理多个块的冲突,就好像它们是一个实体一样?
【发布时间】:2020-01-10 12:03:37
【问题描述】:

我正在使用 Corona SDK 创建一个 2D 平台游戏,但遇到了碰撞问题。

基本上有一个角色在这块由块组成的地面上奔跑。这是因为有时地面上可能会有洞。 游戏是无止境的,所以随着角色向前移动,新的方块(和洞)会被动态添加——如果它们离开屏幕,也会被移除。

它工作得很好,但这种方法对碰撞系统有效,让我解释一下。 现在我已经有了地面,我希望角色跳跃,但前提是它接触到地面,以避免在空中跳跃。 每当在characterground 之间检测到冲突时,就会触发一个事件 - 两次。第一次是在角色进入地面方块时,第二次是在角色离开地面时。因此,当角色落地时,isGround 布尔值设置为真。而当 - 在跳跃之后 - 它离开它时,标志设置为假。问题是每次它离开一个街区进入另一个街区 - 沿着地面行走而不跳跃 - 标志都会更新。这使得基于 isGround 标志的跳转不太可靠。有时你不能跳是因为isGround == false 虽然角色在地上。

地块创建sn-p

-- 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 sn-p

-- 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

碰撞检测sn-p

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,但如何在其中打孔?

【问题讨论】:

    标签: lua coronasdk


    【解决方案1】:

    您可以通过跟踪角色是否可以跳跃而不是跟踪角色是否在地面上来简化代码并防止此问题发生。

    例如,

    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(或任何您想要的落地时)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多