1

I have the following code which manages to make a ball bounce on the top and bottom ends of the screen.

Working code for bouncing on top and bottom

from tkinter import *
import random
import time

class Ball: 
    def __init__(self,canvas,color): 
        self.canvas=canvas 
        self.id=canvas.create_oval(30,30,50,50,fill=color) 
        self.canvas.move(self.id,100,200)

        #ADD THESE LINES TO OUR __INIT__ METHOD
        self.x=0 
        self.y=-1 
        self.canvas_height=self.canvas.winfo_height() 

    def draw(self): 
        self.canvas.move(self.id,self.x,self.y) 
        pos=self.canvas.coords(self.id) 

        if pos[1] <=0:
            self.y=1
        if pos[3] >=self.canvas_height: 
            self.y=-1


def main():
    tk=Tk()
    tk.title("My 21st Century Pong Game")
    tk.resizable(0,0)
    tk.wm_attributes("-topmost",1)
    canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
    canvas.pack()
    tk.update()

    ball1=Ball(canvas,'green')
    while 1:
        tk.update()
        ball1.draw() #call the ball draw method here
        time.sleep(0.01)
main()

When trying to make it happen for left to right (bounce on the left and right wall), I cannot quite figure out the logic or solve my error as seen below.

What I've tried for bouncing on left and right

  self.x=1 #set the object variable x to 0 (don't move the ball horizontally)
        self.y=-0 #set the object variable y to -1 (this means keep moving the ball UP on initilisation)
        self.canvas_height=self.canvas.winfo_height() #set the canvas height by calling the canvas function winfo_height (it gives us the current canvas height)

    def draw(self): 
        self.canvas.move(self.id,self.x,self.y) 
        pos=self.canvas.coords(self.id) 

        if pos[2] <=0: #if you hit the top of the screen then stop subtracting 1 as defined in the __init__ method and therefore stop moving up -reverse directions
            self.x=-1
        if pos[3] >=self.canvas_height: #if the bottom coordinates are greater or equal to canvas height, then reverse again, and set y back to -1 (go up)
            self.x=1

For an answer,

could someone provide a simple explanation as to the logic that is needed to solve the problem,where the coordinates are coming from and what pos[0],pos[1] etc refer to. I have an idea, but it is not at all clear and would benefit (as would SO I imagine) from some clarity.

So, I'm after an explanation + coded solution fix (using my original code) to solve the problem.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Compoot
  • 2,227
  • 6
  • 31
  • 63

1 Answers1

0

The code is almost right. In fact, it's so almost right that a moment's further thought would probably have given you the answer. Your 'move x' code has been copy-pasted from the 'move y' code, but not changed enough. Beware of doing this.

In response to 'what do pos[0] etc mean', I invite you to read Get coords of an oval in Tkinter. Usually, coordinates of a rectangle are given as (left, top, right, bottom).

You'll notice that I've changed some things below, besides correcting your errors:

  1. I've changed the x & y variables to vx and vy. The values are the velocities of the ball, not the position.
  2. The function name is now move, not draw, since the function moves and doesn't draw.
  3. The alive variable with the tk.protocol line gives the program a tidy way of cleaning up after the user closes the window.

.

from tkinter import *
import random
import time

class Ball: 
    def __init__(self,canvas,color):
        self.alive = True
        self.canvas = canvas 
        self.id = canvas.create_oval(30, 30, 50, 50, fill=color) 
        self.canvas.move(self.id, 100, 200)

        #ADD THESE LINES TO OUR __INIT__ METHOD
        self.vx = 1 
        self.vy = -1 
        self.canvas_width = self.canvas.winfo_width() 
        self.canvas_height = self.canvas.winfo_height() 

    def move(self): 
        self.canvas.move(self.id, self.vx, self.vy) 
        pos = self.canvas.coords(self.id) 
        if pos[0] <= 0:
            self.vx = 1
        if pos[2] >= self.canvas_width:
            self.vx = -1
        if pos[1] <= 0:
            self.vy = 1
        if pos[3] >= self.canvas_height: 
            self.vy = -1

    def kill(self):
        self.alive = False

def main():
    tk = Tk()
    tk.title("My 21st Century Pong Game")
    tk.resizable(0, 0)
    tk.wm_attributes("-topmost", 1)
    canvas = Canvas(tk, bg="white", width=500, height=400, bd=0, highlightthickness=0)
    canvas.pack()
    tk.update()

    tk.protocol("WM_DELETE_WINDOW", lambda: ball1.kill())

    ball1 = Ball(canvas, 'green')
    while ball1.alive:
        tk.update()
        ball1.move() #call the ball move method here
        time.sleep(0.01)
    tk.destroy()

if __name__ == "__main__":
    main()
Glenn Rogers
  • 351
  • 2
  • 4