【问题标题】:Unexpected collision behaviour when block moves fast - sprite passes through方块快速移动时的意外碰撞行为 - 精灵穿过
【发布时间】:2016-02-24 08:38:02
【问题描述】:

我有一个方形框架,用户可以在其中移动一个块但不能触摸框架。如果用户触摸方框,则游戏结束。目前我有一个问题,如果用户快速滑动块,它会通过框架而没有任何碰撞/接触检测。如果玩家缓慢移动方块并接触到框架,那么它会检测到碰撞。我的代码如下,我无法让它停止通过框架。

// setup play scene
let playScreen = SKSpriteNode(color: .clearColor(), size: CGSize(width: 370, height: 370))
playScreen.position = CGPoint(x: frame.midX, y: frame.midY - CGFloat(yFrame))
// create the rectangle which will represent physics body
let rect = CGRect(origin: CGPoint(x: -playScreen.size.width/2, y: -playScreen.size.height/2), size: playScreen.size)
// apply physics conditions to the play scene
playScreen.physicsBody = SKPhysicsBody(edgeLoopFromRect: rect)
playScreen.physicsBody!.friction = 0
// add play scene to the frame
addChild(playScreen)
playScreen.physicsBody!.categoryBitMask = BitMask.frame
playScreen.physicsBody!.contactTestBitMask = BitMask.player
playScreen.physicsBody!.collisionBitMask = BitMask.player
playScreen.physicsBody!.usesPreciseCollisionDetection = true;

// set up player block
player.position = CGPoint(x:frame.size.width/2, y: frame.size.height/2  - CGFloat(yFrame))
player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 30, height: 30))
player.physicsBody!.dynamic = true
player.physicsBody!.friction = 0
player.physicsBody!.affectedByGravity = false
player.physicsBody!.allowsRotation = false
addChild(player)
player.physicsBody!.categoryBitMask     = BitMask.player
player.physicsBody!.contactTestBitMask  = BitMask.obstacle | BitMask.frame
player.physicsBody!.collisionBitMask    = BitMask.obstacle | BitMask.frame

我有以下接触检测:

func didBeginContact(contact: SKPhysicsContact) {
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    if (firstBody.categoryBitMask == BitMask.player) && ( (secondBody.categoryBitMask == BitMask.obstacle) || (secondBody.categoryBitMask == BitMask.frame) )  {

        self.view?.paused = true

        // check if this stops it
        player.physicsBody!.velocity.dx = 0
        player.physicsBody!.velocity.dy = 0

        playerCollided = true

    }
}

所以这是我的触摸开始功能的代码。如果用户触摸播放器块:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first! as UITouch
    let touchLocation = touch.locationInNode(self)
    let touchedNode = self.nodeAtPoint(touchLocation)
    let name = touchedNode.name

    if name == "player" {

        // first touch
        if playerFirstTouch {
            print("New Game")
            print("Finger is on player block")
            isFingerOnPlayer = true

            NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "printDuration:", userInfo: NSDate(), repeats: true)

            playerFirstTouch = false
            print("\(player.physicsBody!.velocity.dy)")

        } else {
            print("Finger is on player block after game started")
            isFingerOnPlayer = true
            print("\(player.physicsBody!.velocity.dy)")
        }
    }
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first! as UITouch
    let touchLocation = touch.locationInNode(self)

    // check if user touched the player block
    if isFingerOnPlayer {
        // get touch location
        if let touch = touches.first {
            let prevTouchLoc = touch.previousLocationInNode(self)
            // calculate new position along x and y
            var newXPos = player.position.x + (touchLocation.x - prevTouchLoc.x)
            var newYPos = player.position.y + (touchLocation.y - prevTouchLoc.y)
            //
            newXPos = max(newXPos, self.player.frame.size.width/2)
            newXPos = min(newXPos, self.size.width - self.player.frame.size.width/2)
            //
            newYPos = max(newYPos, self.player.frame.size.height/2)
            newYPos = min(newYPos, self.size.height - self.player.frame.size.height/2)
            // update player block position
            player.position = CGPointMake(newXPos, newYPos)
        }
    }

}

【问题讨论】:

    标签: ios swift sprite-kit


    【解决方案1】:

    让玩家使用精确的碰撞检测,而不是场景。玩家是正在移动的节点,需要对其物理计算进行分步处理。所以像:

    player.physicsBody!.usesPreciseCollisionDetection = true;
    

    您可以从playScene 中删除精确的碰撞检测,因为启用它只会让物理引擎陷入困境。

    编辑

    我将对此进行扩展以涵盖如何使用SKAction 移动节点而不是设置位置。我很确定这会奏效,但请告诉我。查看我将要使用的the documentation for the moveBy method

    你要做的第一件事就是删除这一行:

    player.position = CGPointMake(newXPos, newYPos)
    

    我们将用这一行替换它:

    player.runAction(SKAction.moveTo(CGPointMake(newXPos, newYPos), 0.01))
    

    这应该真的快速将玩家移动到所需的位置(我认为)。

    【讨论】:

    • 我刚试过你说的,恐怕没有运气。
    • 嗯。您介意包括如何发送player 移动吗?我没有看到您在问题中的代码有任何明显错误,但刷卡代码中可能存在某些问题(例如直接设置 xy 值)。
    • 我添加了 touches started 函数,我使用它允许用户触摸和移动播放器块
    • @spigen 似乎您正在手动设置位置,这意味着物理体忽略了从 a 到 b 的行进路径。相反,尝试制作一个非常短的SKAction,将player 从a 移动到b。我认为这将允许物理检测,但我不确定。告诉我!
    • 当您说我手动设置位置时,您是指在计算新 X 和 Y 位置的 touchesMoved 函数中吗?我将如何实施您提到的 SKAction?抱歉,这有点陌生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-03
    • 2012-03-04
    • 1970-01-01
    相关资源
    最近更新 更多