简体   繁体   English

如何在Singleton的快速Sprite Kit游戏中显示分数标签

[英]How to display a score label in a swift Sprite Kit game with Singleton

I have been trying for a couple of days now to implement a singleton method to update the score for each level of a game I am making. 我已经尝试了几天,以实现单例方法来更新我正在制作的游戏的每个级别的分数。 I cannot figure out the correct way to implement it. 我不知道实现它的正确方法。 I have no errors when I build and run the project, but the Score Label will not display when I run the game. 在构建和运行项目时,我没有任何错误,但是在运行游戏时,分数标签不会显示。 I have no idea why, but I know it has something to do with the singleton method not being implemented correctly. 我不知道为什么,但是我知道这与单例方法未正确实现有关。 Any input would be much appreciated. 任何输入将不胜感激。 The code below is my first and opening scene that does not show the score label or score as of right now. 下面的代码是我的第一个开场场景,目前还没有显示得分标签或得分。

This is the first level of the game: 这是游戏的第一级:

import SpriteKit

class Singleton {

static let sharedInstance = Singleton()
var ScoreLabel = UILabel()
var Score : Int = 0


}



struct PhysicsCategory {
static let Enemy : UInt32 = 1
static let Bullet : UInt32 = 2
static let Player : UInt32 = 3
}



class GameScene: SKScene, SKPhysicsContactDelegate {
var HighScore = Int()
var Player = SKSpriteNode(imageNamed: "GoodGuy.png")
var Level1Label = UILabel()


override func didMoveToView(view: SKView) {
    /* Setup your scene here */

    var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "update", userInfo: nil, repeats: true)

    var HighScoreDefault = NSUserDefaults.standardUserDefaults()
    if (HighScoreDefault.valueForKey("HighScore") != nil){

        HighScore = HighScoreDefault.valueForKey("HighScore") as! NSInteger
    }
    else{
        HighScore = 0
    }




    physicsWorld.contactDelegate = self

    self.scene?.backgroundColor = UIColor.blackColor()

    self.scene?.size = CGSize(width:640, height: 1136)

    self.addChild(SKEmitterNode(fileNamed: "MagicParticle")!)

    Player.position = CGPointMake(self.size.width/2, self.size.height/8)
    Player.physicsBody = SKPhysicsBody (rectangleOfSize: Player.size)
    Player.physicsBody?.affectedByGravity = false
    Player.physicsBody?.categoryBitMask = PhysicsCategory.Player
    Player.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
    Player.physicsBody?.dynamic = false

    Level1Label = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3, height: 30))
    Level1Label.center = CGPoint(x: view.frame.size.width/1.675 , y: view.frame.size.height/1.05)
    Level1Label.textColor = UIColor.whiteColor()
    Level1Label.text = "Level 1"
    self.view?.addSubview(Level1Label)

    Singleton.sharedInstance.ScoreLabel.text = "\(Singleton.sharedInstance.Score)"
    Singleton.sharedInstance.ScoreLabel = UILabel(frame: CGRect(x:0, y:0, width:100, height:20))
    Singleton.sharedInstance.ScoreLabel.backgroundColor = UIColor.clearColor()
    Singleton.sharedInstance.ScoreLabel.textColor = UIColor.whiteColor()
    self.view?.addSubview(Singleton.sharedInstance.ScoreLabel)


    var Timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("SpawnBullets"), userInfo: nil, repeats: true)

    var Enemytimer = NSTimer.scheduledTimerWithTimeInterval(1.5, target: self, selector: Selector("SpawnEnemies"), userInfo: nil, repeats: true)



    self.addChild(Player)





}

func update() {
    self.view?.presentScene(GameScene2())
    Level1Label.removeFromSuperview()
}

func didBeginContact(contact: SKPhysicsContact) {
    var firstBody : SKPhysicsBody = contact.bodyA
    var secondBody : SKPhysicsBody = contact.bodyB
    if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.Bullet) ||
        (firstBody.categoryBitMask == PhysicsCategory.Bullet) && (secondBody.categoryBitMask == PhysicsCategory.Enemy)){

        CollisionWithBullet(firstBody.node as! SKSpriteNode, Bullet: secondBody.node as! SKSpriteNode)

    }

    else if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.Player) ||
        (firstBody.categoryBitMask == PhysicsCategory.Player) && (secondBody.categoryBitMask == PhysicsCategory.Enemy)){

            CollisionWithPlayer(firstBody.node as! SKSpriteNode, Player: secondBody.node as! SKSpriteNode)
    }


}


func CollisionWithBullet(Enemy: SKSpriteNode, Bullet: SKSpriteNode){
    Enemy.removeFromParent()
    Bullet.removeFromParent()
    Singleton.sharedInstance.Score++


    Singleton.sharedInstance.ScoreLabel.text = "\(Singleton.sharedInstance.Score)"
}



