在SpriteKit中为给定SpriteNode的每一侧创建物理实体

时间:2016-08-02 17:59:51

标签: swift sprite-kit game-physics skspritenode

我正在制作一个简单的游戏,其中物体从屏幕顶部落下并落在屏幕底部的地面上(有点像俄罗斯方块),玩家在地面上避开并摧毁物体土地。我希望玩家能够在接触到左侧和右侧时摧毁物体,并且我希望玩家在物体落到他身上时被杀死。我还希望玩家能够在不破坏物体的情况下跳到物体顶部。

我试图弄清楚正确的坐标,以便为我的物体的每一面制作一个物理体。 (这是我正在尝试执行此操作的一些代码):

        let topLeftPoint = CGPointMake(1, (objectSprite.size.height))
        let bottomLeftPoint = CGPointMake(1 , 1)
        let topRightPoint = CGPointMake((objectSprite.size.width), (objectSprite.size.height))
        let bottomRightPoint = CGPointMake((objectSprite.size.width), 1)


        self.topSideBody = SKPhysicsBody(edgeFromPoint: topLeftPoint, toPoint: topRightPoint)
        self.topSideBody.categoryBitMask = ObstacleSide.topSide.rawValue
        self.topSideBody.contactTestBitMask = BodyType.player.rawValue | BodyType.grassObject.rawValue


        self.leftSideBody = SKPhysicsBody(edgeFromPoint: topLeftPoint, toPoint: bottomLeftPoint)
        self.leftSideBody.categoryBitMask = ObstacleSide.leftSide.rawValue
        self.leftSideBody.contactTestBitMask = BodyType.player.rawValue | BodyType.grassObject.rawValue

        self.rightSideBody = SKPhysicsBody(edgeFromPoint: topRightPoint, toPoint: bottomRightPoint)
        self.rightSideBody.categoryBitMask = ObstacleSide.rightSide.rawValue
        self.rightSideBody.contactTestBitMask = BodyType.player.rawValue | BodyType.grassObject.rawValue

        self.bottomSideBody = SKPhysicsBody(edgeFromPoint: bottomLeftPoint, toPoint: bottomRightPoint)
        self.bottomSideBody.categoryBitMask = ObstacleSide.bottomSide.rawValue
        self.bottomSideBody.contactTestBitMask = BodyType.player.rawValue | BodyType.grassObject.rawValue

        physicsBody = SKPhysicsBody(bodies: [topSideBody, leftSideBody, rightSideBody, bottomSideBody])
        objectSprite.physicsBody = physicsBody
        //objectSprite.physicsBody?.categoryBitMask = BodyType.grassObject.rawValue
        objectSprite.physicsBody!.friction = 0.0
        objectSprite.physicsBody!.dynamic = true
        objectSprite.physicsBody!.affectedByGravity = true

        objectSprite.physicsBody!.restitution = 0.0
        objectSprite.physicsBody!.allowsRotation = false

        self.zPosition = 102

我主要不确定我应该使用什么坐标,或者是否有更简单的方法来执行此操作。考虑到我为障碍设置的一些布尔值,我也没有破坏障碍并杀死玩家的问题,我的主要问题是玩家能够在不破坏物体的情况下在物体上行走。

1 个答案:

答案 0 :(得分:0)

如果物体是方形或矩形,那么你真的不需要超过1个物理体。这是您将如何做的概述:

请注意,我从this question复制了大部分代码。我建议你阅读它以更好地了解最新情况

在你的didBegin(_ contact:SKPhysicsContact)函数中

获取对象节点和collisionPoint(假设对象是contact.bodyB.node)并将其传递给下面的函数:

let block = contact.bodyB.node as! SKSpriteNode
let contactPoint = contact.contactPoint


func handleCollision(block:SKSpriteNode, contactPoint:CGPoint){
        // find the corners and convert thoes points into the scene coordinate space
        let topLeft = convert(CGPoint(x: -block.size.width/2, y: block.size.height/2), from: block)
        let bottomLeft = convert(CGPoint(x: -block.size.width/2, y: -block.size.width/2), from: block)
        let topRight = convert(CGPoint(x: block.size.width/2, y: block.size.height/2), from: block)
        let bottomRight = convert(CGPoint(x: block.size.width/2, y: -block.size.width/2), from: block)

        // Then we put these "referencePoints" into an array for easy acces.
        // Note that we go in a clockwise direction from the top left

        let referencePoints = [topLeft,topRight,bottomRight,bottomLeft]

        // ***Find the closest corner relative to the contactPoint.***

        // Varible to store the closetCorner
        var closestCorner = referencePoints[0]

        //We set the prevDistance to something very large.
        var prevDistance:CGFloat = 10000000

        for corner in referencePoints{

            // We check the distance from the contactPoint to each corner.
            // If the distance is smaler then the last checked corner we update the closestCorner varible and also the prevDistance.
            let distance = hypot(corner.x - contactPoint.x, corner.y - contactPoint.y)
            if distance < prevDistance{
                prevDistance = distance
                closestCorner = corner
            }

        }

        // Now lets find the NextCorner and prevCorner relative to the closestCorner.
        var nextCorner:CGPoint
        var prevCorner:CGPoint
        let index = referencePoints.index(of: closestCorner)

        if index == 3{
            nextCorner = referencePoints[0]
        }
        else{
            nextCorner = referencePoints[index! + 1]
        }

        if index == 0{

            prevCorner = referencePoints[3]

        }
        else{
            prevCorner = referencePoints[index! - 1]
        }



        // Distance from closestCorner to nextCorner.
        let distToNextCorner = hypot(closestCorner.x - nextCorner.x, closestCorner.y - nextCorner.y)
        // Distance from contactPoint to nextCorner
        let distFromContactPoint = hypot(contactPoint.x - nextCorner.x, contactPoint.y - nextCorner.y)



        let firstSurfacePoint = closestCorner
        var secondSurfacePoint:CGPoint

        if distToNextCorner > distFromContactPoint{

            secondSurfacePoint = nextCorner

        }
        else{
            secondSurfacePoint = prevCorner

        }


        if firstSurfacePoint == topLeft || firstSurfacePoint == topRight &&
            secondSurfacePoint == topLeft || secondSurfacePoint == topRight  {

            // collision happend on the top side. Do something here to handle that

        }

        if firstSurfacePoint == topRight || firstSurfacePoint == bottomRight &&
            secondSurfacePoint == topRight || secondSurfacePoint == bottomRight  {

            // collision happend on the right side. Do something here to handle that

        }

        if firstSurfacePoint == bottomLeft || firstSurfacePoint == bottomRight &&
            secondSurfacePoint == bottomLeft || secondSurfacePoint == bottomRight  {

            // collision happend on the underside. Do something here to handle that

        }

        if firstSurfacePoint == topLeft || firstSurfacePoint == bottomLeft &&
            secondSurfacePoint == topLeft || secondSurfacePoint == bottomLeft  {

            // collision happend on the left side. Do something here to handle that

        }

    }

这个答案可能有点草率,但如果有人问我可以改进它。因为这个问题已经11个月了,所以并没有真正打扰:)