1
votes

I am making a space ship game in which enemy ships spawn and move towards the player.

I want the enemy space ships to fire bullets every x seconds. I tried using an SKAction that was implemented inside of the villain method but it does not work.

I think if I could get the enemy ship node location I could do it but I can't since the enemy ship node is in a function and I can't get its location outside of the function.

This is the bullet method:

func Laser(){

    let LaserBullet = SKSpriteNode(imageNamed: "Laser")

    //Physics World
    LaserBullet.physicsBody = SKPhysicsBody(rectangleOf: LaserBullet.size)
    LaserBullet.physicsBody?.categoryBitMask = NumberingPhysics.Laser
    LaserBullet.physicsBody?.contactTestBitMask = NumberingPhysics.UpperV | NumberingPhysics.YellowUpper | NumberingPhysics.UpperBlue
    LaserBullet.physicsBody?.affectedByGravity = false
    LaserBullet.physicsBody?.isDynamic = true
    LaserBullet.zPosition = 1
    LaserBullet.position = CGPoint(x: SpaceShip.position.x, y: SpaceShip.position.y). // I can put the villains location here if I can get it but I don't know how  

    let LaserThrown = SKAction.moveTo(y: frame.maxY + SpaceShip.size.height, duration: 1)

    let LaserEnded = SKAction.removeFromParent()

    run(LaserSound)
    addChild(LaserBullet)
    LaserBullet.run(SKAction.sequence([LaserThrown,LaserEnded]))
}

This is the Enemy method:

func RedSpawn(){
    let VillainR = Villain()

    VillainR.zPosition = 2

    VillainR.zRotation = CGFloat(Double.pi)

    let min = 0 + VillainR.size.width
    let max = self.frame.width - VillainR.size.width

    let spawn = UInt32(max-min)

    VillainR.position = CGPoint(x: CGFloat(arc4random_uniform(spawn)),y: self.size.height)

    let movement = SKAction.moveTo(y: self.frame.minY + 20, duration: 6.5)
    let remove = SKAction.removeFromParent()

    VillainR.run(SKAction.sequence([movement,remove]))

    //Physics World
    VillainR.physicsBody = SKPhysicsBody(rectangleOf: VillainR.size)
    VillainR.physicsBody?.categoryBitMask = NumberingPhysics.UpperV
    VillainR.physicsBody?.contactTestBitMask = NumberingPhysics.Laser | NumberingPhysics.SpaceShip
    VillainR.physicsBody?.affectedByGravity = false
    VillainR.physicsBody?.isDynamic = true
    VillainR.physicsBody?.collisionBitMask = 0

    addChild(VillainR)
}

And this is the enemy class (I don't think you guys need this):

public class Villain: SKSpriteNode {  
    var life = 1   //Number of lives for the red villain
    var hitThisFrame = false    //Not used

   init(){
     let texture = SKTexture(imageNamed: "Villain")
     // print("number of lives: ", life)
     super.init(texture: texture, color: SKColor.clear, size: texture.size())
   }

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

I tried searching everywhere but I cannot find the answer.

Thank You In Advance !!

1

1 Answers

0
votes

If I got you, you want that every X seconds a random spawnRed will executed. as I see in your code your spawnRed position is a random value (at least the x position value). I suggest you to use SKAction, here is my idea.

your villains function should be like this (Setting and creating the villains is separate function):

func villains(){
let VillainR = Villain()

VillainR.zPosition = 2

VillainR.zRotation = CGFloat(Double.pi)

let min = 0 + VillainR.size.width
let max = self.frame.width - VillainR.size.width

let spawn = UInt32(max-min)

VillainR.position = CGPoint(x: CGFloat(arc4random_uniform(spawn)),y: self.size.height)

//Physics World
VillainR.physicsBody = SKPhysicsBody(rectangleOf: VillainR.size)
VillainR.physicsBody?.categoryBitMask = NumberingPhysics.UpperV
VillainR.physicsBody?.contactTestBitMask = NumberingPhysics.Laser | NumberingPhysics.SpaceShip
VillainR.physicsBody?.affectedByGravity = false
VillainR.physicsBody?.isDynamic = true
VillainR.physicsBody?.collisionBitMask = 0

let m = SKAction.moveTo(y: self.frame.minY + 20, duration: 6.5)
let remove = SKAction.removeFromParent()
VillainR.run(SKAction.sequence([movement,remove]))

addChild(VillainR)
}

and for the repeated SKAction I think you should set it inside your didMove() func or as a another function that will executed inside the didMove() func, I prefer to set it in different function because of comfort and aesthetics:

    func spawnReds() {
    let wait = SKAction.wait(forDuration: 3) //the time in seconds between each action
    let action = SKAction.run {
    self.villains() //create a villain
    }
    run(SKAction.repeatForever((SKAction.sequence([wait, action])))) // repeat this action forever = the villains function will executed every 3 seconds, which means that every 3 seconds a new villains will shout.

}

if you do it in separate function you should call the function inside your didMove, like this:

override func didMove(to view: SKView) {
spawnReds()
}

you can look at apple doc for more info.