2017-07-13 123 views
1

我想知道是否有人有办法在SpriteKit中使用WKCrownDelegate移动SKSpriteNode。无论是在Y方向或X方向WatchKit在SpriteKit游戏中移动SimpleSpriteNode

希望这可以帮助其他人开始与WatchKit。

这是我GameElement.swift

extension GameScene { 

    func addPlayer() { 
    player = SKSpriteNode(imageNamed: "Spaceship") 
    player.setScale(0.15) 
    player.position = CGPoint(x: 5, y: -60) 
    player.name = “ONE” 
    player.physicsBody?.isDynamic = false 
    player.physicsBody = SKPhysicsBody(rectangleOf: player.size) 


    player2 = SKSpriteNode(imageNamed: "Spaceship") 
    player2.setScale(0.15) 
    player2.position = CGPoint(x: 5, y: -60) 
    player2.name = “ONE” 
    player2.physicsBody?.isDynamic = false 
    player2.physicsBody = SKPhysicsBody(rectangleOf: player2.size) 

    addChild(player) 
    addChild(player2) 

    playerPosition = player.position 
    } 
} 

这是我GameScene.swift

class GameScene: SKScene, SKPhysicsContactDelegate, WKCrownDelegate { 

    var watchParticles:SKEmitterNode! 

    var player:SKSpriteNode! 
    var player2:SKSpriteNode! 

    var playerPosition:CGPoint! 

    override func sceneDidLoad() { 

    self.scaleMode = SKSceneScaleMode.aspectFill 

    watchParticles = SKEmitterNode(fileNamed: "watchParticles") 
    addChild(watchParticles) 


    self.physicsWorld.gravity = CGVector(dx: 0 , dy: 0) 
    physicsWorld.contactDelegate = self 
    addPlayer() 
    } 

    func moveSprite(player : SKSpriteNode,moveDirection: String){ 

    switch moveDirection { 
    case "UP": 
     print("UP") 
     player.childNode(withName: "ONE")?.physicsBody?.applyImpulse(CGVector(dx: 60, dy: 0)) 
    case "DOWN": 
     print("DOWN") 
     player.childNode(withName: "ONE")?.physicsBody?.applyImpulse(CGVector(dx: -60, dy: 0)) 
    case "STOP": 
     print("STOPPED") 
     player.childNode(withName: "ONE")?.physicsBody?.velocity = CGVector(dx: 0, dy: 0) 

    default: 
     break 
    } 
    } 
} 

这是我的InterfaceController.swift

class InterfaceController: WKInterfaceController, WKCrownDelegate { 

    @IBOutlet var skInterface: WKInterfaceSKScene! 
    private var moveDirection = "" 
    private var game = GameScene() 
    private var player = GameScene() 

    override func awake(withContext context: Any?) { 
    super.awake(withContext: context) 
    crownSequencer.delegate = self 
    crownSequencer.focus() 

    // Configure interface objects here. 

    // Load the SKScene from 'GameScene.sks' 
    if let scene = GameScene(fileNamed: "GameScene") { 

     // Set the scale mode to scale to fit the window 
     scene.scaleMode = .aspectFill 

     // Present the scene 
     self.skInterface.presentScene(scene) 
     crownSequencer.delegate = self 
     crownSequencer.focus() 


     // Use a value that will maintain a consistent frame rate 
     self.skInterface.preferredFramesPerSecond = 30 
    } 
    } 

    func crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) { 
    if rotationalDelta > 0{ 
     moveDirection = "UP" 
     game.moveSprite(player: player.player, moveDirection: moveDirection) 

    }else if rotationalDelta < 0{ 
     moveDirection = "DOWN" 
     game.moveSprite(player: player.player, moveDirection: moveDirection) 
    } 
    } 

    func crownDidBecomeIdle(_ crownSequencer: WKCrownSequencer?) { 
    moveDirection = "STOP" 
    game.moveSprite(player: player.player, moveDirection: moveDirection) 

    } 

    override func willActivate() { 
    // This method is called when watch view controller is about to be visible to user 
    super.willActivate() 
    } 

    override func didDeactivate() { 
    // This method is called when watch view controller is no longer visible 
    super.didDeactivate() 
    } 
} 
+0

如果您发布委托的代码,我可以告诉你如何串起来的SKNode。 – Fluidity

+0

我已更新它最好我可以希望这有助于并感谢您的帮助。 @Fluidity –

回答

0

欢迎来到SO!

好的,有很多东西需要解压缩才能得到一些爆米花......我认为你在这里是正确的,大多数情况下你需要在出现错误时检查零。

首先,您的界面控制器和关注我的部分是错误的。在这里,您只是实例化新的GameScene实例,它们与您的界面控制器创建的gameScene实例完全分开几行。然后,你发送冠委托功能,这些完全空gameScenes:

private var game = GameScene() // You are referencing nothing here, just creating a new gamescene. 
private var player = GameScene() // I don't think that player is supposed to be a gamescene! 

我做你指定要使用的属性(这样他们就可以由冠代理使用)的实际gameScene固定它。

private var game: GameScene! 
lazy private var player: SKSpriteNode = self.game.player 

override func awake(withContext context: Any?) { 
    // ... Stuff... 
    if let scene = GameScene(fileNamed: "GameScene") { 
    game = scene 

这也改为代表你的冠冕代表的新代码:

game.moveSprite(player: player, moveDirection: moveDirection) 

在addPlayer你这样做:

player.physicsBody?.isDynamic = true // This needs to go AFTER you init your pb. 
player.physicsBody = SKPhysicsBody(rectangleOf: player.size) 

...我通过交换线来修复它。

个人而言,我喜欢做以下,以确保不小的失误是由:

let pb = SKPhysicsBody(...) 
pb.isDynamic = true 
player.physicsBody = pb 

moveSprite有一堆与它的问题,所以我不打算一一列举如我在上面做了。看看我做了什么,然后问我是否有任何问题。基本上,你从一开始就注定了这个功能,因为你从界面控制器调用了这个方法,并且全部都是零的player值。

此外,.applyImpulse给了我很不好的控制,所以我将它改为.position的简单调整。在玩家停止之前滑行仍然存在一个小问题,但可以在另一个问题中处理:)(注意,我只在模拟器上测试过这个问题..可能不是设备上的问题)。

此外,我讨厌字符串拼写错误导致的错误,所以我将它转换为一个枚举给你。

func moveSprite(player : SKSpriteNode, moveDirection: Direction) { 

    // This will give us an equal amount of pixels to move across the watch devices: 
    // Adjust this number for shorter/longer movements: 
    let percentageOfScreenToMovePerRotation = CGFloat(1) // One percent 
    let modifier = percentageOfScreenToMovePerRotation/100 
    let amountToMove = self.frame.maxX * modifier 

    switch moveDirection { 

    case .UP: 
    player.position.x += amountToMove 
    case .DOWN: 
    player.position.x -= amountToMove 
    case .STOP: 
    break 
    } 
} 

这个故事的真正的道德这里是支票零。如果您只是始终使用someOptional?.someMethod(),那么您很可能无法轻松确定someMethod()是否实际被调用或不是。因此,您不知道问题是否与调用逻辑,方法,或与对象不存在,等

力解包在生产代码令人难以接受的,但IMO是极其宝贵当第一次开始了 - 因为它可以帮助你快速识别错误。

之后,你可以开始使用像if letguard东西来帮助检查零没有崩溃您的程序,但增加了更多的混乱和复杂的代码,当你试图做到学习一个新的API的基础知识,语言。

而作为一个最后的技巧,尽量不使用硬编码字符串时参考:把它们放进一个枚举或恒定的,因为我在你的代码:

// Because I hate string spelling erros, and you probably do too! 
enum Direction { 
    case UP, DOWN, STOP 
} 

// Because I hate errors related to spelling in strings: 
let names = (ONE: "ONE", TWO: "TWO") 


这里在他们的全部两个文件..请注意,我不得不注释掉几件事情要得到它在我的项目工作:


GameScene:

// Because I hate string spelling erros, and you probably do too! 
enum Direction { 
    case UP, DOWN, STOP 
} 

class GameScene: SKScene, SKPhysicsContactDelegate, WKCrownDelegate { 

    var watchParticles:SKEmitterNode! 

    var player: SKSpriteNode! 
    var player2: SKSpriteNode! 

    var playerPosition:CGPoint! 

    // Because I hate errors related to spelling in strings: 
    let names = (ONE: "ONE", TWO: "TWO") 

    func addPlayer() { 
    player = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50)) 
    // player = SKSpriteNode(imageNamed: "Spaceship") 
    // player.setScale(0.15) 
    player.position = CGPoint(x: 5, y: -60) 
    player.name = names.ONE 
    player.physicsBody = SKPhysicsBody(rectangleOf: player.size) 
    player.physicsBody!.isDynamic = true // This was placed *before* pb initialzier (thus never got called) 

    player2 = SKSpriteNode(color: .yellow, size: CGSize(width: 50, height: 50)) 
    // player2 = SKSpriteNode(imageNamed: "Spaceship") 
    // player2.setScale(0.15) 
    player2.position = CGPoint(x: 5, y: -60) 
    player2.name = names.TWO 
    player2.physicsBody = SKPhysicsBody(rectangleOf: player2.size) 
    player2.physicsBody!.isDynamic = false // This was placed *before* pb initialzier (thus never got called) 

    addChild(player) 
    addChild(player2) 

    playerPosition = player.position 
    } 

    override func sceneDidLoad() { 

    self.scaleMode = SKSceneScaleMode.aspectFill 

    //watchParticles = SKEmitterNode(fileNamed: "watchParticles") 
    //addChild(watchParticles) 

    self.physicsWorld.gravity = CGVector.zero 
    physicsWorld.contactDelegate = self 
    addPlayer() 
    } 

    func moveSprite(player : SKSpriteNode, moveDirection: Direction) { 

     // This will give us an equal amount of pixels to move across the watch devices: 
     // Adjust this number for shorter/longer movements: 
     let percentageOfScreenToMovePerRotation = CGFloat(1) // One percent 
     let modifier = percentageOfScreenToMovePerRotation/100 
     let amountToMove = self.frame.maxX * modifier 

     switch moveDirection { 

     case .UP: 
     player.position.x += amountToMove 
     case .DOWN: 
     player.position.x -= amountToMove 
     case .STOP: 
     break 
     } 
    } 
} 

InterfaceController:

class InterfaceController: WKInterfaceController, WKCrownDelegate { 

    @IBOutlet var skInterface: WKInterfaceSKScene! 
    private var moveDirection = Direction.STOP 

    private var game: GameScene! 
    lazy private var player: SKSpriteNode = self.game.player 

    override func awake(withContext context: Any?) { 
    super.awake(withContext: context) 
    crownSequencer.delegate = self 
    crownSequencer.focus() 

    if let scene = GameScene(fileNamed: "GameScene") { 

     game = scene // VERY IMPORTANT! 

     // Set the scale mode to scale to fit the window 
     scene.scaleMode = .aspectFill 

     // Present the scene 
     self.skInterface.presentScene(scene) 
     crownSequencer.delegate = self 
     crownSequencer.focus() 

     // Use a value that will maintain a consistent frame rate 
     self.skInterface.preferredFramesPerSecond = 30 
    } 
    else { 
     fatalError("scene not found") 
    } 
    } 

    func crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) { 
    if rotationalDelta > 0{ 
     moveDirection = .UP 
     game.moveSprite(player: player, moveDirection: moveDirection) 

    } else if rotationalDelta < 0{ 
     moveDirection = .DOWN 
     game.moveSprite(player: player, moveDirection: moveDirection) 
    } 
    } 

    func crownDidBecomeIdle(_ crownSequencer: WKCrownSequencer?) { 
    moveDirection = .STOP 
    game.moveSprite(player: player, moveDirection: moveDirection) 
    } 

    override func willActivate() { 
    // This method is called when watch view controller is about to be visible to user 
    super.willActivate() 
    } 

    override func didDeactivate() { 
    // This method is called when watch view controller is no longer visible 
    super.didDeactivate() 
    } 
}