ios - 收集硬币并添加到 Sprite Kit 中的分数标签

标签 ios swift sprite-kit game-development

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

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

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

 let another = whichNode as! 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
  }
}

游戏状态.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()


    }
}

关于ios - 收集硬币并添加到 Sprite Kit 中的分数标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33663151/

相关文章:

ios - 如何阻止 NSTimer 转到 Selector 并以另一种方法扩展它?

ios - UINavigationController 仅在第二次出现 View 时隐藏后退按钮

IOS Swift - 无需 Storyboard 即可导航至主屏幕

ios - 如何使用 Swift 在 Sprite Kit 中将标签设置为特定颜色?

sprite-kit - 无法在 iOS9 中重复使用具有不同父项的发射器节点

ios - 哪个 Sprite Kit 节点定义了 shouldRasterize 属性?

html - CSS3 奇怪的行为边框 Safari iOS 和 iPad

ios - flutter 驱动程序 : Flutter Driver extension is taking a long time to become available

ios - Apple 的 "No cancellation of the current subscription is allowed during active subscription period."是什么意思?

swift - 具有不同 Actor 隔离的 Actor-Isolated 类