如何让对象从 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 主循环一起工作;也没有必要调用 update
,mainloop
会处理它。
重复操作是 root.after
的最佳处理方式。
我在使用 root.after
调用自身的函数 bounce
中提取了反弹逻辑。你会看到我简化了逻辑。
我还参数化了 canvas 大小。
初始速度组件 dx
和 dy
是从可能值列表中随机选择的,因此游戏不会太无聊。
外观如下:
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()
我正在使用来自 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 主循环一起工作;也没有必要调用
update
,mainloop
会处理它。重复操作是
root.after
的最佳处理方式。我在使用
root.after
调用自身的函数bounce
中提取了反弹逻辑。你会看到我简化了逻辑。我还参数化了 canvas 大小。
初始速度组件
dx
和dy
是从可能值列表中随机选择的,因此游戏不会太无聊。
外观如下:
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()