Cal_9000
Cal_9000

Reputation: 57

Moving two objects on a canvas in separate loops

I'm having trouble getting these two objects to move on my canvas. Once one shot is fired it stops the movement of the other object. I'm pretty sure it's because I'm using two while loops and python can't handle that. Is there any way to get around that/ include it in the same loop?

Ive tried using the self.canvas.after () command, but every time i shoot the bullet it goes faster than the time before.

from tkinter import *
import time

class Game:
    def __init__(self):

        #creating the static canvas background
        window = Tk()
        window.title('Shoot your friends')
        self.canvas = Canvas(width= 900,
                          height= 900,
                          cursor= 'circle')
        self.canvas.pack()

        self.canvas.create_line(450, 900,
                           450, 0, 
                           dash = (10))

        self.p1_ship = PhotoImage(file = "red_ship.gif")
        self.p2_ship = PhotoImage(file = "blue_ship.gif")
        self.p1_laser = PhotoImage(file = "red_laser.gif")
        self.p2_laser = PhotoImage(file = "blue_laser.gif")        

        #Buttons at the bottom
        frame = Frame(window)
        frame.pack()

        #Determining the state of edge teleporting and toggling it
        self.etb = True
        def et():
            if self.etb == True:               
                self.etb = False
                Et["text"] = "Turn On Edge Teleporting"
            else:
                self.etb = True
                Et["text"] = "Turn Off Edge Teleporting"

            print ("Edge Telepoting Toggled")


        Et = Button(frame, text="Turn Off Edge Teleporting", command = et, cursor= 'double_arrow')
        Et.grid(row=0,column=0)

        self.Rfb = False
        def rf():
            if self.Rfb == True:               
                self.Rfb = False
                Rf["text"] = "Turn On Rapid Fire "
            else:
                self.Rfb = True
                Rf["text"] = "Turn Off Rapid Fire"

            print ("Rapid Fire Toggled")


        Rf = Button(frame, text="Turn On Rapid Fire", command = rf, cursor= 'cross')
        Rf.grid(row=0,column=1)

        def restart():
            print ('restart')
        restart_b = Button(frame, text="Restart Game", command = restart, fg='Blue', bg= 'red', cursor='exchange' )
        restart_b.grid(row=0,column=2)

        self.y_p1 = 400
        self.y_p2 = 400

        self.ship_p1 = self.canvas.create_image(40, 450, image=self.p1_ship)             
        self.ship_p2 = self.canvas.create_image(860, 450, image=self.p2_ship) 



        self.canvas.move(self.ship_p1,0,0)
        self.canvas.move(self.ship_p2,0,0)



        #For example If edge teleporting is ON the ship will teleport to the top of the screen if it is at the bottom and the down key is pressed and vice versa
        #My implementation of this may not be the most efficient but I like the options it gives me for adding future features and it looks cool.
        def p1_up(event):
            if self.etb == True and self.y_p1 >= 100:
                self.canvas.move(self.ship_p1,0,-100)
                self.y_p1 += -100                
            elif self.etb == True:
                self.canvas.move(self.ship_p1,0,+800)
                self.y_p1 += +800                
            elif self.y_p1 >= 100:
                self.canvas.move(self.ship_p1,0,-100)
                self.y_p1 += -100


        def p1_down(event):
            if self.etb == True and self.y_p1 <= 799:
                self.canvas.move(self.ship_p1,0,+100)
                self.y_p1 += 100                
            elif self.etb == True:
                self.canvas.move(self.ship_p1,0,-800)
                self.y_p1 += -800
            elif self.y_p1 <= 799:
                self.canvas.move(self.ship_p1,0,+100)
                self.y_p1 += 100


        def p2_up(event):
            if self.etb == True and self.y_p2 >= 100:
                self.canvas.move(self.ship_p2,0,-100)
                self.y_p2 += -100  
            elif self.etb == True:
                self.canvas.move(self.ship_p2,0,+800)
                self.y_p2 += +800
            elif self.y_p2 >= 100:
                self.canvas.move(self.ship_p2,0,-100)
                self.y_p2 += -100


        def p2_down(event):
            if self.etb == True and self.y_p2 <= 799:
                self.canvas.move(self.ship_p2,0,+100)
                self.y_p2 += 100
            elif self.etb == True:
                self.canvas.move(self.ship_p2,0,-800)
                self.y_p2 += -800
            elif self.y_p2 <= 799:
                self.canvas.move(self.ship_p2,0,+100)
                self.y_p2 += 100

        # Functions for shooting
        #self.canvas.move(self.shot_p1,0,0)




        #self.laser_p1 = self.canvas.create_image(50, self.y_p1 +50, image=self.p1_laser)
        #self.laser_p2 = self.canvas.create_image(850, self.y_p2 +50, image=self.p2_laser)
        self.p1_shot_out = False
        self.p2_shot_out = False

        def p1_shoot(event):

            if self.p1_shot_out == True:  
                self.canvas.delete(self.laser_p1)
            #draws the laser    
            self.laser_p1 = self.canvas.create_image(50, self.y_p1 +50, image=self.p1_laser)
            self.x_p1_laser = 50
            self.p1_shot_out = True

            time.sleep(.009)
            p1_shoot_move()


        def p1_shoot_move():
            #moves the laser until its outside the canvas
            while self.x_p1_laser <= 900:
                self.canvas.move(self.laser_p1,5,0)
                self.x_p1_laser += 5 
                self.canvas.update()
                time.sleep(.009)


        def p2_shoot(event):
            if self.p2_shot_out == True:
                self.canvas.delete(self.laser_p2)
            #draws the laser
            self.laser_p2 = self.canvas.create_image(750, self.y_p2 +50, image=self.p2_laser)
            self.x_p2_laser = 750
            self.p2_shot_out = True

            time.sleep(.009)
            p2_shoot_move()


        def p2_shoot_move():
            #moves the laser until its outside the canvas
            while self.x_p2_laser >= -100:
                self.canvas.move(self.laser_p2,-5,0)
                self.x_p2_laser += -5 
                self.canvas.update()
                time.sleep(.009)  



        # Key bindings that trigger their respective functions
        self.canvas.bind('w', p1_up)
        self.canvas.bind('s', p1_down)        
        self.canvas.bind('<Up>', p2_up)
        self.canvas.bind('<Down>', p2_down)
        self.canvas.bind('<space>', p1_shoot)
        self.canvas.bind('<Control_R>', p2_shoot)


        self.canvas.focus_set()
        # this mainloop thing is some sort of witchcraft! OH MY!!!
        window.mainloop()


