4

I am trying to make the game Pong. I have everything (except moving the ball) set up but when I run it I can't move both paddles at the same time. Does anybody know what I need to do?

import time
import turtle

#window
Wn_width = 800
Wn_height = 600
Wn = turtle.Screen()
Wn.setup(Wn_width, Wn_height)
Wn.tracer(0)
Title = turtle.title("Pong")
Background_color = turtle.bgcolor("black")

#bats and ball
bat1 = turtle.Turtle("square")
bat1.color("white")
bat1.shapesize(3, 1)
bat1.penup()
bat1.setpos(360,0)

bat2 = turtle.Turtle("square")
bat2.color("white")
bat2.shapesize(3, 1)
bat2.penup()
bat2.setpos(-360, 0)

bal = turtle.Turtle("circle")
bal.color("white") 
bal.penup()

#up down
def up():
    bat1.sety(bat1.ycor() + 5)
    if bat1.ycor() > 260:
        bat1.sety(bat1.ycor() -5)

def down():
    bat1.sety(bat1.ycor() - 5)  
    if bat1.ycor() < -250:
        bat1.sety(bat1.ycor() + 5)  

def up2(): 
    bat2.sety(bat2.ycor() + 5)
    if bat2.ycor() > 260:
        bat2.sety(bat2.ycor() - 5)

def down2(): 
    bat2.sety(bat2.ycor() - 5)
    if bat2.ycor() < -250:
        bat2.sety(bat2.ycor() + 5)

Wn.onkeypress(up, "Up")
Wn.onkeypress(down, "Down")
Wn.onkeyrelease(up, "Up")
Wn.onkeyrelease(down, "Down")
Wn.onkeypress(up2, "w")
Wn.onkeypress(down2, "s")
Wn.onkeyrelease(up2, "w")
Wn.onkeyrelease(down2, "s")
Wn.listen()

#main loop
while True: 
    Wn.update()
    time.sleep(0.01)

Each paddle moves perfectly fine on its own, but when I try to move them simultaneously, for example while holding the "up" button, pressing the "w" button - the first paddle will just stop and the second will start moving. How can I be able to press both "up" (or "down") and "w" (or "s") at the same time and have both paddles move?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
kroedie
  • 41
  • 3
  • I believe this contains your answer! It uses pygame. https://stackoverflow.com/a/64227080/12282360 – Noah Jan 21 '22 at 18:45
  • 1
    Well.... I found a question (an exact duplicate to be fair). Problem is: it doesn't have answers yet.... [How can I enable multiple key presses in Turtle?](https://stackoverflow.com/q/56384666/6045800) – Tomerikoo Jan 21 '22 at 18:59
  • that's a shame. it's really weird as it didn't occur on the youtube tutorial i was watching. i'll now just try to get the ball moving and after i will take a look at it again. thanks for trying to help :) – kroedie Jan 21 '22 at 19:04
  • No problem. Seems an interesting issue. If I find anything, I'll be sure to update here :) – Tomerikoo Jan 21 '22 at 19:07
  • 1
    Does this answer your question? [How to bind several key presses together in turtle graphics?](https://stackoverflow.com/questions/47879608/how-to-bind-several-key-presses-together-in-turtle-graphics) – ggorlen Feb 03 '22 at 22:48

2 Answers2

0

Instead of triggering your up and down functions directly try to set a moving direction and then trigger the move itself in your main loop. Here is the relevant code for one paddle. Create the same for the second paddle and work in the conditions to stay inside the screen and you should be able to move both paddles at once.

...

moving_direction_1 = 0

def up():
    moving_direction_1 = 1

def down():
    moving_direction_1 = -1

def stop_moving():
    moving_direction_1 = 0

def update_position():
    bat1.sety(bat1.ycor() + 5 * moving_direction_1)


Wn.onkeypress(up, "Up")
Wn.onkeypress(down, "Down")
Wn.onkeyrelease(stop_moving, "Up")
Wn.onkeyrelease(stop_moving, "Down")
Wn.listen()

#main loop
while True: 
    update_position()
    Wn.update()
    time.sleep(0.01)
0

Another solution, using decorators. The advantage of the solution below is that it abstracts the key pressed/released management - you use the decorator once, before the function declaration and specifying the key and you know that the function will be called while the function is pressed.

The other small change is to add the invocation of events in the main loop.

As decorator are syntactic sugar, you can use the RepeatEvents without the @ syntax (see down2 below)

import time
import turtle

#window
Wn_width = 800
Wn_height = 600
Wn = turtle.Screen()
Wn.setup(Wn_width, Wn_height)
Wn.tracer(0)
Title = turtle.title("Pong")
Background_color = turtle.bgcolor("black")

#bats and ball
bat1 = turtle.Turtle("square")
bat1.color("white")
bat1.shapesize(3, 1)
bat1.penup()
bat1.setpos(360,0)

bat2 = turtle.Turtle("square")
bat2.color("white")
bat2.shapesize(3, 1)
bat2.penup()
bat2.setpos(-360, 0)

bal = turtle.Turtle("circle")
bal.color("white") 
bal.penup()

import functools

events = []

class RepeatEvents:
    def __init__(self, screen, key):
        # This creates the object which will store the key status (presesed or not)
        self.pressed = False
        self.key = key
        # We register to listen to events so that we can change the key status
        screen.onkeypress(self.press, key)
        screen.onkeyrelease(self.release, key)

    def press(self):
        self.pressed = True

    def release(self):
        self.pressed = False

    def __call__(self, func=None):
        # This function is first time called when decorator is put before
        # the function name - we add ourselves to the events list and remember
        # what function whould we call
        if self not in events:
            self.func = func
            events.append(self)
            return
        # This is called from the main loop and depending on key status we call
        # the function or not
        if not self.pressed:
            return lambda : None
        return self.func()

@RepeatEvents(Wn, "Up")
def up():
    bat1.sety(bat1.ycor() + 5)
    if bat1.ycor() > 260:
        bat1.sety(bat1.ycor() -5)

@RepeatEvents(Wn, "Down")
def down():
    bat1.sety(bat1.ycor() - 5)  
    if bat1.ycor() < -250:
        bat1.sety(bat1.ycor() + 5)  

@RepeatEvents(Wn, "w")
def up2(): 
    bat2.sety(bat2.ycor() + 5)
    if bat2.ycor() > 260:
        bat2.sety(bat2.ycor() - 5)

def down2(): 
    bat2.sety(bat2.ycor() - 5)
    if bat2.ycor() < -250:
        bat2.sety(bat2.ycor() + 5)

# Maybe we want to have more control over keys, invoke RepeatEvents manually:
# (like this you can for example remove repeat_down2 object from events to
# disable this)
repeat_down2 = RepeatEvents(Wn, "s")
repeat_down2((down2))


Wn.listen()

#main loop
while True: 
    Wn.update()
    # Invoke the events
    for e in events:
        e()
    time.sleep(0.01)
vladmihaisima
  • 2,119
  • 16
  • 20