func CollisionWithPlayer(Enemy: SKSpriteNode, Player: SKSpriteNode){
    var ScoreDefault = NSUserDefaults.standardUserDefaults()
    ScoreDefault.setValue(Singleton.sharedInstance.Score, forKey: "Score")
    ScoreDefault.synchronize()


    if (Singleton.sharedInstance.Score > HighScore){

    var HighScoreDefault = NSUserDefaults.standardUserDefaults()
    HighScoreDefault.setValue(Singleton.sharedInstance.Score, forKey: "HighScore")

    }


    Enemy.removeFromParent()
    Player.removeFromParent()
    self.view?.presentScene(EndScene())
    Level1Label.removeFromSuperview()

        }

func SpawnBullets(){
    var Bullet = SKSpriteNode(imageNamed: "Bullet.png")
    Bullet.zPosition = -5
    Bullet.position = CGPointMake(Player.position.x, Player.position.y)

    let action = SKAction.moveToY(self.size.height + 30, duration: 1.0)
    let actionDone = SKAction.removeFromParent()
    Bullet.runAction(SKAction.sequence([action, actionDone]))


    Bullet.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet.size)
    Bullet.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
    Bullet.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
    Bullet.physicsBody?.affectedByGravity = false
    Bullet.physicsBody?.dynamic = false
    self.addChild(Bullet)
}

func SpawnEnemies(){
    var Enemy = SKSpriteNode(imageNamed: "BadGuy.png")
    var MinValue = self.size.width/8
    var MaxValue = self.size.width - 150
    let SpawnPoint = UInt32(MaxValue - MinValue)
    Enemy.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
    Enemy.physicsBody = SKPhysicsBody(rectangleOfSize: Enemy.size)
    Enemy.physicsBody?.categoryBitMask = PhysicsCategory.Enemy
    Enemy.physicsBody?.contactTestBitMask = PhysicsCategory.Bullet
    Enemy.physicsBody?.affectedByGravity = false
    Enemy.physicsBody?.dynamic = true

    let action = SKAction.moveToY(-70, duration: 3.0)
    let actionDone = SKAction.removeFromParent()
    Enemy.runAction(SKAction.sequence([action, actionDone]))

    Enemy.runAction(SKAction.repeatActionForever(action))

    self.addChild(Enemy)

}



override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   /* Called when a touch begins */

    for touch in touches {
        let location = touch.locationInNode(self)

        Player.position.x = location.x

    }
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        Player.position.x = location.x

    }
}
override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */
}
}

This is the second level of the game: 这是游戏的第二层:

import SpriteKit 导入SpriteKit

struct PhysicsCategory2 {
static let Enemy : UInt32 = 1//00000000000000000000000000000001
static let Bullet : UInt32 = 2//00000000000000000000000000000010
static let Player : UInt32 = 3//00000000000000000000000000000100
}


class GameScene2: SKScene, SKPhysicsContactDelegate {
var HighScore = Int()
var Player = SKSpriteNode(imageNamed: "GoodGuy.png")
var Level2Label = UILabel()


override func didMoveToView(view: SKView) {
    /* Setup your scene here */

    var HighScoreDefault = NSUserDefaults.standardUserDefaults()
    if (HighScoreDefault.valueForKey("HighScore") != nil){

        HighScore = HighScoreDefault.valueForKey("HighScore") as! NSInteger
    }
    else{
        HighScore = 0
    }



    physicsWorld.contactDelegate = self

    self.scene?.backgroundColor = UIColor.blackColor()

    self.scene?.size = CGSize(width:640, height: 1136)

    self.addChild(SKEmitterNode(fileNamed: "MagicParticle")!)

    Player.position = CGPointMake(self.size.width/2, self.size.height/8)
    Player.physicsBody = SKPhysicsBody (rectangleOfSize: Player.size)
    Player.physicsBody?.affectedByGravity = false
    Player.physicsBody?.categoryBitMask = PhysicsCategory2.Player
    Player.physicsBody?.contactTestBitMask = PhysicsCategory2.Enemy
    Player.physicsBody?.dynamic = false

    Level2Label = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3, height: 30))
    Level2Label.center = CGPoint(x: view.frame.size.width/1.675 , y: view.frame.size.height/1.05)
    Level2Label.textColor = UIColor.whiteColor()
    Level2Label.text = "Level 2"
    self.view?.addSubview(Level2Label)


    var Timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("SpawnBullets"), userInfo: nil, repeats: true)

    var Enemytimer = NSTimer.scheduledTimerWithTimeInterval(1.5, target: self, selector: Selector("SpawnEnemies"), userInfo: nil, repeats: true)



    self.addChild(Player)

    Singleton.sharedInstance.ScoreLabel.text = "\(Singleton.sharedInstance.Score)"
    Singleton.sharedInstance.ScoreLabel = UILabel(frame: CGRect(x:0, y:0, width:100, height:20))
    Singleton.sharedInstance.ScoreLabel.backgroundColor = UIColor.clearColor()
    Singleton.sharedInstance.ScoreLabel.textColor = UIColor.whiteColor()



}

