【问题标题】:Keep an SKNode from leaving the view防止 SKNode 离开视图
【发布时间】:2016-01-19 21:57:00
【问题描述】:

我正在开发一款“太空侵略者”游戏,我已经实现了 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)!)))

        }

    }
}

【问题讨论】:

    标签: ios swift sprite-kit


    【解决方案1】:

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

    当两个物理体相互接触时,可能会发生碰撞。 将此主体的碰撞掩码与其他主体的类别进行比较 通过执行逻辑与运算来屏蔽。如果结果是非零 值,这个物体会受到碰撞的影响。每个身体独立 选择是否要被对方影响。为了 例如,您可以使用它来避免碰撞计算 对身体的速度做出微不足道的变化。

    您已将玩家的 collisionBitMask 设置为 0x00000000 之类的东西(所有位都已清除)。默认情况下,categoryBitMask 设置为0xFFFFFFFF(所有位设置)。因为您没有另外说明,所以场景的物理主体 categoryBitMask 设置为0xFFFFFFFF。在这两者之间进行逻辑与(&)运算符时,结果为零,表示没有冲突。

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

     heroShip.physicsBody?.collisionBitMask = 0x0
    

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

    提示:

    • 锚点定义了纹理相对于节点位置的绘制方式。它与物理体无关。物理体,默认情况下以节点位置为中心。如果您打开物理视觉表示 (skView.showsPhysics = true),您将看到,在您的示例中,物理体没有按应有的位置定位。

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

    【讨论】:

    • 这是正确的,我只有 0x0,还没有设置 sceneCategory UInt32。感谢您的帮助
    【解决方案2】:

    除了 Whirlwind 的回答之外,您可能还想在您的物理体上启用 usesPreciseCollisionDetection。通过将此设置为true,这将防止您的heroShip 在遇到来自加速度计数据的巨大力时弹出墙壁。

    基本上,物理学是根据它的位置来计算的。所以如果有一个巨大的力量,它可以说,“哦,这个巨大的力量意味着我应该在边界框之外的地方。”如果您启用了精确的碰撞检测,这将强制它计算从该帧的起始位置到计算位置的多个位置的物理场。如果它在到达计算出的位置之前撞到了某个东西,那么它会进行调整,以便它不会通过它撞到的任何东西。在大多数情况下,您不必担心这一点,但安全总比后悔好。

    所以在初始化之后将这一行放在你的物理体配置代码中:

    heroShip.physicsBody?.usesPreciseCollisionDetection = true
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      相关资源
      最近更新 更多