Combining the missile tutorial with the joystick tutorial for a shooting game

Home Forums Swift and Sprite Kit Combining the missile tutorial with the joystick tutorial for a shooting game

This topic contains 12 replies, has 2 voices, and was last updated by  gage kolman 6 months, 3 weeks ago.

  • May 10, 2016 at 6:44 pm #149677

    I’m trying to combine your joystick tutorial with your missile tutorial. I understand and have spawned bullets based on the Z rotation and angles but how do you spawn a bullet while the joystick is held down (which would be defined in a touches began) then update the bullet spawn location when the joystick is moved? since the joystick rotation is declared in a touches moved function how do you spawn and move a bullet based on that location since when you’re creating your spawn bullet function you can’t spawn it based on the zRotation and/or angle because you haven’t defined those yet? i noticed in your rotation video you used a UIRotationGestureRecognizer which can be defined for the entire class since it is already programmed as a UITouch/tapped whatever, as apposed to a joystick defined in a touches moved and or touches began. should i make my joystick it’s own class with its own touches began and touches moved? If so how do i go about that? Ive spent quite a while trying to find solutions to this only to find a solution that creates a different problem :(. Btw love the vids.you articulate quite well when explaining things, you break down pretty intimidating concepts into quick and easy to follow videos

  • May 10, 2016 at 7:29 pm #149679

    Thanks Gage!

    Obviously, there’s a few ways to tackle this, but you could just keep a separate Bool variable like isFiring and flip that to true or false depending on whether touchesBegan was triggered or touchesEnded was. Then you could move some of the firing code over to the update statement and if its true, fire away. So that way the firing is independent from the touchesMoved statement. But it could still be used to rotate the turret, just not fire it.

    Make sense?

    • May 11, 2016 at 1:55 pm #149701

      Thank you for your help! It made sense, i created a bool called fireWeapon and a run block method in my touches began and touches moved, however how would i go about my update method? Since there is no method to call because my bullet spawn location was defined in my touches moved. Could you maybe edit my code just a little? I’ve been stuck on this for a while 🙁

      
      override func touchesBegan(touches: Set<UITouch>, withEvent event:UIEvent?) {
      
              for touch in touches {
      
                  let location = touch.locationInNode(self)
                  let node = nodeAtPoint(location)
      
                  if (CGRectContainsPoint(joystick.frame, location)) {
      
                      stickActive = true
                      fireWeapon = true
                  }else{
      
                      stickActive = false
                  }
      
                  if stickActive == true && fireWeapon == true{  if fireWeapon == false {}
                      
                  let bulletAction = SKAction.runBlock({
                  let v = CGVector(dx: location.x - self.joystickBase.position.x, dy:     
                  location.y - self.joystickBase.position.y)
                  let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
                  let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and 
                  generates a degree when touchesMoved == true
                   
                   print(deg + 180) // prints degree in debugging
                   self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy 
                   stick
      
                      let bullet1:Bullet1 = Bullet1()
                      bullet1.createBullet1()
                  
             bullet1.position = CGPoint (x: self.hero.position.x , y: self.hero.position.y)   
             // Bullet spawn @ anchor point
      
             let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
             let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location
      
               bullet1.position = CGPointMake( self.hero.position.x - xDist, 
               self.hero.position.y + yDist) //spawning bullet @ defined location
                      
               let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x distance
               let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y distance
                      
               let bulletMovementY = SKAction.moveToY(self.hero.position.y + yDistMove, 
               duration: 1) //Bullet y speed
               let bulletMovementX = SKAction.moveToX(self.hero.position.x - xDistMove, 
               duration: 1) //Bullet x speed
      
               bullet1.runAction(bulletMovementY)
               bullet1.runAction(bulletMovementX)
                          
               self.addChild(bullet1)
                      })
      
               let wait = SKAction.waitForDuration(0.25)
               let completeSequence = SKAction.sequence([bulletAction, wait])
               let repeatShootingActionForever =
               SKAction.repeatActionForever(completeSequence)
               self.runAction(repeatShootingActionForever, withKey: "BulletAction")
                  }
                  
                  if stickActive == false{
                      
                      fireWeapon = false
                  }}}
      
       override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
      
              for touch in touches {
      
                  let location = touch.locationInNode(self)
      
                  if stickActive == true && fireWeapon == true{  if fireWeapon == false {}
                     
                    let v = CGVector(dx: location.x - joystickBase.position.x, dy: 
                    location.y - joystickBase.position.y)
                    let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
                    let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and 
                    generates a degree when touchesMoved == true
                    let length: CGFloat = joystickBase.frame.size.height / 2 //sets maximum 
                    distance for joystick ball
                    print(deg + 180) // prints degree in debugging
      
                      joystick.position = location
                 self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy stick
                 let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
                 let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location
                      
                      bullet1.position = CGPointMake( self.hero.position.x - xDist, 
                      self.hero.position.y + yDist) //spawning bullet @ defined location
                      
               let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x distance
               let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y distance
                      
                let bulletMovementY = SKAction.moveToY(self.hero.position.y + yDistMove, \    
                duration: 1) //Bullet y speed
                let bulletMovemenX = SKAction.moveToX(self.hero.position.x - xDistMove, 
                duration: 1) //Bullet x speed
      
                bullet1.runAction(bulletMovementY)
                bullet1.runAction(bulletMovemenX)
      
                if (CGRectContainsPoint(joystickBase.frame, location)) {
      
                  }else{
      
                          let xDist:CGFloat = sin(angle - 1.5709633) * length 
                          let yDist:CGFloat = cos(angle - 1.5709633) * length 
      
                joystick.position = CGPointMake(joystickBase.position.x - xDist, 
                joystickBase.position.y + yDist)
      
                    }
                  }
                }
              }
      

      this method works kinda-ish, the problem I’m having is that i can’t figure out a way to change the spawn location of the bullet when the joystick is moved, with this method the bullet spawns in the direction of the first click and does not update when the joystick is moved around. Which makes sense because you said i need to call something in my update method, how do i do that? Oh and the create bullet class is about the same as your create enemy missile class so i thought it was redundant to add. Thanks for your help! i appreciate it so much

    • May 13, 2016 at 1:18 pm #149783

      Can you paste in what you have in the update function?

  • May 13, 2016 at 1:41 pm #149784

    By the way, there’s a little code box you can use to pretty up any code you paste. Just click it before and after whatever you paste in. I retro-fitted your code up there =)

    Also the update func is in every Sprite Kit project by default. It looks like…

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

    Just in case you weren’t sure what I meant. Keep in mind, that runs about 60 frames per second, so you wouldn’t want to add a new bullet every frame, though that would look cool, it would be like a flame thrower. But you could do a few things to limit how often new bullets are added. One would be to just keep a variable ticking upwards and whenever it gets to a certain number, you fire. So in your class declare something like

    var bulletCounter:Int = 0

    Then in the update func….

    
      override func update(currentTime: CFTimeInterval) {
            
    if (bulletCounter >= 60) {
    
    bulletCounter = 0 //reset after 60 frames
    //fire bullet (add child, etc)
    
    } else {
    bulletCounter += 1  //increment the variable 
    
    }
    
        }
    
    • May 13, 2016 at 2:17 pm #149787

      Yes, I have an update method but nothing inside for the bullet spawn method. If you use the update method for bullet spawn instead of the run block method i used every 0.25 seconds, would that limit me to only one fire rate? 1 bullet per second?

  • May 13, 2016 at 2:24 pm #149788

    No, you can decide how often the bullet is added based on how quickly that bulletCounter variable is reset. So for example, 60 would be every second. 30 would be every half second. And so on.

    • May 13, 2016 at 8:52 pm #149808

      ok, hopefully, last question lol. How to I update the spawn location of the bullet? since you’re saying i need to add the child in the update function. However i need to add the bullet1 child in the same method where i define the angle of the joystick. Otherwise i get an error saying use of undeclared identifier “angle” because i defined angle in my touches moved and touches began. Your idea makes sense I’m just trying to make it work

  • May 13, 2016 at 9:10 pm #149809

    Yup, you’re getting there. Just declare angle and any other variables you need outside of the touches function. Which is why you declare variables for all functions to use. =)

    • May 14, 2016 at 3:09 pm #149848

      Ok, how do you define the angle for the whole class? for

      let v = CGVector(dx: location.x - base.position.x, dy: location.y -
      base.position.y)
      let angle = atan2(v.dy, v.dx)
      let deg = angle * CGFloat( 180 / M_PI)

      More specifically how do you define the CGvector? because you can’t use location or joystick base to define the x and y values of the vector

  • May 16, 2016 at 12:02 pm #149889

    Here’s how you would declare those…

    class GameScene: SKScene {
        
        
        var v:CGVector = CGVector(dx: 0,dy: 0)
        var angle:CGFloat = 0
        var deg:CGFloat = 0
    
    //any other declared variables
    
        

    Then those lines just need to remove the let part where they are currently at. Oh and change CGVector to CGVectorMake ….

    v = CGVectorMake(dx: location.x - base.position.x, dy: location.y -
    base.position.y)
    angle = atan2(v.dy, v.dx)
    deg = angle * CGFloat( 180 / M_PI)

    That way you aren’t creating new ones, you’re using the previously declared ones.

    • May 16, 2016 at 2:38 pm #149892

      thank you so much! You don’t know how much time you saved me i was scratching my head for a few days lol, Ill recommend your website as well 🙂

    • May 16, 2016 at 5:52 pm #149896

      It worked! I used your timer method which was called by a bool value in the update method, and because i defined angle for the whole class i was able to use the same angle for the spawn location in a separate bullet method. thank you so much!

You must be logged in to reply to this topic.