-1

I am using the canvas widget from tkinter to create an ellipse and have it move around in the canvas.

However when the ellipse comes in contact with the border it gets stuck to wall instead of bouncing off.

I'm struggling with debugging the code, thanks in advance!

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
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
D.Ayala
  • 1
  • 1

2 Answers2

0

It's just basic math. The ball moves left when you subtract some amount from the x coordinate. If it hits the left wall and you want it to bounce to the right, you need to stop subtracting from x and start adding to x. The same is true for the y coordinate.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • That's why I changed the dx and dy to negative when it hits a wall so it starts subtracting but it goes the opposite direction once and goes back to the wall instead of moving away from the wall – D.Ayala Aug 11 '18 at 15:26
0

Here is a simple way to organize your bouncing ball program, and get you started with GUI programming:

  • While loops don't work well with a GUI mainloop; it is also not necessary to call update, the mainloop handles that.

  • Repeated actions are best handles with root.after.

  • I extracted the bounce logic inside a function bounce that calls itself using root.after. You will see that I simplified the logic.

  • I also parametrized the canvas size.

  • The initial speed components dx and dy are randomly chosen from a list of possible values so the game is not too boring.

Here is how it looks:

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()
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80