如何让对象从 canvas 边界反弹?

How do I have an object rebound off the canvas border?

我正在使用来自 tkinter 的 canvas 小部件创建一个椭圆并让它在 canvas 中四处移动。

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

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

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

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

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

  • 虽然循环不能很好地与 GUI 主循环一起工作;也没有必要调用 updatemainloop 会处理它。

  • 重复操作是 root.after 的最佳处理方式。

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

  • 我还参数化了 canvas 大小。

  • 初始速度组件 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()