SpriteKit - Creating a timer - ios

How can I create a timer that fires every two seconds that will increment the score by one on a HUD I have on my screen? This is the code I have for the HUD:
#implementation MyScene
{
int counter;
BOOL updateLabel;
SKLabelNode *counterLabel;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
counter = 0;
updateLabel = false;
counterLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
counterLabel.name = #"myCounterLabel";
counterLabel.text = #"0";
counterLabel.fontSize = 20;
counterLabel.fontColor = [SKColor yellowColor];
counterLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
counterLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeBottom;
counterLabel.position = CGPointMake(50,50); // change x,y to location you want
counterLabel.zPosition = 900;
[self addChild: counterLabel];
}
}

In Sprite Kit do not use NSTimer, performSelector:afterDelay: or Grand Central Dispatch (GCD, ie any dispatch_... method) because these timing methods ignore a node's, scene's or the view's paused state. Moreover you do not know at which point in the game loop they are executed which can cause a variety of issues depending on what your code actually does.
The only two sanctioned ways to perform something time-based in Sprite Kit is to either use the SKScene update: method and using the passed-in currentTime parameter to keep track of time.
Or more commonly you would just use an action sequence that starts with a wait action:
id wait = [SKAction waitForDuration:2.5];
id run = [SKAction runBlock:^{
// your code here ...
}];
[node runAction:[SKAction sequence:#[wait, run]]];
And to run the code repeatedly:
[node runAction:[SKAction repeatActionForever:[SKAction sequence:#[wait, run]]]];
Alternatively you can also use performSelector:onTarget: instead of runBlock: or perhaps use a customActionWithDuration:actionBlock: if you need to mimick the SKScene update: method and don't know how to forward it to the node or where forwarding would be inconvenient.
See SKAction reference for details.
UPDATE: Code examples using Swift
Swift 5
run(SKAction.repeatForever(SKAction.sequence([
SKAction.run( /*code block or a func name to call*/ ),
SKAction.wait(forDuration: 2.5)
])))
Swift 3
let wait = SKAction.wait(forDuration:2.5)
let action = SKAction.run {
// your code here ...
}
run(SKAction.sequence([wait,action]))
Swift 2
let wait = SKAction.waitForDuration(2.5)
let run = SKAction.runBlock {
// your code here ...
}
runAction(SKAction.sequence([wait, run]))
And to run the code repeatedly:
runAction(SKAction.repeatActionForever(SKAction.sequence([wait, run])))

In Swift usable:
var timescore = Int()
var actionwait = SKAction.waitForDuration(0.5)
var timesecond = Int()
var actionrun = SKAction.runBlock({
timescore++
timesecond++
if timesecond == 60 {timesecond = 0}
scoreLabel.text = "Score Time: \(timescore/60):\(timesecond)"
})
scoreLabel.runAction(SKAction.repeatActionForever(SKAction.sequence([actionwait,actionrun])))

I've taken the swift example above and added in leading zeros for the clock.
func updateClock() {
var leadingZero = ""
var leadingZeroMin = ""
var timeMin = Int()
var actionwait = SKAction.waitForDuration(1.0)
var timesecond = Int()
var actionrun = SKAction.runBlock({
timeMin++
timesecond++
if timesecond == 60 {timesecond = 0}
if timeMin / 60 <= 9 { leadingZeroMin = "0" } else { leadingZeroMin = "" }
if timesecond <= 9 { leadingZero = "0" } else { leadingZero = "" }
self.flyTimeText.text = "Flight Time [ \(leadingZeroMin)\(timeMin/60) : \(leadingZero)\(timesecond) ]"
})
self.flyTimeText.runAction(SKAction.repeatActionForever(SKAction.sequence([actionwait,actionrun])))
}

Here's the full code to build a timer for SpriteKit with Xcode 9.3 and Swift 4.1
In our example the score label will be incrementd by 1 every 2 seconds.
Here's final result
Good, let's start!
1) The score label
First of all we need a label
class GameScene: SKScene {
private let label = SKLabelNode(text: "Score: 0")
}
2) The score label goes into the scene
class GameScene: SKScene {
private let label = SKLabelNode(text: "Score: 0")
override func didMove(to view: SKView) {
self.label.fontSize = 60
self.addChild(label)
}
}
Now the label is at the center of the screen. Let's run the project to see it.
Please note that at this point the label is not being updated!
3) A counter
We also want to build a counter property which will hold the current value displayed by the label. We also want the label to be updated as soon as the counter property is changed so...
class GameScene: SKScene {
private let label = SKLabelNode(text: "Score: 0")
private var counter = 0 {
didSet {
self.label.text = "Score: \(self.counter)"
}
}
override func didMove(to view: SKView) {
self.label.fontSize = 60
self.addChild(label)
// let's test it!
self.counter = 123
}
}
4) The actions
Finally we want to build an action that every 2 seconds will increment counter
class GameScene: SKScene {
private let label = SKLabelNode(text: "Score: 0")
private var counter = 0 {
didSet {
self.label.text = "Score: \(self.counter)"
}
}
override func didMove(to view: SKView) {
self.label.fontSize = 60
self.addChild(label)
// 1 wait action
let wait2Seconds = SKAction.wait(forDuration: 2)
// 2 increment action
let incrementCounter = SKAction.run { [weak self] in
self?.counter += 1
}
// 3. wait + increment
let sequence = SKAction.sequence([wait2Seconds, incrementCounter])
// 4. (wait + increment) forever
let repeatForever = SKAction.repeatForever(sequence)
// run it!
self.run(repeatForever)
}
}

The following code creates a new thread and waits 2 seconds before doing something on the main thread:
BOOL continueIncrementingScore = YES;
dispatch_async(dispatch_queue_create("timer", NULL);, ^{
while(continueIncrementingScore) {
[NSThread sleepForTimeInterval:2];
dispatch_async(dispatch_get_main_queue(), ^{
// this is performed on the main thread - increment score here
});
}
});
Whenever you want to stop it - just set continueIncrementingScore to NO

Related

How to setup collisions correctly in SceneKit?

I'm facing a problem with collision detection.
Current setup
1) I extended ViewController class with SCNPhysicsContactDelegate:
class ViewController: UIViewController, SCNPhysicsContactDelegate
2) I setup an OptionSet to manage collision categories:
// Collisions
struct CollisionCategory: OptionSet {
let rawValue: Int
static let CoinsCategory = CollisionCategory(rawValue: 0) // Coin SCNNode
static let CarCategory = CollisionCategory(rawValue : 1) // Car SCNNode
static let FinishLineCategory = CollisionCategory(rawValue: 2) // FinishLine SCNNode
}
3) I setup categoryBitMask, contactTestBitMask and collisionBitMask of all of them:
// Setup car
carNode.physicsBody?.categoryBitMask = CollisionCategory.CarCategory.rawValue
carNode.physicsBody?.contactTestBitMask = CollisionCategory.CoinsCategory.rawValue | CollisionCategory.FinishLineCategory.rawValue
carNode.physicsBody?.collisionBitMask = CollisionCategory.CoinsCategory.rawValue | CollisionCategory.FinishLineCategory.rawValue
// Setup finishLine
planeNode.physicsBody?.categoryBitMask = CollisionCategory.FinishLineCategory.rawValue
planeNode.physicsBody?.contactTestBitMask = CollisionCategory.CarCategory.rawValue
planeNode.physicsBody?.collisionBitMask = CollisionCategory.CarCategory.rawValue
// Setup coin
coin.physicsBody?.categoryBitMask = CollisionCategory.CoinsCategory.rawValue
coin.physicsBody?.contactTestBitMask = CollisionCategory.CarCategory.rawValue
coin.physicsBody?.collisionBitMask = CollisionCategory.CarCategory.rawValue
4) I setup physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) to manage collision when they happen:
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
if(contact.penetrationDistance >= 0.08 && contact.nodeB.name!.contains("Coin")) {
// Remove coin from parent
contact.nodeB.removeFromParentNode()
// Increment counter
self.coinsCounter += 1
DispatchQueue.main.async {
// Increase coin counter
let view = self.arSceneView.viewWithTag(10) as! UILabel
view.text = String(self.coinsCounter)
}
}
// PROBLEMS HERE
if(contact.penetrationDistance >= 0.076 && contact.nodeB.name!.contains("FinishLine") && !self.startFinishLineCollision && !self.outOfTrack) {
self.startFinishLineCollision = true
// Increment lap
if(seconds > 10) {
self.laps += 1
DispatchQueue.main.async {
(self.arSceneView.viewWithTag(14) as! UILabel).text = String(self.laps)
}
if(self.laps == 4){
endGame()
}
}
}
}
Problem
I need to check when car touches finish line to mark a lap and increment the lap counter by 1. The problem is that I'm getting continuously contact messages from this function between nodeA and nodeB, even if there is no collision between car and finish line.
For example, in the following image there is a collision message, but there isn't an effective collision between car and finish line.
What is wrong with the current setup?
What I need
I need to check if there is a collision between car and finishline with precision.
Thank you
Update
I tried the following setup too, with no solution...
let CoinsCategory = 2
let CarCategory = 4
let FinishLineCategory = 6
carNode.physicsBody?.categoryBitMask = CarCategory
carNode.physicsBody?.collisionBitMask = CoinsCategory | FinishLineCategory
planeNode.physicsBody?.categoryBitMask = FinishLineCategory
planeNode.physicsBody?.collisionBitMask = CarCategory
coin.physicsBody?.categoryBitMask = CoinsCategory
coin.physicsBody?.collisionBitMask = CarCategory
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
switch contact.nodeB.physicsBody!.collisionBitMask {
case FinishLineCategory:
print("Finish Line Collision")
case CoinsCategory:
print("Coin Collision")
default:
print("Other collision")
}
}
No prints are called... It's like there is no collision between objects.
NOTE: finishline, car and coins are all children on the the same parent (the plane below them). Is it relevant?
Ok, I found a workaround to workaround my issue:
1) I used a coin (yellow cube) as collider.
2) I setup it with Color.clear (transparent color) in such a way as to make it invisible.
3) I placed it the center of the finish line.
4) Since contactTest is not working, I used penetrationDistance:
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
if(contact.penetrationDistance >= 0.08 && contact.nodeB.name! == "Coin") {
// Remove coin from parent
contact.nodeB.removeFromParentNode()
// Increment counter
self.coinsCounter += 1
DispatchQueue.main.async {
// Increase coin counter
let view = self.arSceneView.viewWithTag(10) as! UILabel
view.text = String(self.coinsCounter)
}
}
// >>>>> NEW CODE HERE! <<<<<
if(contact.penetrationDistance > 0.078 && contact.nodeB.name! == "CoinFinishLine" && !self.outOfTrack && !self.lapIncrement) {
self.lapIncrement = true
// Start lap increment timer (5 seconds)
self.startNSecondsTimer(howMuchTime: 1.0, target: 1)
// Increment lap
if(seconds > 10) {
self.laps += 1
DispatchQueue.main.async {
(self.arSceneView.viewWithTag(14) as! UILabel).text = String(self.laps)
}
if(self.laps == 3){
endGame()
}
}
}
}
Anyhow, if someone can explain me why I can't get contactTestBitMask to work and I can use only collisionBitMask with this solution is welcome. Thank you

