代码之家  ›  专栏  ›  技术社区  ›  SHatna

在Tkinter中穿线以防止主回路冻结

  •  0
  • SHatna  · 技术社区  · 6 年前

    我在Tkinter用画布制作一个射击游戏。用户控制一个精灵,该精灵沿着X轴方向不断地发射子弹。

    我遇到了一个问题,同时试图动画子弹在屏幕上移动。我用的是 while True

    从我的研究中我了解到,我可能不得不使用线程来阻止主顶部冻结,但我还没有找到任何容易遵循的指南线程在Tkinter在线。

    这是我的代码:

    from Tkinter import *
    from Tkinter import Canvas
    import time
    
    window1 = Tk()
    window1.title("Shoot 'Em Up")
    window1.config(background="black")
    window1.geometry("600x300")
    
    
    def move_spryte1_up(event):
        xspeed = 0
        yspeed = -10
        canvas.move(spryte1, xspeed, yspeed)
        Tk.update(window1)
    
    
    def move_spryte1_down(event):
        xspeed = 0
        yspeed = 10
        canvas.move(spryte1, xspeed, yspeed)
        Tk.update(window1)
    
    
    def move_spryte1_left(event):
        xspeed = -10
        yspeed = 0
        canvas.move(spryte1, xspeed, yspeed)
        Tk.update(window1)
    
    
    def move_spryte1_right(event):
        xspeed = 10
        yspeed = 0
        canvas.move(spryte1, xspeed, yspeed)
        Tk.update(window1)
    
    
    def bullets():
        spryte1_pos = canvas.bbox(spryte1)
        newpos1 = spryte1_pos[1]
        newpos2 = spryte1_pos[2]-30
        newpos3 = spryte1_pos[3]-20
        spryte2 = canvas.create_rectangle(newpos1, newpos2, newpos3, newpos3, fill="blue")
        print(spryte1_pos)
        print(newpos1)
        print(newpos2)
        print(newpos3)
        while True:
            canvas.move(spryte2, 10, 0)
            Tk.update(window1)
            time.sleep(0.1)
    
    
    canvas = Canvas(window1, width=600, height=300, bg="black", bd=0, highlightthickness=1, relief="ridge", highlightbackground="black")
    canvas.pack()
    points = [20, 40, 35, 40, 35, 30, 50, 40, 65, 40, 80, 52.5, 65, 65, 50, 65, 35, 75, 35, 65, 20, 65, 30, 62, 20, 59, 30, 56, 20, 53, 30, 50, 20, 47, 30, 44]
    spryte1 = canvas.create_polygon(points, outline='red', fill='gray')
    bullets()
    canvas.tag_raise(spryte1)
    window1.bind('<Up>', move_spryte1_up)
    window1.bind('<Down>', move_spryte1_down)
    window1.bind('<Left>', move_spryte1_left)
    window1.bind('<Right>', move_spryte1_right)
    
    window1.mainloop()
    

    任何帮助都将不胜感激!

    编辑:这个问题与 python - While Loop causes entire program to crash in Tkinter 因为这是我最初在Tkinter中寻找线程帮助时提出的一个问题。然而,我尝试了提出的解决方案,但发现它并没有解决我的问题

    1 回复  |  直到 6 年前
        1
  •  0
  •   Bryan Oakley    6 年前

    你不需要线程,也不需要一个while循环来完成这么简单的事情。

    您已经运行了一个无限循环——事件循环(例如: mainloop )您可以使用 after 方法。要执行动画,只需调用函数来绘制一帧,然后让该函数将自身添加回事件队列以绘制下一帧。

    下面是对代码的简单修改,以说明这一点:

    def bullets():
        spryte1_pos = canvas.bbox(spryte1)
        newpos1 = spryte1_pos[1]
        newpos2 = spryte1_pos[2]-30
        newpos3 = spryte1_pos[3]-20
        spryte2 = canvas.create_rectangle(newpos1, newpos2, newpos3, newpos3, fill="blue")
        shoot(spryte2, 10, 0)
    
    def shoot(spryte, x, y):
        canvas.move(spryte, x, y)
        x0,y0,x1,y1 = canvas.bbox(spryte)
        if x0 < 600
            # call again in 100ms, unless the bullet is off the screen
            canvas.after(100, shoot, spryte, x, y)
    

    画布可能可以在陷入困境之前处理好几十个这样移动的sprytes。

    顺便说一句,你也可以删除对 Tk.update(window1) 在你的move函数中——它增加了开销并减慢了程序的运行速度。一般来说你应该 从未 呼叫 update .