Game()

Any help is appreciated, Thanks!

Upvotes: 1

Views: 740

Answers (1)

W1ll1amvl
W1ll1amvl

Reputation: 1269

You are correct, it is due to having 2 while loops going at the same time, it causes one 'laser'/while loop to stop until the other 'laser'/while loop is finished, to solve this you could go into threading etc., but as you mentioned there is the window.after() method, which will perform the task sufficiently, then we can use an if/else test rather than while loops.

Here is you whole code, with some improvements, I made the window and canvas global, and got rid of time.sleep() instead using self.window.after(1, function...) and used if/else rather than while. It shoots rather slowly still, but you will be able to fix this no doubt :), if not I could help.

from tkinter import *

class Game:
    def __init__(self):
        #creating the static canvas background
        self.window = Tk()
        self.window.title('Shoot your friends')
        self.canvas = Canvas(width= 900,
                          height= 700,
                          cursor= 'circle')
        self.canvas.pack()

        self.canvas.create_line(450, 900,
                           450, 0, 
                           dash = (10))

        self.p1_ship = PhotoImage(file = "rd.gif")
        self.p2_ship = PhotoImage(file = "rd.gif")
        self.p1_laser = PhotoImage(file = "rd.gif")
        self.p2_laser = PhotoImage(file = "rd.gif")        

        #Buttons at the bottom
        self.frame = Frame(self.window)
        self.frame.pack()

        #Determining the state of edge teleporting and toggling it
        self.etb = True
        def et():
            if self.etb == True:               
                self.etb = False
                Et["text"] = "Turn On Edge Teleporting"
            else:
                self.etb = True
                Et["text"] = "Turn Off Edge Teleporting"

            print ("Edge Telepoting Toggled")


        Et = Button(self.frame, text="Turn Off Edge Teleporting", command = et, cursor= 'double_arrow')
        Et.grid(row=0,column=0)

        self.Rfb = False
        def rf():
            if self.Rfb == True:               
                self.Rfb = False
                Rf["text"] = "Turn On Rapid Fire "
            else:
                self.Rfb = True
                Rf["text"] = "Turn Off Rapid Fire"

            print ("Rapid Fire Toggled")


        Rf = Button(self.frame, text="Turn On Rapid Fire", command = rf, cursor= 'cross')
        Rf.grid(row=0,column=1)

        def restart():
            print ('restart')
        restart_b = Button(self.frame, text="Restart Game", command = restart, fg='Blue', bg= 'red', cursor='exchange' )
        restart_b.grid(row=0,column=2)

        self.y_p1 = 400
        self.y_p2 = 400

        self.ship_p1 = self.canvas.create_image(40, 450, image=self.p1_ship)             
        self.ship_p2 = self.canvas.create_image(860, 450, image=self.p2_ship) 



        self.canvas.move(self.ship_p1,0,0)
        self.canvas.move(self.ship_p2,0,0)



        #For example If edge teleporting is ON the ship will teleport to the top of the screen if it is at the bottom and the down key is pressed and vice versa
        #My implementation of this may not be the most efficient but I like the options it gives me for adding future features and it looks cool.
        def p1_up(event):
            if self.etb == True and self.y_p1 >= 100:
                self.canvas.move(self.ship_p1,0,-100)
                self.y_p1 += -100                
            elif self.etb == True:
                self.canvas.move(self.ship_p1,0,+800)
                self.y_p1 += +800                
            elif self.y_p1 >= 100:
                self.canvas.move(self.ship_p1,0,-100)
                self.y_p1 += -100


        def p1_down(event):
            if self.etb == True and self.y_p1 <= 799:
                self.canvas.move(self.ship_p1,0,+100)
                self.y_p1 += 100                
            elif self.etb == True:
                self.canvas.move(self.ship_p1,0,-800)
                self.y_p1 += -800
            elif self.y_p1 <= 799:
                self.canvas.move(self.ship_p1,0,+100)
                self.y_p1 += 100


        def p2_up(event):
            if self.etb == True and self.y_p2 >= 100:
                self.canvas.move(self.ship_p2,0,-100)
                self.y_p2 += -100  
            elif self.etb == True:
                self.canvas.move(self.ship_p2,0,+800)
                self.y_p2 += +800
            elif self.y_p2 >= 100:
                self.canvas.move(self.ship_p2,0,-100)
                self.y_p2 += -100


        def p2_down(event):
            if self.etb == True and self.y_p2 <= 799:
                self.canvas.move(self.ship_p2,0,+100)
                self.y_p2 += 100
            elif self.etb == True:
                self.canvas.move(self.ship_p2,0,-800)
                self.y_p2 += -800
            elif self.y_p2 <= 799:
                self.canvas.move(self.ship_p2,0,+100)
                self.y_p2 += 100

        # Functions for shooting

        self.p1_shot_out = False
        self.p2_shot_out = False

        def p1_shoot(event):

            if self.p1_shot_out == True:  
                self.canvas.delete(self.laser_p1)
            #draws the laser    
            self.laser_p1 = self.canvas.create_image(50, self.y_p1 +50, image=self.p1_laser)
            self.x_p1_laser = 50
            self.p1_shot_out = True

            self.window.after(1, p1_shoot_move)


        def p1_shoot_move():
            #moves the laser until its outside the canvas
            if self.x_p1_laser >= 930:
                pass
            else:
                self.canvas.move(self.laser_p1,5,0)
                self.x_p1_laser += 5 
                self.canvas.update()
                self.window.after(1, p1_shoot_move)


        def p2_shoot(event):
            if self.p2_shot_out == True:
                self.canvas.delete(self.laser_p2)
            #draws the laser
            self.laser_p2 = self.canvas.create_image(750, self.y_p2 +50, image=self.p2_laser)
            self.x_p2_laser = 750
            self.p2_shot_out = True

            self.window.after(1, p2_shoot_move)


        def p2_shoot_move():
            #moves the laser until its outside the canvas
            if self.x_p2_laser <= -110:
                pass
            else:
                self.canvas.move(self.laser_p2,-5,0)
                self.x_p2_laser += -5 
                self.canvas.update()
                self.window.after(1, p2_shoot_move) 



        # Key bindings that trigger their respective functions
        self.canvas.bind('w', p1_up)
        self.canvas.bind('s', p1_down)        
        self.canvas.bind('<Up>', p2_up)
        self.canvas.bind('<Down>', p2_down)
        self.canvas.bind('<space>', p1_shoot)
        self.canvas.bind('<Control_R>', p2_shoot)


        self.canvas.focus_set()


Game()

hope that helps you out

Upvotes: 1

Related Questions