Why can't I call a function in function update?

Please help me! Im trying to call a function I have declared in the GameScene class, within the update function. But it doesn't recognise the function, I'm wondering if this is something to do with the class or something because I want to run the function every frame (but has to update for each individual spriteCopy, depending on its own movement) to make sure the sprite copies all follow the function and continue to, infinitely.
Thank you in advance for any help.
here is the code for the function that sort of works to an extent:
func touchUp(atPoint pos : CGPoint) {
if let spriteCopy = self.sprite?.copy() as! SKShapeNode? {
spriteCopy.fillColor = UIColor.white
spriteCopy.position = initialTouch
spriteCopy.physicsBody?.restitution = 0.5
spriteCopy.physicsBody?.friction = 0
spriteCopy.physicsBody?.affectedByGravity = false
spriteCopy.physicsBody?.linearDamping = 0
spriteCopy.physicsBody?.angularDamping = 0
spriteCopy.physicsBody?.angularVelocity = 0
spriteCopy.physicsBody?.isDynamic = true
spriteCopy.physicsBody?.categoryBitMask = 1 //active
spriteCopy.isHidden = false
touchUp = pos
xAxisLength = initialTouch.x - touchUp.x
yAxisLength = initialTouch.y - touchUp.y
xUnitVector = xAxisLength / distanceBetweenTouch * power * 300
yUnitVector = yAxisLength / distanceBetweenTouch * power * 300
spriteCopy.physicsBody?.velocity = CGVector(dx: xUnitVector, dy: yUnitVector)
func directionRotation() {
if let body = spriteCopy.physicsBody {
if (body.velocity.speed() > 0.01) {
spriteCopy.zRotation = body.velocity.angle()
}
}
}
directionRotation() //When I run the function with this line, the spriteCopy
//is spawned initially with the right angle (in the direction
//of movement) but doesn't stay updating the angle
sprite?.isHidden = true
self.addChild(spriteCopy)
}
}
and here is the function not being recognised in function update:
override func update(_ currentTime: TimeInterval) {
directionRotation() //this line has error saying "use of unresolved identifier"
// Called before each frame is rendered
}
EDIT: I was thinking maybe there could be a way to spawn multiple spriteCopy's without the "copy()" method that will not restrict the access to the spriteCopy's properties after they have been spawned? Whilst remembering they still must have to be individual SpriteNodes so that the directionRotation function could be applied independently to each of them (FYI: The user can spawn upwards of 50+ sprite nodes)
You have specified local function. You need move out from touchUp function realisation directionRotation
func directionRotation() {
if let body = spriteCopy.physicsBody {
if (body.velocity.speed() > 0.01) {
spriteCopy.zRotation = body.velocity.angle()
}
}
}
func touchUp(atPoint pos : CGPoint) {
...
}
EDIT
I mean you need do some think like this:
func directionRotation(node:SKNode) {
if let body = node.physicsBody {
if (body.velocity.speed() > 0.01) {
node.zRotation = body.velocity.angle()
}
}
}
override func update(_ currentTime: TimeInterval) {
for node in self.children
{
directionRotation(node)
}
}

