Astrum Astrum - 1 month ago 7
Swift Question

scoring system counting multiple times

My Goal: To achieve a scoring system that only counts when a level unit is behind the player once and therefore if the player goes back it doesn’t count the same one twice

I currently have a scoring system that adds one to the score label every time I tap my player to go forward in my game, this has its flaws as the player can go backwards and then tap to go forward which would count onto the score again if the player went backwards then forwards.

I came up with the idea to count how many platforms(LevelUnits) are behind the player so that if they go back it won’t count the same platform(LevelUnit) twice when they decide to go forward again.

This is what I came up with:

override func update(_ currentTime: TimeInterval) {

let scoreLabel = childNode(withName: "scoreLabel") as! Score // links the scorelabel with Score class

worldNode.enumerateChildNodes(withName: "levelUnit") {
node, stop in

let nodeLocation:CGPoint = self.convert(node.position, from: self.worldNode) //converts cordinates of level units with the world node.
let player1Location:CGPoint = self.convert(self.thePlayer.position, from: self.worldNode)

if (nodeLocation.y < (player1Location.y) - self.levelUnitHeight ) { // checks to see if the node is behind the player's position

self.countLevelUnits += 1
}

if (self.countLevelUnits > scoreLabel.number) {

while self.countLevelUnits > scoreLabel.number {

scoreLabel.addOneToScore()

}

} else if (self.countLevelUnits < scoreLabel.number) {

// Do Nothing

}
}
}


The only problem is that because they’re constantly behind the player the code counts it multiple times and continues to do so unless I turn off the game. Is there a way to just count the LevelUnits behind the player once for each one that goes behind the players position?

EDIT 1: LEVEL UNIT CLASS

class LevelUnit:SKNode {

//General Level Unit and Object Variables
var imageName:String = ""
var levelUnitSprite:SKSpriteNode = SKSpriteNode()
var levelUnitWidth:CGFloat = 0
var levelUnitHeight:CGFloat = 0
var theType:LevelType = LevelType.normal
let thePlayer:Player = Player(imageNamed: "Frog")
var levelUnitPicker = 0
var levelUnitsSpawned = 0

var levelUnitScored:Bool = false

required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override init () {

super.init()
}


func setUpLevel(){

imageName = “Wall”

let theSize:CGSize = CGSize(width: levelUnitWidth, height: levelUnitHeight) //defines the size background sprite as defined by the height and width of level unit
let tex:SKTexture = SKTexture(imageNamed: imageName) //defines the testue that the backgroundsprite will have.

levelUnitSprite = SKSpriteNode(texture: tex, color: SKColor.black, size: theSize)
scoredLevelUnit = false

self.addChild(levelUnitSprite) //adds the level unit to the scene
self.name = "levelUnit" //names the whole backgroundsprite under the name level Unit

self.position = CGPoint(x: levelUnitSprite.size.width / 2, y: 0)


//The Level Types Physics Body
if (theType == LevelType.blank) {

levelUnitSprite.physicsBody = SKPhysicsBody(rectangleOf: levelUnitSprite.size)

levelUnitSprite.physicsBody!.categoryBitMask = BodyType.normal.rawValue
levelUnitSprite.physicsBody!.contactTestBitMask = BodyType.normal.rawValue
levelUnitSprite.physicsBody!.isDynamic = false


} else if (theType == LevelType.normal) {

levelUnitSprite.physicsBody = SKPhysicsBody(rectangleOf: levelUnitSprite.size)

levelUnitSprite.physicsBody!.categoryBitMask = BodyType.normal.rawValue
levelUnitSprite.physicsBody!.contactTestBitMask = BodyType.normal.rawValue
levelUnitSprite.physicsBody!.isDynamic = false


} else if (theType == LevelType.floating) {

levelUnitSprite.physicsBody = SKPhysicsBody(rectangleOf: levelUnitSprite.size)

levelUnitSprite.physicsBody!.categoryBitMask = BodyType.floating.rawValue
levelUnitSprite.physicsBody!.contactTestBitMask = BodyType.floating.rawValue
levelUnitSprite.physicsBody!.isDynamic = false
}


}

Answer

If you use a custom subclass for your level unit, you can easily add a Bool property scored; when you "score" this object, set scored = true, then next time you can check if scored == true and not score it again

override func update(_ currentTime: TimeInterval) {      

  let scoreLabel = childNode(withName: "scoreLabel") as! Score // links the scorelabel with Score class

  worldNode.enumerateChildNodes(withName: "levelUnit") {
      node, stop in

        if let levelNode = node as? LevelUnit
            let nodeLocation:CGPoint = self.convert(levelNode.position, from: self.worldNode)   //converts cordinates of level units with the world node.
            let player1Location:CGPoint = self.convert(self.thePlayer.position, from: self.worldNode)

             if (nodeLocation.y < (player1Location.y) - self.levelUnitHeight ) { // checks to see if the node is behind the player's position
                 if !levelNode.levelUnitScored {
                     scoreLabel.addOneToScore()
                     levelNode.levelUnitScored = true
                 }
             }
         }
    }
}