收集硬币并添加到Sprite Kit中的得分标签

我正在尝试使用本教程作为参考在我的游戏中实现一个简单的评分系统:

http://www.raywenderlich.com/87232/make-game-like-mega-jump-sprite-kit-swift-part-2

问题是,如果我尝试按原样实现,它会在此行的GameScene.swift中崩溃:

let another = whichNode as! GameObjectNode 

以下是玩家收集硬币的代码的主要部分。 如果你想更接近和更好看,我也可以邀请你到我的回购。 我知道从我在这里粘贴的代码看起来很难。

GameObjectNode.swift:

 enum CoinType: Int { case Normal = 0 case Special } struct CollisionCategoryBitmask { static let Player: UInt32 = 0x00 static let Coin: UInt32 = 0x01 static let Platform: UInt32 = 0x02 } class GameObjectNode: SKNode { func collisionWithPlayer(player: SKNode) -> Bool { return false } func checkNodeRemoval(playerY: CGFloat) { if playerY > self.position.y + 300.0 { self.removeFromParent() } } } class CoinNode: GameObjectNode { let coinSound = SKAction.playSoundFileNamed("StarPing.wav", waitForCompletion: false) var coinType: CoinType! override func collisionWithPlayer(player: SKNode) -> Bool { // Boost the player up player.physicsBody?.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: 400.0) // Play sound runAction(coinSound, completion: { // Remove this Star self.removeFromParent() }) // Award score GameState.sharedInstance.score += (coinType == .Normal ? 20 : 100) // Award stars GameState.sharedInstance.coins += (coinType == .Normal ? 1 : 5) // The HUD needs updating to show the new stars and score return true } } 

GameState.swift

 class GameState { var score: Int var highScore: Int var coins: Int init() { // Init score = 0 highScore = 0 coins = 0 // Load game state let defaults = NSUserDefaults.standardUserDefaults() highScore = defaults.integerForKey("highScore") coins = defaults.integerForKey("coins") } func saveState() { // Update highScore if the current score is greater highScore = max(score, highScore) // Store in user defaults let defaults = NSUserDefaults.standardUserDefaults() defaults.setInteger(highScore, forKey: "highScore") defaults.setInteger(coins, forKey: "coins") NSUserDefaults.standardUserDefaults().synchronize() } class var sharedInstance: GameState { struct Singleton { static let instance = GameState() } return Singleton.instance } } 

而GameScene.swift:

 import SpriteKit import CoreMotion import GameplayKit struct PhysicsCategory { static let None: UInt32 = 0 static let Player: UInt32 = 0b1 // 1 static let PlatformNormal: UInt32 = 0b10 // 2 static let PlatformBreakable: UInt32 = 0b100 // 4 static let CoinNormal: UInt32 = 0b1000 // 8 static let CoinSpecial: UInt32 = 0b10000 // 16 static let Edges: UInt32 = 0b100000 // 32 } class GameScene: SKScene, SKPhysicsContactDelegate { // Other Properties ... var player: SKSpriteNode! // HUD var hudNode: SKNode! var lblScore: SKLabelNode! var lblCoins: SKLabelNode! override func didMoveToView(view: SKView) { .... // HUD hudNode = SKNode() hudNode.zPosition = 1000 cameraNode.addChild(hudNode) // Coins let coin = SKSpriteNode(imageNamed: "powerup05_1") coin.position = convertPoint(CGPoint(x: 300, y: self.size.height-100), toNode: cameraNode) coin.zPosition = 1000 hudNode.addChild(coin) lblCoins = SKLabelNode(fontNamed: "ChalkboardSE-Bold") lblCoins.fontSize = 70 lblCoins.fontColor = SKColor.whiteColor() lblCoins.position = convertPoint(CGPoint(x: 375, y: self.size.height-100), toNode: cameraNode) lblCoins.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left lblCoins.zPosition = 1000 lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins) hudNode.addChild(lblCoins) // Score // 4 lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold") lblScore.fontSize = 70 lblScore.fontColor = SKColor.whiteColor() lblScore.position = convertPoint(CGPoint(x: self.size.width-325, y: self.size.height-100), toNode: cameraNode) lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Right lblScore.zPosition = 1000 lblScore.text = "0" hudNode.addChild(lblScore) } func setupNodes() { ... player = fgNode.childNodeWithName("Player") as! SKSpriteNode } func createStarAtPosition(position: CGPoint, ofType type: CoinType) -> CoinNode { // 1 let node = CoinNode() let thePosition = CGPoint(x: position.x * scaleFactor, y: position.y) node.position = thePosition node.name = "NODE_COIN" // 2 node.coinType = type var sprite: SKSpriteNode if type == .Special { sprite = SKSpriteNode(imageNamed: "CoinSpecial") } else { sprite = SKSpriteNode(imageNamed: "Coin") } node.addChild(sprite) // 3 node.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size.width / 2) // 4 node.physicsBody?.dynamic = false node.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Coin node.physicsBody?.collisionBitMask = 0 node.physicsBody?.contactTestBitMask = 0 return node } func didBeginContact(contact: SKPhysicsContact) { let other = contact.bodyA.categoryBitMask == PhysicsCategory.Player ? contact.bodyB : contact.bodyA var updateHUD = false let whichNode = (contact.bodyA.node != player) ? contact.bodyA.node : contact.bodyB.node // Code crashes here let another = whichNode as! GameObjectNode updateHUD = another.collisionWithPlayer(player) if updateHUD { lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins) lblScore.text = String(format: "%d", GameState.sharedInstance.score) } switch other.categoryBitMask { case PhysicsCategory.CoinNormal: if let coin = other.node as? SKSpriteNode { emitParticles("CollectNormal", sprite: coin) jumpPlayer() runAction(soundCoin) } case PhysicsCategory.CoinSpecial: if let coin = other.node as? SKSpriteNode { emitParticles("CollectSpecial", sprite: coin) boostPlayer() runAction(soundBoost) } case PhysicsCategory.PlatformNormal: if let platform = other.node as? SKSpriteNode { if player.physicsBody!.velocity.dy < 0 { platformAction(platform, breakable: false) jumpPlayer() runAction(soundJump) } } case PhysicsCategory.PlatformBreakable: if let platform = other.node as? SKSpriteNode { if player.physicsBody!.velocity.dy < 0 { platformAction(platform, breakable: true) jumpPlayer() runAction(soundBrick) } } default: break; } } 

我不理解您在didBeganContact中使用的代码,但您可以通过以下方式定义联系人主体:

  enum Ctg:UInt32 { case Coin = 1 case Hero = 2 case Villain = 4 case Car = 8 } var hero = SKSpriteNode() hero.physicsBody = SKPhysicsBody(rectangleOfSize: hero.size) hero.physicsBody?.categoryBitMask = Ctg.Hero.rawValue hero.physicsBody?.contactTestBitMask = Ctg.Coin.rawValue | Ctg.Villian.rawValue var coin = SKSpriteNode() coin.physicsBody = SKPhysicsBody(rectangleOfSize: coin.size) coin.physicsBody?.categoryBitMask = Ctg.Coin.rawValue coin.physicsBody?.contactTestBitMask = Ctg.Hero.rawValue func didBeginContact(contact: SKPhysicsContact) { var first = SKNode() var sec = SKNode() // this way you ensure that the first body is the most valuable Ctg (enum) if contact.bodyA.node?.physicsBody?.categoryBitMask > contact.bodyB.node?.physicsBody?.categoryBitMask { first = contact.bodyA.node! sec = contact.bodyB.node! } else { first = contact.bodyB.node! sec = contact.bodyA.node! } // this part be sure that the category of first it is of most value that sec if first.physicsBody!.categoryBitMask == Ctg.Hero.rawValue && sec.physicsBody!.categoryBitMask == Ctg.Coin.rawValue { hero.coins++ scene.labelCoins.text = String(coins) } if first.physicsBody!.categoryBitMask == Ctg.Villain.rawValue && sec.physicsBody!.categoryBitMask == Ctg.Hero.rawValue { gameOver = true hero.removeFromParent() lostGame() } }