2014-12-12 4 views
0

У меня возникли проблемы, когда если выстрел несколько раз выстрелил, прежде чем он покинет холст, он будет ускоряться каждый раз, когда он будет перерисован до тех пор, пока его скорость не сможет обновиться. Ive приписал проблему команде canvas.after, потому что, если я буду использовать этот цикл while, используя команду time.sleep, он отлично работает (к сожалению, я могу использовать реализацию кода, потому что он работает как два отдельных цикла)Странные вещи с canvas.after()

#imports 
from tkinter import * 


#The Game 
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= 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 
    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) 


# Functions that handle movement of the ships taking into account multiple variables 

    #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(3, 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(4, 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(4, 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() 
    # this mainloop thing is some sort of witchcraft! OH MY!!! 
    self.window.mainloop() 

Game()

+0

Я не уверен, что хорошо использовать 'time.sleep' с' tkinter' – nbro

+1

Прочтите https://stackoverflow.com/help/mcve. Для тестирования требуется только один из p1, p2, но для тестирования требуется больше. –

+0

@nbro time.sleep - это, как правило, плохая идея, но я не думаю, что это проблема здесь, поскольку она выполняется только один раз для снаряда. –

ответ

3

проблема заключается в том, что каждый раз, когда вы "стрелять", вы называете after. Если вы стреляете пять раз подряд, у вас будет 5 «ходов» в очереди. Каждый добавляет 5 к местоположению x, и все они будут работать всего на несколько мсек друг от друга, поэтому лазер будет двигаться очень быстро. Пять будут работать быстро, затем через 3 мс они снова начнут быстро, и так далее.

Что вам нужно сделать, это сохранить ссылку на то, что вы планируете с after, и отменить его перед началом нового снимка. Это или сохранить независимую запись координаты x/y для каждого снимка, если вы хотите, чтобы одновременно было задействовано более одного кадра.

Например:

def p1_shoot(event): 
    .... 
    # cancel any previous shot 
    if self.p1_job is not None: 
     self.window.after_cancel(self.p1_job) 
    self.p1_job = self.window.after(1, p1_shoot_move) 

Конечно, вам нужно установить self.p1_job каждый раз, когда вы вызываете после, и вы должны инициализировать его None в начале, и когда пуля разрушается.

Смежные вопросы