让SKNode不离开视图

时间:2016-01-19 05:06:33

标签: ios swift sprite-kit

我正在研究太空侵略者"游戏中,我已经实现了CMMotionManager来倾斜移动我的heroShip(游戏只在横向上运行),但由于某种原因我的船将移出视图,即使

self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)

应该通过创造物理优势来防止这种情况发生。有什么想法吗?

   import SpriteKit
    import CoreMotion

class GameScene: SKScene,SKPhysicsContactDelegate{
    let collisionBulletCategory: UInt32  = 0x1 << 0
    let collisionHeroCategory: UInt32    = 0x1 << 1
    let background = SKSpriteNode(imageNamed: "background")
    let heroShip = SKSpriteNode(imageNamed: "heroShip")
    let enemyShip = SKSpriteNode(imageNamed: "enemyShip")
    let MotionManager = CMMotionManager()



    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        self.physicsWorld.contactDelegate = self

        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
        heroShip.anchorPoint = CGPointMake(1.0, 0.5)
        heroShip.physicsBody?.mass = 0.02
        heroShip.physicsBody?.dynamic = true
        heroShip.physicsBody = SKPhysicsBody(rectangleOfSize: heroShip.size)
        heroShip.physicsBody?.affectedByGravity = false
        heroShip.physicsBody?.categoryBitMask = collisionHeroCategory
        heroShip.physicsBody?.contactTestBitMask = collisionBulletCategory
        heroShip.physicsBody?.collisionBitMask = 0x0
        heroShip.position =  CGPointMake(self.size.width/6.0, self.size.height/2.0)
        enemyShip.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        enemyShip.zPosition = 1.0
        self.heroShip.zPosition = 1.0
        self.addChild(enemyShip)
        self.addChild(background)
        self.addChild(heroShip)

        if MotionManager.accelerometerAvailable{
            MotionManager.startAccelerometerUpdates()
        }

    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let bullet = SKSpriteNode(imageNamed: "bullet")
        bullet.position = CGPointMake(heroShip.position.x, heroShip.position.y)
        bullet.zPosition = 1.0
        // Add physics body for collision detection
        bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.frame.size)
        bullet.physicsBody?.dynamic = true
        bullet.physicsBody?.affectedByGravity = false
        bullet.physicsBody?.categoryBitMask = collisionBulletCategory
        bullet.physicsBody?.contactTestBitMask = collisionHeroCategory
        bullet.physicsBody?.collisionBitMask = 0x0;
        let action = SKAction.moveToX(CGRectGetMaxX(self.frame) + bullet.size.width, duration: 0.75)
        self.addChild(bullet)
        bullet.runAction(action, completion: {
            bullet.removeAllActions()
            bullet.removeFromParent()
        })
    }

    func didBeginContact(contact: SKPhysicsContact) {

    }
    override func update(currentTime: CFTimeInterval) {
        let data = MotionManager.accelerometerData
        if data?.acceleration.x == nil{
            print("nil")
        }
        else if fabs((data?.acceleration.x)!) > 0.2 {
            self.heroShip.physicsBody?.applyForce(CGVectorMake(0.0, CGFloat(50 * (data?.acceleration.x)!)))

        }

    }
}

2 个答案:

答案 0 :(得分:4)

根据文档,这就是碰撞的发生方式:

  

当两个物理实体相互接触时,可能会发生碰撞。   该身体的碰撞面具与其他身体的类别进行比较   通过执行逻辑AND操作进行掩码。如果结果是非零   值,这个身体受到碰撞的影响。每个身体独立   选择是否想要受到其他身体的影响。对于   例如,您可以使用它来避免碰撞计算   对身体的速度做出微不足道的改变。

您已将播放器的collisionBitMask设置为0x00000000(所有位已清除)。默认情况下,categoryBitMask设置为0xFFFFFFFF(所有位都设置)。因为您没有另外说明,所以场景的物理主体categoryBitMask设置为0xFFFFFFFF。当在这两者之间执行逻辑AND(&amp;)运算符时,结果将为零,表示无冲突。

要解决此问题,您只需删除此行:

 heroShip.physicsBody?.collisionBitMask = 0x0

或者通过定义Wall类别来正确设置......

<强>提示:

  • 定位点定义了如何相对于节点的位置绘制纹理。它与物理机构没什么关系。默认情况下,物理主体以节点的位置为中心。如果您打开物理视觉表示(skView.showsPhysics = true),在您的示例中,您将看到物理主体未按预期定位。

  • 在实际初始化之前设置物理体是没有意义的。你必须先初始化物理体。

答案 1 :(得分:0)

添加Whirlwind的答案,您可能还想在物理机构上启用usesPreciseCollisionDetection。通过将其设置为true,如果遇到来自加速度计数据的巨大力量,这将阻止heroShip突然出现在墙上。

基本上,物理学的计算方法与实际情况相同。因此,如果有一股巨大的力量,它可以说,“哦,这种巨大的力量意味着我应该在边界框外面的路上。”如果启用了精确的碰撞检测,则会强制它计算从该帧的起始位置到计算位置的多个位置的物理。如果它在到达计算位置之前遇到某些东西,那么它会进行调整,以使其无法通过它所击中的任何内容。在大多数情况下,你不必担心这一点,但最好是安全而不是抱歉。

在初始化之后,将此行放在物理主体配置代码中的某处:

heroShip.physicsBody?.usesPreciseCollisionDetection = true