swift - game countdown timer almost working

I'm using script (below), to use as a countdown for my game start, the script I've used is from Gourav Nayyar's YouTube video and works great for the first time it is called. However once the game goes through the reset process and the script is called again I only see 5 rather than 5 - 4 - 3 - 2 - 1 - GO!. If I remove one of the cals from my script then it works fine either in the reset func or when gameScene loads.
Here is the two calls in GameScene.swift
override func didMoveToView(view: SKView) {
var gamelaunchTimerView:TimerView = TimerView.loadingCountDownTimerViewInView(self.view!)
gamelaunchTimerView.startTimer()
func resetScene() {
//code removed from here
return countdown()
}
func countdown() {
var gamelaunchTimerView:TimerView = TimerView.loadingCountDownTimerViewInView(self.view!)
gamelaunchTimerView.startTimer()
}
Here is the Timer Code in GameLaunchTimer.swift as this is set up the countdown only works when first called and hangs on the second call.
//
// TimerView.swift
// GameLaunchTimer
//
// Created by Gourav Nayyar on 7/3/14.
// Copyright (c) 2014 Gourav Nayyar. All rights reserved.
//
let VIEW_ALPHA:CGFloat = 0.5
let TIMERVIEW_RADIUS:CGFloat = 50
let TIMER_LABEL_INITIAL_VAL:Int = 5
let BORDER_WIDTH:CGFloat = 2
var timerVal:Int = TIMER_LABEL_INITIAL_VAL;
var timer:NSTimer!
import UIKit
import QuartzCore
class TimerView :UIView {
struct Stored {
static var timerLbl:UILabel!
}
class func loadingCountDownTimerViewInView (_superView:UIView)-> TimerView
{
var timerView:TimerView = TimerView(frame:_superView.frame)
// timerView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(VIEW_ALPHA)
_superView.addSubview(timerView)
/* add a custom Circle view */
let refFrame:CGRect = CGRectMake(_superView.center.x-TIMERVIEW_RADIUS, _superView.center.y-TIMERVIEW_RADIUS, 2*TIMERVIEW_RADIUS, 2*TIMERVIEW_RADIUS)
var circleView:UIView = UIView(frame:refFrame)
circleView.layer.cornerRadius = TIMERVIEW_RADIUS
circleView.layer.borderColor = UIColor.whiteColor().CGColor
circleView.layer.borderWidth = BORDER_WIDTH
/* add a custom Label */
Stored.timerLbl = UILabel(frame:circleView.bounds)
Stored.timerLbl.text = "\(TIMER_LABEL_INITIAL_VAL)"
Stored.timerLbl.textColor = UIColor.whiteColor()
Stored.timerLbl.font = UIFont(name: "MarkerFelt-Thin", size: 40)
Stored.timerLbl.textAlignment = NSTextAlignment.Center
circleView.addSubview(Stored.timerLbl)
timerView.addSubview(circleView)
return timerView
}
func startTimer()
{
timer = NSTimer.scheduledTimerWithTimeInterval(1.0
, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
}
func updateTimer(dt:NSTimer)
{
timerVal--
if timerVal==0{
Stored.timerLbl.text = "GO!"
}else if timerVal<0{
timer.invalidate()
removeCountDownTimerView()
} else{
Stored.timerLbl.text = "\(timerVal)"
}
}
func removeCountDownTimerView()
{
var mySuperView:UIView = self.superview!
mySuperView.userInteractionEnabled = true
super.removeFromSuperview()
}
}
Define your variables under the class body;
import UIKit
import QuartzCore
class TimerView :UIView {
let VIEW_ALPHA:CGFloat = 0.5
let TIMERVIEW_RADIUS:CGFloat = 50
let TIMER_LABEL_INITIAL_VAL:Int = 5
let BORDER_WIDTH:CGFloat = 2
var timerVal:Int = TIMER_LABEL_INITIAL_VAL;
var timer:NSTimer!
... // other code
or, may be
let VIEW_ALPHA:CGFloat = 0.5
let TIMERVIEW_RADIUS:CGFloat = 50
let TIMER_LABEL_INITIAL_VAL:Int = 5
let BORDER_WIDTH:CGFloat = 2
import UIKit
import QuartzCore
class TimerView :UIView {
var timerVal:Int = TIMER_LABEL_INITIAL_VAL;
var timer:NSTimer!
... //other code
Assign nil to the timer after invalidating it: even though you are invalidating, the object state is still kept, resulting on states conflicts when creating a new instance of the timer, once that it runs in a different thread.

How do I increment and save a int value in Swift?

Im trying to keep track of how many times the user loses in my game. So for every loss it goes up by 1. I also want to save it too so the user could see how many total times they lost. Right now the code I have it works the first time and goes to one but if I lose in the game after that it just stays at 1. What am I doing wrong? Thanks!
class level1: SKScene, SKPhysicsContactDelegate, GKGameCenterControllerDelegate {
var deathScore = 0
override func didMoveToView(view: SKView) {
var deathLabel = SKLabelNode()
deathLabel = SKLabelNode(fontNamed: "LadyIce-3D")
deathLabel.text = "100"
deathLabel.zPosition = 14
deathLabel.fontSize = 100
deathLabel.fontColor = SKColor.darkTextColor()
deathLabel.position = CGPointMake(self.size.width / 1.1, self.size.height / 1.4)
deathLabel.hidden = true
self.addChild(deathLabel)
}
if firstBody.categoryBitMask == HeroCategory && fourthBody.categoryBitMask == GameOverCategory {
deathScore++
deathLabel.hidden = false
let defaults = NSUserDefaults()
let saveDeaths = NSUserDefaults().integerForKey("saveNumberOfDeaths")
if(deathScore > saveDeaths)
{
NSUserDefaults().setInteger(saveDeaths, forKey: "saveNumberOfDeaths")
}
var showNumberOfDeaths = defaults.integerForKey("saveNumberOfDeaths")
deathLabel.text = String(showNumberOfDeaths)
}
}
You are declaring a new var deathScore everytime, initialized with 0 and incrementing it. It will always be 1.
UserDefaults.standard.set(UserDefaults.standard.integer(forKey: "saveNumberOfDeaths")+1, forKey: "saveNumberOfDeaths")
deathLabel.text = String(UserDefaults.standard.integer(forKey: "saveNumberOfDeaths"))

How do I make my enemySprite respawn as new bad guy once its been killed?

I am having trouble with my game, I've managed to have my enemySprites all shoot at the hero in a synchronized matter and I've gotten them to play the "killed" animation once they've been hit. Although I've run into a rather small matter which I was really hoping you guys could help me with. The problem I have is that when my badGuy is killed they move off the screen and I don't know how I can program it so that a 'new' badGuy appears forever until the Hero sprite is killed.
This is my function to spawn my enemy:
func spawnEnemy(targetSprite: SKNode) -> SKSpriteNode {
if !gamePaused{
// create a new enemy sprite
let main = GameScene()
newEnemy = SKSpriteNode(imageNamed:"BNG1_1.png")
enemySprite.append(newEnemy)//ADD TO THE LIBRARY OF BADGUYS
newEnemy.xScale = 1.2
newEnemy.yScale = 0.6
newEnemy.physicsBody?.dynamic = true
newEnemy.physicsBody = SKPhysicsBody(texture: newEnemy.texture, size: newEnemy.size)
newEnemy.physicsBody?.affectedByGravity = false
newEnemy.physicsBody?.categoryBitMask = BodyType.badguyCollision.rawValue
newEnemy.physicsBody?.contactTestBitMask = BodyType.beamCollison.rawValue
newEnemy.physicsBody?.collisionBitMask = 0x0
let muv : UInt32 = (200 + (arc4random()%500))
let actualDuration = NSTimeInterval(random(min: CGFloat(3.0), max: CGFloat(4.0)))
let randomNum = CGPoint(x:Int (muv), y:Int (arc4random()%500))
// Create the actions
var actionMove = SKAction.moveTo(randomNum, duration: NSTimeInterval(actualDuration))
newEnemy.runAction(SKAction.sequence([actionMove]))
// position new sprite at a random position on the screen
var posX = arc4random_uniform(UInt32(sizeRect.size.width))
var posY = arc4random_uniform(UInt32(sizeRect.size.height))
newEnemy.position = CGPoint(x: screenSize.width*2 + newEnemy.size.width, y: random(min: newEnemy.size.height, max: screenSize.height - newEnemy.size.height))
let atlas = SKTextureAtlas(named: "BG1.atlas")
let anime = SKAction.animateWithTextures([atlas.textureNamed("BG1_1.png"), atlas.textureNamed("BG1_2.png"),
atlas.textureNamed("BG1_3.png"),
atlas.textureNamed("BG1_2.png"),
atlas.textureNamed("BG1_1.png")], timePerFrame: 0.1)
dinoRun = SKAction.repeatActionForever(anime)
newEnemy.runAction(dinoRun)
}
return newEnemy
}
And this is my function for once they are hit (this function is called when the collisionTest between my hero's laser and the badguy is recognized):
func deadBadGuy(){
//animation
var dinoRun:SKAction
var newdes = CGPoint(x: Int(arc4random()%500), y:0)
var actionMoov = SKAction.moveTo(newdes, duration: 3)
var goaway = SKAction.removeFromParent()
let aTlas = SKTextureAtlas(named: "dedBG.atlas")
let anime = SKAction.animateWithTextures([aTlas.textureNamed("deadBG1.png"), aTlas.textureNamed("deadBG2.png"),
aTlas.textureNamed("deadBG3.png"),
aTlas.textureNamed("deadBG2.png"),
aTlas.textureNamed("deadBG1.png")], timePerFrame: 0.1)
dinoRun = SKAction.repeatActionForever(anime)
newEnemy.runAction(dinoRun)
newEnemy.runAction(SKAction.sequence([actionMoov,goaway]))
score++
self.scoreNode.text = String(score)
enemySprites.newPlace(neewEnemy)
dead = true //i created this Boolean because the sprite keeps shooting even if its dead
}
This is the way I called for the collisionTest in my program in case you need it for more information:
func didBeginContact(contact:SKPhysicsContact){
if !gamePaused {
let firstNode = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch(firstNode){
case BodyType.beamCollison.rawValue | BodyType.badguyCollision.rawValue:
deadBadGuy()
//enemySprites.spawnEnemy(sprite)
default:
print("hit")
}
Note: I tried having the func spawnEnemy being called during the collisionTest but that results in the BadGuy staying off screen shooting at my hero.
Update : I found out how to add a new enemy sprite once the other is dead all i had to do was
newEnemy.runAction(SKAction.sequence([actionMoov,goaway]), completion: {
self.addChild(self.enemySprites.spawnEnemy(sprite))
})
in the deadBadGuy function(the spawnEnemy function is in another class which I named enemySprites as a variable). However now I've run into a new issue and that is that it adds 10 enemySprites instead of one. How can I change that?
Update 2 : I figured out that issue too, I just needed to remove to dead Boolean method in the deadBadGuy function.
I found my answer and all I had to do was add this line to my deadBadGuy function and remove the dead boolean methods
newEnemy.runAction(SKAction.sequence([actionMoov,goaway]), completion: {
self.addChild(self.enemySprites.spawnEnemy(sprite))
})

Resources