【问题标题】:How do I have an object rebound off the canvas border?如何让对象从画布边框反弹?
【发布时间】:2018-08-10 20:51:21
【问题描述】:

我正在使用 tkinter 的画布小部件创建一个椭圆并让它在画布中移动。

但是,当椭圆与边框接触时,它会粘在墙上而不是弹开。

我正在努力调试代码,在此先感谢!

from tkinter import *
from time import *
import numpy as np
root = Tk()
root.wm_title("Bouncing Ball")
canvas = Canvas(root, width=400, height=400, bg="black")
canvas.grid()
size=10
x = 50
y = 50
myBall = canvas.create_oval(x-size, y-size, x+size, y+size, fill = "red")
while True:
    root.update()
    root.after(50)
    dx = 5
    dy = 0
#separating x and y cooridnates from tuple of canvas.coords
    x = canvas.coords(myBall)[0]+10
    y = canvas.coords(myBall)[1]+10
    coordinates = np.array([x, y], dtype = int)
#Checking boundaries
    if coordinates[0]-size <= 0:
        dx = -1*dx
    if coordinates[0]+size >= 400:
        dx = -1*dx
    if coordinates[1]-size <= 0:
        dy = -1*dy
    if coordinates[1]+size >= 400:
        dy = -1*dy
    print(coordinates) #Used to see what coordinates are doing
    canvas.move(myBall, dx, dy) #Move ball by dx and dy

【问题讨论】:

    标签: python python-3.x tkinter collision tkinter-canvas


    【解决方案1】:

    这里有一个简单的方法来组织你的弹跳球程序,让你开始使用 GUI 编程:

    • 虽然循环不适用于 GUI 主循环;也没有必要调用updatemainloop 处理。

    • 重复操作是root.after 的最佳句柄。

    • 我在函数bounce 中提取了反弹逻辑,该函数使用root.after 调用自身。你会看到我简化了逻辑。

    • 我还参数化了画布大小。

    • 初始速度分量dxdy 是从可能值列表中随机选择的,因此游戏不会太无聊。

    这是它的外观:

    import tkinter as tk   # <-- avoid star imports
    import numpy as np
    import random
    
    WIDTH = 400
    HEIGHT = 400
    initial_speeds = [-6, -5, -4, 4, 5, 6]
    dx, dy = 0, 0
    while dx == dy:
        dx, dy = random.choice(initial_speeds), random.choice(initial_speeds) 
    
    def bounce():
        global dx, dy
        x0, y0, x1, y1 = canvas.coords(my_ball)
        if x0 <= 0 or x1 >= WIDTH:    # compare to left of ball bounding box on the left wall, and to the right on the right wall
            dx = -dx
        if y0 <= 0 or y1 >= HEIGHT:   # same for top and bottom walls
            dy = -dy
        canvas.move(my_ball, dx, dy)
        root.after(50, bounce)
    
    if __name__ == '__main__':
    
        root = tk.Tk()
        root.wm_title("Bouncing Ball")
        canvas = tk.Canvas(root, width=400, height=400, bg="black")
        canvas.pack(expand=True, fill=tk.BOTH)
    
        size=10
        x = 50
        y = 50
        my_ball = canvas.create_oval(x-size, y-size, x+size, y+size, fill="red")
    
        bounce()
        root.mainloop()
    

    【讨论】:

    • 为什么我不应该使用星号导入来运行代码,添加 expand=True 和 fill=tk.BOTH 有什么价值?
    • expand=True 和 fill=tk.BOTH:您希望您的画布填充它的容器;这里是根。
    【解决方案2】:

    这只是基本的数学。当您从 x 坐标中减去一些量时,球会向左移动。如果它撞到左边的墙并且你想让它反弹到右边,你需要停止从 x 中减去并开始添加到 x。 y 坐标也是如此。

    【讨论】:

    • 这就是为什么我将 dx 和 dy 在它撞到墙上时改为负数,所以它开始减去但它朝相反的方向走一次,然后回到墙上而不是远离墙壁
    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 2016-12-10
    • 2016-11-27
    • 2022-09-26
    • 1970-01-01
    • 2011-03-01
    • 2017-08-10
    • 1970-01-01
    相关资源
    最近更新 更多