omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Help me find a way to make the lasers fire in a certain direction.

    Pythonista
    7
    66
    16997
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • BurntRice
      BurntRice last edited by ccc

      I need the type of code so that depending on which direction button was pressed last, the lasers fires in that direction. My code so far only shoots in a positive x axis. I need it to shoot in negative x axis, and positive and negative y axis as well.
      Here is my code so far:

      from scene import *
      import turtle 
      import ui 
      import math
      import random
      A = Action()
      #Setting up background colour for the entire scene
      class Game(Scene):
          
          def setup(self):
              self.bg = SpriteNode('spc:BackgroundBlack')
              self.lasers = []
              
              #Creating the player
              self.Player = SpriteNode('shp:RoundRect')
              self.Player.color = ("cyan")
              self.Player.anchor_point = (0.5, 0)
              self.Player.position = (512, 400)
              self.add_child(self.Player)
              
              #Controlling the player
              self.UpCrtl = SpriteNode('iow:arrow_up_b_32')
              self.UpCrtl.x_scale = 3.5/1.0
              self.UpCrtl.y_scale = 3.5/1.0
              self.UpCrtl.alpha = 0.5
              self.UpCrtl.position = (175, 295)
              self.add_child(self.UpCrtl)
              
              self.DownCrtl = SpriteNode('iow:arrow_down_b_32')
              self.DownCrtl.x_scale = 3.5/1.0
              self.DownCrtl.y_scale = 3.5/1.0
              self.DownCrtl.alpha = 0.5
              self.DownCrtl.position = (175, 130)
              self.add_child(self.DownCrtl)
              
              self.RightCrtl = SpriteNode('iow:arrow_right_b_32')
              self.RightCrtl.x_scale = 3.5/1.0
              self.RightCrtl.y_scale = 3.5/1.0
              self.RightCrtl.alpha = 0.5
              self.RightCrtl.position = (250, 212.5)
              self.add_child(self.RightCrtl)
              
              self.LeftCrtl = SpriteNode('iow:arrow_left_b_32')
              self.LeftCrtl.x_scale = 3.5/1.0
              self.LeftCrtl.y_scale = 3.5/1.0
              self.LeftCrtl.alpha = 0.5
              self.LeftCrtl.position = (100, 212.5)
              self.add_child(self.LeftCrtl)
              
              #The button for shooting
              self.laserButton = SpriteNode('shp:Circle')
              self.laserButton.color = ('gray')
              self.laserButton.x_scale = 3/1
              self.laserButton.y_scale = 3/1
              self.add_child(self.laserButton)
              self.laserButton.position = (1000, 212.5)
              
          def update(self):
              for touch in self.touches.values():
                  if touch.location in self.LeftCrtl.bbox:
                      #left button pressed
                      new_x = self.Player.position.x - 5
                      if new_x >= 0 and new_x <= 1100:
                          self.Player.position = (new_x, self.Player.position.y)
                          
                  if touch.location in self.RightCrtl.bbox:
                          #right button pressed
                      new_x = self.Player.position.x + 5
                      if new_x >= 0 and new_x <= 1100:
                          self.Player.position = (new_x, self.Player.position.y)
                  
                  if touch.location in self.UpCrtl.bbox:
                      new_y = self.Player.position.y + 5
                      if new_y >= 0 and new_y <= 800:
                          self.Player.position = (self.Player.position.x, new_y)
                      
                  if touch.location in self.DownCrtl.bbox:
                      new_y = self.Player.position.y - 5
                      if new_y >= 0 and new_y <= 800:
                          self.Player.position = (self.Player.position.x, new_y)
      
                  if touch.location in self.laserButton.bbox:
                      new_laser = SpriteNode('spc:LaserBlue6')
                      new_laser.position = (self.Player.position.x, self.Player.position.y + 60)
                      self.add_child(new_laser)
                      self.lasers.append(new_laser)
      
              for l in self.lasers:
                  l.position = (l.position.x, l.position.y + 7.5)
                  if l.position.y > 800:
                      l.remove_from_parent()
                      self.lasers.remove(l)
      
      
      if __name__ == '__main__':
          run(Game(), LANDSCAPE, show_fps=True)
      
      1 Reply Last reply Reply Quote 0
      • BurntRice
        BurntRice last edited by

        Also, if you can add code for creating a scrolling background, that would be pretty good to (or adding a link to a previous forum).

        1 Reply Last reply Reply Quote 0
        • JonB
          JonB last edited by JonB

          The code that defines how the lasers move is here

          l.position = (l.position.x, l.position.y + 7.5)
          

          So, you can see that if you want a laser to move in a different direction,you will need another field to your lasers objects (might I suggest direction), which you would add to l.position. You might need to subclass SpriteNode,I forget if SpriteNodes let you add new attributes. if direction is a Vector2 object(or maybe Point2D, whatever class position is), you can simply add

          l.position = l.position + l.direction
          

          An alternative, if your laser is a "beam" instead of a circle, you could set rotation, then use rotation to both display the sprite, and decide which way to move - either with a bunch of if statements, or if you know trigonometry, you can use sin and cos of rotation (converted to radians) to compute the direction of motion.

          Then, obviously, you need to change the code that spawns the laser to set a direction and/or rotation field, and also change the code that deles each laser when it falls off the screen, since you now need to check 3 or 4 edges, not just y.

          1 Reply Last reply Reply Quote 0
          • BurntRice
            BurntRice last edited by ccc

            Why won’t this work?

            from scene import *
            import turtle 
            import ui 
            import math
            import random
            A = Action()
            direction = 1
            #Setting up background colour for the entire scene
            class Game(Scene):
                def setup(self):
                    self.bg = SpriteNode('spc:BackgroundBlack')
                    self.lasers = []
                    
                    #Creating the player
                    self.Player = SpriteNode('shp:RoundRect')
                    self.Player.color = ("cyan")
                    self.Player.anchor_point = (0.5, 0)
                    self.Player.position = (512, 400)
                    self.add_child(self.Player)
                    
                    #Controlling the player
                    self.UpCrtl = SpriteNode('iow:arrow_up_b_32')
                    self.UpCrtl.x_scale = 3.5/1.0
                    self.UpCrtl.y_scale = 3.5/1.0
                    self.UpCrtl.alpha = 0.5
                    self.UpCrtl.position = (175, 295)
                    self.add_child(self.UpCrtl)
                    
                    self.DownCrtl = SpriteNode('iow:arrow_down_b_32')
                    self.DownCrtl.x_scale = 3.5/1.0
                    self.DownCrtl.y_scale = 3.5/1.0
                    self.DownCrtl.alpha = 0.5
                    self.DownCrtl.position = (175, 130)
                    self.add_child(self.DownCrtl)
                    
                    self.RightCrtl = SpriteNode('iow:arrow_right_b_32')
                    self.RightCrtl.x_scale = 3.5/1.0
                    self.RightCrtl.y_scale = 3.5/1.0
                    self.RightCrtl.alpha = 0.5
                    self.RightCrtl.position = (250, 212.5)
                    self.add_child(self.RightCrtl)
                    
                    self.LeftCrtl = SpriteNode('iow:arrow_left_b_32')
                    self.LeftCrtl.x_scale = 3.5/1.0
                    self.LeftCrtl.y_scale = 3.5/1.0
                    self.LeftCrtl.alpha = 0.5
                    self.LeftCrtl.position = (100, 212.5)
                    self.add_child(self.LeftCrtl)
                    
                    #The button for shooting
                    self.laserButton = SpriteNode('shp:Circle')
                    self.laserButton.color = ('gray')
                    self.laserButton.x_scale = 3/1
                    self.laserButton.y_scale = 3/1
                    self.add_child(self.laserButton)
                    self.laserButton.position = (1000, 212.5)
            
                def update(self):
                    for touch in self.touches.values():
                        if touch.location in self.LeftCrtl.bbox:
                            #left button pressed
                            direction = 4
                            new_x = self.Player.position.x - 5
                            if new_x >= 0 and new_x <= 1100:
                                self.Player.position = (new_x, self.Player.position.y)
                                
                        if touch.location in self.RightCrtl.bbox:
                            #right button pressed
                            direction = 2
                            new_x = self.Player.position.x + 5
                            if new_x >= 0 and new_x <= 1100:
                                self.Player.position = (new_x, self.Player.position.y)
                        
                        if touch.location in self.UpCrtl.bbox:
                            direction = 1
                            new_y = self.Player.position.y + 5
                            if new_y >= 0 and new_y <= 800:
                                self.Player.position = (self.Player.position.x, new_y)
                            
                        if touch.location in self.DownCrtl.bbox:
                            direction = 3
                            new_y = self.Player.position.y - 5
                            if new_y >= 0 and new_y <= 800:
                                self.Player.position = (self.Player.position.x, new_y)
                                
                        if touch.location in self.laserButton.bbox:
                            new_laser = SpriteNode('spc:LaserBlue6')
                            new_laser.position=(self.Player.position.x,self.Player.position.y + 6)
                            self.add_child(new_laser)
                            self.lasers.append(new_laser)
            
                        for l in self.lasers:
                            if direction() = 1:
                            l.position = (l.position.x, l.position.y + 75)
                            if direction() = 2:
                                l.position = (l.position.x + 75, l.position.y)
                                if.direction() = 3:
                                    l.position = (l.position.x, l.position.y - 75)
                                    if direction() = 4:
                                        l.position = (l.position.x + 75, l.position.y)
            
            if __name__ == '__main__':
                run(Game(), LANDSCAPE, show_fps=True)
            
            1 Reply Last reply Reply Quote 0
            • JonB
              JonB last edited by

              What do you think

              if direction() = 1:
              

              refers to? Where have you defined a function named direction? Are you attempting to compare the value of direction with 1, or assign the value 1 to direction?

              Even if you fix the fundamental issues so that the code runs without error (this code likely is throwing Name error or maybe complaining about Callable, or AttributeError), it won't do what you want. Instead, it will make all lasers in the screen move in the direction you are holding the button.

              Like I said, you either need to define a laser class that includes a direction at the time it is spawned, or you need to use an Action to move the laser (which you would spawn and run once, when the laser is created, with a move_to the final point on the screen, over a fixed time, in which case you don't need to manage the laser positions at all on your own)

              1 Reply Last reply Reply Quote 0
              • ccc
                ccc last edited by ccc

                if direction == 1: # use ==, not = !!!

                1 Reply Last reply Reply Quote 0
                • BurntRice
                  BurntRice last edited by

                  Um, who is correct out of you two?
                  Your two comments kinda contradict each other.

                  1 Reply Last reply Reply Quote 0
                  • ccc
                    ccc last edited by ccc

                    @JonB 's question was: Should it be direction() as a function or direction as a variable? I suspect the latter so drop the ().

                    @ccc 's suggestion was: Use ==, not = to test equality in an if statement.

                    Both are important for correctness.

                    I would recommend that you run the Analyze (pyflakes) command accessible under the wrench menu. It flags exactly the same line of code that @JonB flagged above. Pyflakes is a subset of flake8 but it can still highlight some of these issues.

                                for laser in self.lasers:
                                    if direction == 1:
                                        laser.position.y += 75
                                    elif direction == 2:
                                        laser.position.x += 75
                                    elif direction == 3:
                                        laser.position.y -= 75
                                    elif direction == 4:
                                        laser.position.x -= 75
                    
                    1 Reply Last reply Reply Quote 0
                    • JonB
                      JonB last edited by

                      @ccc unless he is trying to steer the lasers, your code won't work either. He needs to capture the direction that the ship is moving when the laser gets spawned, and keep track of that along with the laser object. Or use sprite rotation to define the direction of motion.

                      1 Reply Last reply Reply Quote 1
                      • BurntRice
                        BurntRice last edited by

                        Have any of you actually tested the code or not?
                        I’ve got two half done codes for each scenario, so can you just quickly test it @ccc? I’m quite slow, and very busy with other work (got a deadline in the next 3 days, and I’m only half-way). If you get back to me then I can just focus on one strong effort.

                        1 Reply Last reply Reply Quote 0
                        • JonB
                          JonB last edited by JonB

                          Your code was untestable, because you provided code with syntax errors, that could not even run. You will probably get better results asking for help when it seems like you have even tried your code, and have made any attempt to diagnose it. If you are getting an error, you should mention that.

                          I did get your code to run, and behave in a logical way, as follows:

                          1. Moved the lasers update loop to the right indent level (you dont want to do that for every touch), and remived all of the if statements, since they were garbage and not properly indented
                            2) Used self.Player.rotation to define a persistent direction of last motion. Had you gotten through your syntax error, you would have noticed another immediate error, that direction was not defined, because of course, it is a local variable that only is defined during a touch, and so when you lift your finger off the direction button, it will fail. Presuamably what you want is for the direction buttons to rotate the player, and laser direction based on player rotation. Here it helps to define a player sprite that has some directionality, like one of the spc:PlayerShipxxx, but once you choose a sprite, you will use 0, math.pi/2, math.pi, and math.pi*3/2 as your four directions. You likely will want your anchor point to be 0.5,0.5. By trial and error, you will figure out which rotation is appropriate for each drirection.
                            3) Using player rotation now lets you set the laser rotation equal to Player.rotation. That takes care of drawing the laser properly.

                          2. I found it convienent to compute a Vector2
                            direction = Vector2(-math.sin(new_laser.rotation), math.cos(new_laser.rotation))
                            Depending in how you define your rotations, you might need to swap the sin and cos, and or change signs, if the laser moves in the wrong direction. how you define those rotations depend on the sprite you use for your player.
                            Then, you can simply offset the position by a scaled version of this,
                            l.position += direction*75
                            or
                            new_laser.position = self.Player.position + direction*6
                            etc
                            Vector2 is very useful like that. You could also use it to simplify your movement code in the same way

                          1 Reply Last reply Reply Quote 1
                          • JonB
                            JonB last edited by

                            other comments:
                            You are spawning lasers at 60 per second when the button is touched, then moving them at 4500 pixels per second. Consider storing a variable that has the last time a laser was fired, then check self.t is greater than that time plus some lock out time. Or, use touch_began only as the method for firing lasers, rather than update (which gets called at 60 fps), so feverishly tapping the button can make lasers appear faster.

                            You can also use run_action with an Action.Sequence consisting of Action.move_by the laser by a few thousand pixels in the desired direction over some time that defines the speed, then removes it from the scene. The animation looks much smoother when you use Actions

                            1 Reply Last reply Reply Quote 0
                            • BurntRice
                              BurntRice last edited by ccc

                              Whenever, I press the laser button, the laser just goes to far left-hand side and goes up no matter what. I think its due to the fact that I haven’t implemented your tips correctly however.

                              from scene import *
                              import math
                              A = Action()
                              
                              
                              #Setting up background colour for the entire scene
                              class Game(Scene):
                                  
                                  def setup(self):
                                      self.bg = SpriteNode('spc:BackgroundBlack')
                                      self.lasers = []
                                      
                                      #Creating the player
                                      self.Player = SpriteNode('shp:RoundRect')
                                      self.Player.color = ("cyan")
                                      self.Player.anchor_point = (0.5, 0.5)
                                      self.Player.position = (512, 400)
                                      self.Player.rotation = 0.0
                                      self.add_child(self.Player)
                                      
                                      self.UpCrtl = SpriteNode('iow:arrow_up_b_32')
                                      self.UpCrtl.x_scale = 3.5/1.0
                                      self.UpCrtl.y_scale = 3.5/1.0
                                      self.UpCrtl.alpha = 0.5
                                      self.UpCrtl.position = (175, 295)
                                      self.add_child(self.UpCrtl)
                                      
                                      self.DownCrtl = SpriteNode('iow:arrow_down_b_32')
                                      self.DownCrtl.x_scale = 3.5/1.0
                                      self.DownCrtl.y_scale = 3.5/1.0
                                      self.DownCrtl.alpha = 0.5
                                      self.DownCrtl.position = (175, 130)
                                      self.add_child(self.DownCrtl)
                                      
                                      self.RightCrtl = SpriteNode('iow:arrow_right_b_32')
                                      self.RightCrtl.x_scale = 3.5/1.0
                                      self.RightCrtl.y_scale = 3.5/1.0
                                      self.RightCrtl.alpha = 0.5
                                      self.RightCrtl.position = (250, 212.5)
                                      self.add_child(self.RightCrtl)
                                      
                                      self.LeftCrtl = SpriteNode('iow:arrow_left_b_32')
                                      self.LeftCrtl.x_scale = 3.5/1.0
                                      self.LeftCrtl.y_scale = 3.5/1.0
                                      self.LeftCrtl.alpha = 0.5
                                      self.LeftCrtl.position = (100, 212.5)
                                      self.add_child(self.LeftCrtl)
                                      
                                      #The button for shooting
                                      self.laserButton = SpriteNode('shp:Circle')
                                      self.laserButton.color = ('gray')
                                      self.laserButton.x_scale = 3/1
                                      self.laserButton.y_scale = 3/1
                                      self.add_child(self.laserButton)
                                      self.laserButton.position = (1000, 212.5)
                                      
                                      #The score label
                                      self.score_label = LabelNode(text='Score: 0')
                                      self.score_label.anchor_point = (0, -300)
                                      self.score_label.position = (20, 718)
                                      self.score_label.font = ('Arial Rounded MT Bold', 30)
                                      self.add_child(self.score_label)
                              
                              
                                  #Movement code.
                                  def update(self):
                                      for touch in self.touches.values():
                                          if touch.location in self.LeftCrtl.bbox:
                                              new_x = self.Player.position.x - 5
                                              self.Player.rotation = math.pi*3/2
                                              if new_x >= 0 and new_x <= 1100:
                                                  self.Player.position = (new_x, self.Player.position.y)
                                                  
                                          if touch.location in self.RightCrtl.bbox: 
                                              new_x = self.Player.position.x + 5
                                              self.Player.rotation = math.pi/2
                                              if new_x >= 0 and new_x <= 1100:
                                                  self.Player.position = (new_x, self.Player.position.y)
                                          
                                          if touch.location in self.UpCrtl.bbox:
                                              new_y = self.Player.position.y + 5
                                              self.Player.rotation = 0.0
                                              if new_y >= 0 and new_y <= 800:
                                                  self.Player.position = (self.Player.position.x, new_y)
                                              
                                          if touch.location in self.DownCrtl.bbox: 
                                              new_y = self.Player.position.y - 5
                                              self.Player.rotation = math.pi
                                              if new_y >= 0 and new_y <= 800:
                                                  self.Player.position = (self.Player.position.x, new_y)
                                                  
                                          if touch.location in self.laserButton.bbox:
                                              new_laser = SpriteNode('spc:LaserBlue6')
                                              direction = Vector2(-math.sin(new_laser.rotation), math.cos(new_laser.rotation))
                                              self.add_child(new_laser)
                                              self.lasers.append(new_laser)
                                                          
                                              for l in self.lasers:
                                                  l.position += direction*75
                              
                                      
                              if __name__ == '__main__':
                                  run(Game(), LANDSCAPE, show_fps=True)
                              
                              1 Reply Last reply Reply Quote 0
                              • ccc
                                ccc last edited by

                                random, turtle, and ui are imported but not used which slows down startup and uses more memory.

                                A = Action() is created but not used which slows down startup and uses more memory.

                                self.laserButton = SpriteNode('shp:Circle') is created twice which slows down startup, uses more memory, and makes it confusing which instance is being clicked on.

                                Please reread and follow @JonB advise above.

                                1 Reply Last reply Reply Quote 1
                                • JonB
                                  JonB last edited by JonB

                                  If you want help, you need to explain what the problem is, what you have tried. For instance you might start by saying "help, my lasers now don't even spawn in the right position" to which someone might ask (maybe even you), gee, did you remember to set the laser position when you spawned it?

                                  Or you might be wondering why the laser w only move when you are touching the button. In which case one could respond that you maybe didn't fix the indentation as previously mentioned. The act of typing out "for some reason my lasers only move when I am touching the fire button" might make you look at the code that moves your lasers, or look at the code that runs when the fire button is pressed.

                                  You might be wondering "hey, I updated the code to use direction, but all lasers seem to use the direction from when the button was pressed", which would allow someone to point out that if you want to use it in your laser update loop, it needs to be defined inside said loop (using the rotation of the looped laser object), or store it as an attribute of the laser object.

                                  I would encourage you to try to understand your own code before asking for help. Then you can be specific about what you tried, what debugging you added in to understand the program flow, or what you think should be happening vs what is actually happening.

                                  1 Reply Last reply Reply Quote 2
                                  • BurntRice
                                    BurntRice last edited by

                                    Whenever I press the shoot button, lasers fire down on the far left-hand side of the screen, and only go up. I am not getting any immediate errors, so I am investigating into the math.

                                    1 Reply Last reply Reply Quote 0
                                    • BurntRice
                                      BurntRice last edited by

                                      I think its due to the fact that I haven’t implemented your tips correctly however.

                                      1 Reply Last reply Reply Quote 0
                                      • BurntRice
                                        BurntRice last edited by

                                        I have assigned so the new_laser.rotation is = to the player rotation, this results in lasers popping on sides, not the right sides because I probably have to switch the math.pi equations around, but they are not moving.

                                        1 Reply Last reply Reply Quote 0
                                        • JonB
                                          JonB last edited by JonB

                                          Move the for l in self.lasers loop to the proper indentation level. This should not be inside any of the touch handling code.

                                          You will then use the l.rotation to set the motion direction.

                                          Also, you will eventually need code that deletes lasers once they are off screen ( in that loop, check if laser.bbox is in self.bbox)

                                          1 Reply Last reply Reply Quote 0
                                          • BurntRice
                                            BurntRice last edited by

                                            Um, sorry? I don’t really understand. I have properly indented the for l in self.lasers part, I don’t know how to add l.rotation to set motion direction.

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors