Help me find a way to make the lasers fire in a certain direction.
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)
Think about what should happen when you lifr your finger. Remember,
updategets called 60 times per second.
Do you want the existing lasers to keep moving? Or move only when your finger is down, and freeze when your finger is up.
I would suggest rewriting your update function as follows, to make it easier for you to follow:
def update(self): self.handle_button_presses() self.move_lasers()
Your touch handling code then moves to one method, and other game logic moves to their own functions, and get called from
update. For example, eventually you might be moving enemies or asteroids or the map. You might be spawning enemies at certain intervals, which would also be it's own method. Thus, you would create a
move_enemiesmethods, maybe a
scroll_mapif this is scroller type game, perhaps a
check_collisionswhich checks if the player hit any obstacles or enemies, etc. You should be able to write your entire
updatemethod using dummy methods that sort of lay out what you need to work in, and can implement the methods one at a time, since they should all be mostly independent of each other, just depending on a common set of attributes or positions.
I want my existing lasers to keep on moving. I have also implemented your idea of rewriting my update function.
I really don’t know how to though. If I use a touch.began method, it runs once, but stays in it’s place.
Am I forgetting to add something?
Okay, let's try this again.
If you want your laser to move, the movement code must be called EVERY time update is called. There should be no if statements around the for loop that moves the lasers.
In your old code the laser loop was inside the if statement that checked for the laser button touch. That's why it doesn't move when your finger is up. You will need to update your loop because the
directionvariable that you use for moving the lasers must be define inside the loop, because it can be different for every laser. You'll need to grab the laser rotation for each laser to figure that out.
Post your new updated 5 line update method. And post your update_laser_postions function or whatever you called it.
if random.random() < 0.01:
def handle_button_presses(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/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*3/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) def move_lasers(self): for touch in self.touches.values(): if touch.location in self.laserButton.bbox: new_laser = SpriteNode('shp:Circle') new_laser.x_scale = 0.25/1.0 new_laser.y_scale = 0.25/1.0 new_laser.position = self.Player.position new_laser.rotation = self.Player.rotation 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
This post is deleted!last edited by
for l in self.lasers: l.position += direction*75
That is the code that moves a laser beam, right?
In words, can you explain under what conditions this code runs?
Does that code execute EVERY time update is called, or is there some logic that controls when it will run?
Hint, look above it for any for loops or if statements.
This post is deleted!last edited by
The code runs whenever the laser button detects that someone has touched it.
@BurntRice but you told me that you want lasers to MOVE even when someone is not currently touching the button.
So, you must move the MOVE code out from inside the
for touch in self.touchesloop.
Your code has two parts:
- Create a new laser object when person touches the button
- Move all of the existing lasers
The first part should only happen when user is touching the button.
The second part should happen always.
for l in self.laserscode. Now, write new movement code inside a new function, which you will call from
update. You will need to redefine
directioninside your loop -- it is not the same direction variable that is used inside your creation code. for now, hardcod
direction=Vector2(0,1)just so you can get something to work. Later you will use the laser rotation to determine direction.
I’m still working on it, but I added this:
def update_lasers(self): for l in self.lasers: l.direction = Vector2(0,1) l.rotation = self.Player.rotation l.position = l.position + l.direction
I just want to check if I’m getting side tracked or not.
When a laser is moving, it should move based on IT's rotation,not the player rotation. You might move after the laser gets fired, but you want the laser to go straight.
So delete the line updating the rotation. The rotation was set when you spawn the laser.
This code should work, but of course the laser always goes in one direction. So next, you can redefine
directionusing the l.rotation, similar to the way you calculated it when you spawn the laser
I think I’ve finally done it! It works, as it shoots in the way I want it, and keeps on travelling even when I haven’t touched it, thanks.
All I have to do is add a action so I can’t spam or hold down on the button. What is the best way to add this?
Also, I would also like to know how to code screen wrapping.
player.location.x %= screen.width player.location.y %= screen.height
Wait, how do find the screen width and height? And what about location?
how do find the screen width and height
ui.get_screen_size() --> width,height
Re spamming, one approach is, in your button handling code, to keep track of self.t, and self.lastfire_time. When current time minus last fire time is > some value, reset the last fire time to current time, and fire a laser. Otherwise, pass
BTW, in your laser loop, you will need to check if the laser is off screen (not in self.bounds), then delete the object from the scene. Otherwise your scene will eventually bog down or crash because it is moving millions of laser objects.
This could also be done in your check_collisions method where you see if your lasers hit your enemies.
@cvp And what about location?
position, not location.
If you want to wrap, you need to fundamentally change your button logic, since you check limits