func didBeginContact(contact: SKPhysicsContact) {
    var firstBody : SKPhysicsBody = contact.bodyA
    var secondBody : SKPhysicsBody = contact.bodyB
    if ((firstBody.categoryBitMask == PhysicsCategory2.Enemy) && (secondBody.categoryBitMask == PhysicsCategory2.Bullet) ||
        (firstBody.categoryBitMask == PhysicsCategory2.Bullet) && (secondBody.categoryBitMask == PhysicsCategory2.Enemy)){

            CollisionWithBullet(firstBody.node as! SKSpriteNode, Bullet: secondBody.node as! SKSpriteNode)

    }

    else if ((firstBody.categoryBitMask == PhysicsCategory2.Enemy) && (secondBody.categoryBitMask == PhysicsCategory2.Player) ||
        (firstBody.categoryBitMask == PhysicsCategory2.Player) && (secondBody.categoryBitMask == PhysicsCategory2.Enemy)){

            CollisionWithPlayer(firstBody.node as! SKSpriteNode, Player: secondBody.node as! SKSpriteNode)
    }


    }


    func CollisionWithBullet(Enemy: SKSpriteNode, Bullet: SKSpriteNode){
    Enemy.removeFromParent()
    Bullet.removeFromParent()
    Singleton.sharedInstance.Score++


    Singleton.sharedInstance.ScoreLabel.text = "\(Singleton.sharedInstance.Score)"
}




func CollisionWithPlayer(Enemy: SKSpriteNode, Player: SKSpriteNode){
    var ScoreDefault = NSUserDefaults.standardUserDefaults()
    ScoreDefault.setValue(Singleton.sharedInstance.Score, forKey: "Score")
    ScoreDefault.synchronize()

    if (Singleton.sharedInstance.Score > HighScore){

        var HighScoreDefault = NSUserDefaults.standardUserDefaults()
        HighScoreDefault.setValue(Singleton.sharedInstance.Score, forKey: "HighScore")

    }


    Enemy.removeFromParent()
    Player.removeFromParent()
    self.view?.presentScene(EndScene())
    Level2Label.removeFromSuperview()
    Singleton.sharedInstance.ScoreLabel.removeFromSuperview()

    }

    func SpawnBullets(){
    var Bullet = SKSpriteNode(imageNamed: "Bullet.png")
    Bullet.zPosition = -5
    Bullet.position = CGPointMake(Player.position.x, Player.position.y)

    let action = SKAction.moveToY(self.size.height + 30, duration: 1.0)
    let actionDone = SKAction.removeFromParent()
    Bullet.runAction(SKAction.sequence([action, actionDone]))


    Bullet.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet.size)
    Bullet.physicsBody?.categoryBitMask = PhysicsCategory2.Bullet
    Bullet.physicsBody?.contactTestBitMask = PhysicsCategory2.Enemy
    Bullet.physicsBody?.affectedByGravity = false
    Bullet.physicsBody?.dynamic = false
    self.addChild(Bullet)
    }

    func SpawnEnemies(){
    var Enemy = SKSpriteNode(imageNamed: "BadGuy.png")
    var MinValue = self.size.width/8
    var MaxValue = self.size.width - 150
    let SpawnPoint = UInt32(MaxValue - MinValue)
    Enemy.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
    Enemy.physicsBody = SKPhysicsBody(rectangleOfSize: Enemy.size)
    Enemy.physicsBody?.categoryBitMask = PhysicsCategory2.Enemy
    Enemy.physicsBody?.contactTestBitMask = PhysicsCategory2.Bullet
    Enemy.physicsBody?.affectedByGravity = false
    Enemy.physicsBody?.dynamic = true

    let action = SKAction.moveToY(-70, duration: 3.0)
    let actionDone = SKAction.removeFromParent()
    Enemy.runAction(SKAction.sequence([action, actionDone]))

    Enemy.runAction(SKAction.repeatActionForever(action))

    self.addChild(Enemy)

    }



    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    /* Called when a touch begins */

    for touch in touches {
        let location = touch.locationInNode(self)

        Player.position.x = location.x

    }
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        Player.position.x = location.x

    }
}
override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */
}
}

This is the Game Over page of the game: 这是游戏的“游戏结束”页面:

import Foundation
import SpriteKit

