Using the turtle module to make a pong game. For this part, when I press the up/down keys the board doesn't respond to the onkey listen function.
I created the board/bat (or bat specs function from turtle called
bat_specs_p2()
) and set the positions of the board/bat (x and y) on the screen. All is fine at this point. I know that the y-coord will have to change once the up/down keys are pressed. Testing with print shows that the y-coords are been updated everytime up/down is pressed, but the board/bat is not moving on the screen. I think it is still holding the starting position of the board/bat, somewhere the y-coord is not updating
from turtle import Turtle
P1_x = -200
P1_y = 0
P2_x = 200
P2_y = 0
class Bat:
def __init__(self):
self.p2_position = (P2_x, P2_y)
self.p1_position = (P1_x, P1_y)
def bat_specs_p2(self):
global P2_y
bat = Turtle()
bat.penup()
bat.shape("square")
bat.color("white")
bat.shapesize(stretch_wid=4, stretch_len=1)
bat.setposition(self.p2_position)
def p2move_up(self):
global P2_y
P2_y += 20
self.bat_specs_p2()
print(P2_x, P2_y)
def p2move_down(self):
global P2_y
P2_y -= 20
self.bat_specs_p2()
print(P2_x, P2_y)
from turtle import Screen
import time
from bat import Bat
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Pong Game")
screen.tracer(0)
bat = Bat()
bat.bat_specs_p2()
screen.listen()
screen.onkey(bat.p2move_up, "Up")
screen.onkey(bat.p2move_down, "Down")
screen.update()
screen.exitonclick()
You have two correctness problems:
tracer(0)
to disable turtle's control of the rendering loop, you need to call screen.update()
whenever you want to perform a redraw of the canvas.bat.setposition(self.p2_position)
is an attempt at connecting them, but self.p2_position = (P2_x, P2_y)
copies the values of P2_x
and P2_y
, so when they change globally, the tuple doesn't update (tuples are immutable and primitives are not pass-by-reference).Beyond that, your design is a little unusual. Avoid global
, especially when you're trying to write a class that should have instance-specific state. The Bat
class should only be responsible for one player's bat. Make separate instances of the class for each bat, along with self.
for all dynamic state.
Here's a simple example:
from turtle import Screen, Turtle
class Bat:
def __init__(self, y=0, x=0, speed=20):
self.speed = speed
self.t = t = Turtle()
t.penup()
t.shape("square")
t.color("white")
t.shapesize(stretch_wid=4, stretch_len=1)
t.setposition((x, y))
def move_up(self):
self.t.sety(self.t.ycor() + self.speed)
def move_down(self):
self.t.sety(self.t.ycor() - self.speed)
screen = Screen()
screen.tracer(0)
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Pong Game")
screen.listen()
p1 = Bat(x=200)
p2 = Bat(x=-200)
def with_update(action):
def update():
screen.update()
action()
return update
screen.onkey(with_update(p1.move_up), "Up")
screen.onkey(with_update(p1.move_down), "Down")
screen.onkey(with_update(p2.move_up), "w")
screen.onkey(with_update(p2.move_down), "s")
screen.update()
screen.exitonclick()
Now, this isn't great for real-time movement. If you need smooth movement and/or support for multiple key presses at once, you'll want to use ontimer
as described in How to bind several key presses together in turtle graphics? to run an update loop independent of the key handlers. Applying those techniques to pong, see Using 2 onkeypress-es (with a thread/process) in Python Turtle.