class EndScene: SKScene {

var RestartButton : UIButton!
var HighScore : Int!
var HighScoreLabel : UILabel!
var GameOverLabel : UILabel!
override func didMoveToView(view: SKView) {

    self.scene?.backgroundColor = UIColor.blackColor()

    self.scene?.size = CGSize(width:640, height: 1136)

    self.addChild(SKEmitterNode(fileNamed: "MagicParticle")!)

    RestartButton = UIButton(frame: CGRect(x:0, y:0, width: view.frame.size.width/3
        , height: 30))
    RestartButton.titleLabel?.adjustsFontSizeToFitWidth = true
    RestartButton.center = CGPoint(x: view.frame.size.width/2 , y: view.frame.size.height/1.5)
    RestartButton.setTitle("Restart", forState: UIControlState.Normal)
    RestartButton.showsTouchWhenHighlighted = true
    RestartButton.setTitleColor(UIColor.whiteColor(), forState:  UIControlState.Normal)
    RestartButton.addTarget(self, action: Selector("Restart"), forControlEvents: UIControlEvents.TouchUpInside)
    self.view?.addSubview(RestartButton)

    var ScoreDefault = NSUserDefaults.standardUserDefaults()
    var Score = ScoreDefault.valueForKey("Score") as! NSInteger

    var HighScoreDefault = NSUserDefaults.standardUserDefaults()
    HighScore = HighScoreDefault.valueForKey("HighScore") as! NSInteger

    Singleton.sharedInstance.ScoreLabel = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3, height: 30))
    Singleton.sharedInstance.ScoreLabel.center = CGPoint(x: view.frame.size.width/1.6 , y: view.frame.size.height/2.5)
    Singleton.sharedInstance.ScoreLabel.text = "\(Singleton.sharedInstance.Score)"
    Singleton.sharedInstance.ScoreLabel.textColor = UIColor.whiteColor()
    self.view?.addSubview(Singleton.sharedInstance.ScoreLabel)

    HighScoreLabel = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3, height: 30))
    HighScoreLabel.center = CGPoint(x: view.frame.size.width/1.6 , y: view.frame.size.height/2)
    HighScoreLabel.textColor = UIColor.whiteColor()
    HighScoreLabel.text = "\(HighScore)"
    self.view?.addSubview(HighScoreLabel)

    GameOverLabel = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3.8, height: 30))
    GameOverLabel.center = CGPoint(x: view.frame.size.width/2 , y: view.frame.size.height/10)
    GameOverLabel.textColor = UIColor.whiteColor()
    GameOverLabel.text = "Game Over"
    self.view?.addSubview(GameOverLabel)

}

func Restart(){
    self.view?.presentScene(GameScene(), transition: SKTransition.crossFadeWithDuration(0.3))
    RestartButton.removeFromSuperview()
    HighScoreLabel.removeFromSuperview()
    Singleton.sharedInstance.ScoreLabel.removeFromSuperview()
    GameOverLabel.removeFromSuperview()

}
}

I guess a new question would be if there is something else I need to do in order to make the singleton method work from scene to scene other than change the names of the variables 我想一个新的问题是,是否需要做其他事情以使单例方法在场景之间工作,而不是更改变量的名称。

Where do you call DisplayGameScore() ? 您在哪里调用DisplayGameScore()? (you don't) (你不)

Other then that, this is no so good 除此之外,这不是很好

static let ScoreLabel = Singleton()
static let Score = Singleton()

you created two instances of Singleton which is wrong 您创建了两个Singleton实例,这是错误的

and then you have instance variable with the same name ScoreLabel which is also not so good 然后你有一个实例名称相同的实例变量ScoreLabel也不是很好

As others have said you create 2 singletons. 正如其他人所说,您创建了2个单例。

To use it correctly you should only do this in your singleton class 要正确使用它,您应该只在单例课程中这样做

static let sharedInstance = Singelton()

And than to use your score property or other properties/methods in your game scenes you would say this 而不是在游戏场景中使用分数属性或其他属性/方法,您会这样说

Singleton.sharedInstance.score++ 
Singleton.sharedInstance.scoreLabel ...
Singleton.sharedInstance.displayGameScore()

You could also write it like this in GameScene 您也可以在GameScene中这样写

 let singleton = Singleton.sharedInstance
 singleton.score++
 singleton.scoreLabel...
 singleton.displayGameScore()

As a side note it's best practice to write your properties/methods like this 附带说明一下,最佳做法是编写这样的属性/方法

var score...
func displayGameScore()...

not

var Score....
func DisplayGameScore() ...

As another side note you should probably use SpriteKit Apis if you use it, so instead of UILabel you should use SKLabelNodes. 另一方面,如果使用SpriteKit Apis,则可能应该使用SpriteKit Apis,因此应使用SKLabelNodes代替UILabel。 Furthermore the display gameScore method can probably go into your GameScene and than you just reference the score property from your Singleton. 此外,display gameScore方法可能可以进入您的GameScene中,而不仅仅是引用Singleton中的score属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM