One object gets stuck with two while loops - python

I'm trying to add physics to the paddle object whenever I press "w", but the ball object gets stuck until the while loop is finished in the paddle_up() function. How do I make the ball keep moving while the paddle is jumping?
The point of this game is avoiding the ball coming from the right. Whenever the user avoids the ball he or she gets one point, but whenever it collide's with the paddle, they lose one point:
import random
import turtle
# window setup
wn = turtle.Screen()
wn.title("Jump Game")
wn.bgcolor("black")
wn.setup(width=1000, height=750)
wn.tracer(0)
# Key Biding Functions
def paddle_up():
paddle_a.dy = -0.1
while paddle_a.ycor() < 0:
paddle_a.sety(paddle_a.ycor() - paddle_a.dy)
wn.update()
def paddle_down():
y = paddle_a.ycor()
y -= 10
paddle_a.sety(y)
def paddle_left():
x = paddle_a.xcor()
x -= 10
paddle_a.setx(x)
def paddle_right():
x = paddle_a.xcor()
x += 10
paddle_a.setx(x)
# Paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(1)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=2, stretch_len=2, outline=1)
paddle_a.penup()
paddle_a.goto(-480, -350)
# Ball
ball = turtle.Turtle()
ball.shape("circle")
ball.color("white")
ball.penup()
ball.goto(-350, 0)
ball_speed = random.random()
ball_position_y = random.randint(-350, -300)
# Score System
Score = 0
Scr = turtle.Turtle()
Scr.goto(0, 360)
Scr.color("white")
Scr.penup()
Scr.hideturtle()
wn.listen()
wn.onkeypress(paddle_up, "w")
wn.onkeypress(paddle_down, "s")
wn.onkeypress(paddle_left, "a")
wn.onkeypress(paddle_right, "d")
# Main Game Loop
while True:
wn.update()
ball.setx(ball.xcor() - ball_speed * 0.3)
if ball_speed <= 0.3:
ball_speed = 0.3
if ball.xcor() < paddle_a.xcor() + 20 and ball.xcor() > paddle_a.xcor() - 20 and ball.ycor() < paddle_a.ycor() +20 and ball.ycor() > paddle_a.ycor() - 20:
Score = Score - 1
Scr.clear()
Scr.write("Score{}".format(Score), align="center", font=("Courier", 24))
ball.setx(490)
ball_position_y = random.randint(-350, -300)
ball.sety(ball_position_y)
elif ball.xcor() <= -490 and ball.ycor() != paddle_a.ycor():
Score = Score + 1
Scr.clear()
Scr.write("Score{}".format(Score), align="center", font=("Courier", 24))
ball.setx(490)
ball_position_y = random.randint(-350, -300)
ball.sety(ball_position_y)

You're using while loops where you should be using timer events. SO is full of Python turtle game answers that say, "while True: has no business in an event-driven world like turtle." How could you miss them?
I've reworked your code below to make it basically playable:
from random import randint
from turtle import Screen, Turtle
FONT = ('Courier', 24)
# Key Biding Functions
def paddle_up():
def paddle_rise():
if paddle.ycor() < 0:
paddle.sety(paddle.ycor() + paddle.dy)
screen.update()
screen.ontimer(paddle_rise, 10)
paddle_rise()
def paddle_down():
paddle.sety(paddle.ycor() - 10)
def paddle_left():
paddle.setx(paddle.xcor() - 10)
def paddle_right():
paddle.setx(paddle.xcor() + 10)
def update_score():
global ball_speed
scorer.clear()
scorer.write("Score: {}".format(score), align='center', font=FONT)
ball.setposition(490, randint(-350, -300))
ball_speed = randint(1, 3)
# Main Game Loop
def play():
global score
ball.setx(ball.xcor() - ball_speed)
if ball.distance(paddle) <= 20:
score -= 1
update_score()
elif ball.xcor() <= -490 and ball.ycor() != paddle.ycor():
score += 1
update_score()
screen.update()
screen.ontimer(play, 10)
# window setup
screen = Screen()
screen.title("Jump Game")
screen.bgcolor('black')
screen.setup(width=1000, height=800)
screen.tracer(0)
# Paddle A
paddle = Turtle()
paddle.shape('square')
paddle.color('white')
paddle.shapesize(stretch_wid=2, stretch_len=2, outline=1)
paddle.speed('slowest')
paddle.penup()
paddle.goto(-480, -350)
paddle.dy = 2
# Ball
ball = Turtle()
ball.shape('circle')
ball.color('white')
ball.penup()
ball.setposition(490, randint(-350, -300))
ball_speed = randint(1, 3)
# Score System
score = 0
scorer = Turtle()
scorer.hideturtle()
scorer.sety(360)
scorer.color('white')
scorer.penup()
scorer.write("Score: {}".format(score), align='center', font=FONT)
screen.onkeypress(paddle_up, 'w')
screen.onkeypress(paddle_down, 's')
screen.onkeypress(paddle_left, 'a')
screen.onkeypress(paddle_right, 'd')
screen.listen()
play()
screen.mainloop()

Related

Making Turtle Graphics Python game start only after main menu button has been clicked

so i'm currently making a python turtle graphics game, it's a pong game where there is a 2 paddles and they pass the ball to each other, once ball touches each side the player gets a point, the game is fully functional in 1920x1080 res, the thing is i made a main menu type of thing where the game starts after the Start button has been clicked, thing is the menu works exactly as intended but even before i press start the main game loop starts once canvas is opened, not when start button is clicked, so it looks like this: https://imgur.com/tRWc6q9, this is what it looks like after menu button has been pressed: https://imgur.com/FwW9dO2
Here is the whole code, sorry if it's quite long i have been trying to solve it for 2 days
import turtle
import time
pong = turtle.Screen()
pong.title("My First Project")
pong.bgcolor("black")
pong.setup(width=1920,height=1080)
pong.tracer(0)
#Step 1: Create Both Padles and Ball(Done)
#Step 2: Movement Functions and Linking them to Keyboard(Done)
#Step 3: Scoring System and Updating it(Done)
#Step 4: Winning Screen(Done)
#Step 5: Collision with Paddles and Balls(Done)
#Step 5: Main Menu(In Progress)
#Creating Menu
mainCanvas = turtle.Turtle()
mainCanvas.color("cyan")
mainCanvas.hideturtle
mainCanvas.speed(0)
mainCanvas.begin_fill()
#list to make the main menu bg
fd_list1=[(90, 540), (0, 960), (270, 1080),(180,1920),(90,1080),(0,960)]
for hd1, fwd1 in fd_list1:
mainCanvas.setheading(hd1)
mainCanvas.fd(fwd1)
mainCanvas.end_fill()
#Creating Title
mainTitle = turtle.Turtle()
mainTitle.penup()
mainTitle.speed(0)
mainTitle.hideturtle()
mainTitle.goto(0,270)
mainTitle.write("Main Menu",align="center",font=("a Absolute Empire",60,"normal"))
#Create Start Option
startGame = turtle.Turtle()
startGame.speed(0)
startGame.penup()
startGame.goto(0,100)
pong.register_shape("start_400x150.gif") #PNG for start button
startGame.shape("start_400x150.gif") #Applying the PNG
startGame.shapesize(stretch_len=20,stretch_wid=20)
#Start Click Function
def clickStart(x,y):
if x > startGame.xcor() - 200 and x < startGame.xcor() + 200 and y > startGame.ycor() - 75 and y < startGame.ycor() + 75:
time.sleep(0.5)
mainTitle.clear()
pong.bgcolor("black")
startGame.hideturtle()
#Get rid of Main Menu
mainCanvas.color("black")
mainCanvas.goto(0,0)
mainCanvas.begin_fill()
#List to change canvas to desired color once clicked
fd_list=[(90, 540), (0, 960), (270, 1080),(180,1920),(90,1080),(0,960)]
for hd, fwd in fd_list:
mainCanvas.setheading(hd)
mainCanvas.fd(fwd)
mainCanvas.end_fill()
#Hide Button
startGame.goto(0,5000)
#Key Binding Main Menu
pong.listen()
pong.onscreenclick(clickStart,1)
#creating Paddle A, Player 1(left Side)
paddleA = turtle.Turtle()
paddleA.speed(0)
paddleA.shape("square")
paddleA.shapesize(9,1)
paddleA.color("white")
paddleA.penup()
paddleA.goto(-900,0)
#creating Paddle B, Player 2(Right Side)
paddleB = turtle.Turtle()
paddleB.speed(0)
paddleB.shape("square")
paddleB.shapesize(9,1)
paddleB.color("white")
paddleB.penup()
paddleB.goto(900,0)
#creating Ball makes it move in diagonal direction in fixed speed with ball.dx = 3 and ball.dy = 3
#Speed depends on the power of your PC or Mac, you can change dx and dy according to ur computer speed(mine sucks so 3 is pretty fast for me)
ball = turtle.Turtle()
ball.speed(0)
ball.shape("square")
ball.color("white")
ball.shapesize(1.8,1.8)
ball.penup()
ball.goto(0,0)
ball.x = 5
ball.y = 5
#Middle Line
#Creates multiple lines, enumerates them then checks for each enumerate with idx
#t variable is number of turtles, a line that goes down the middle
turtles = [turtle.Turtle() for _ in range(100)]
for idx, t in enumerate(turtles):
t.speed(0)
t.shape("square")
t.shapesize(2,0.1)
t.color("white")
t.penup()
t.goto(0,540-10*idx)
#Movings Functions
#Paddle A Up with (w) key for player A(1)
def paddleAUp():
y = paddleA.ycor()
y += 20
paddleA.sety(y)
#Paddle A Down with (s) Key for player A(1)
def paddleADown():
y = paddleA.ycor()
y -= 20
paddleA.sety(y)
#Paddle B Up with (Up_Arrow) Key for player B(2)
def paddleBUp():
y = paddleB.ycor()
y += 20
paddleB.sety(y)
#Paddle B Down (Down_Arrow) key for player B(2)
def paddleBDown():
y = paddleB.ycor()
y -= 20
paddleB.sety(y)
#Binding the Moving functions to Keyboard
#Pong.listen, listens to keyboard input
pong.listen()
#Moves Paddle A(1) up and down the y axis with (w) and (s) key respectively
pong.onkeypress(paddleAUp,"w")
pong.onkeypress(paddleADown,"s")
#Moves Paddle B(2) up and down the y axis with (Up_Arrow) and (Down_Arrow) key respectively
pong.onkeypress(paddleBUp,"Up")
pong.onkeypress(paddleBDown,"Down")
#Scores
AScore = 0
BScore = 0
#Scoring System for Player A(1)
ScoreSystemA = turtle.Turtle()
ScoreSystemA.pencolor("White")
ScoreSystemA.penup()
ScoreSystemA.setposition(-950,480)
ScoreSystemA.pendown()
ScoreSystemA.write(f"P1 Score: {AScore}",font=("courier",30,"normal"))
ScoreSystemA.hideturtle()
#Scoring System for Player B(2)
ScoreSystemB = turtle.Turtle()
ScoreSystemB.pencolor("White")
ScoreSystemB.penup()
ScoreSystemB.setposition(680,480)
ScoreSystemB.pendown
ScoreSystemB.write(f"P2 Score: {BScore}", font=("courier",30,"normal"))
ScoreSystemB.hideturtle()
#Main Loop To check canvas and update it each millisecond
while True:
pong.update()
#Makes Ball Move
ball.setx(ball.xcor() + ball.x)
ball.sety(ball.ycor() + ball.y)
#Ball Bouncing when it hits edge, Edge Detection at +y
if ball.ycor() > 510:
ball.sety(510)
ball.y = ball.y * -1
#Ball Bouncing when it hits edge, Edge Detection at -y
if ball.ycor() < -510:
ball.sety(-510)
ball.y = ball.y * -1
#Counting scoring system, when Ball goes Behind Paddle the Ball Resets and Goes in the Other Direction
#Which will then update the Score Text at the upper Left Corner
if ball.xcor() > 950:
ball.goto(0,0)
ball.x *= -1
AScore = AScore + 1
ScoreSystemA.clear()
ScoreSystemA.write(f"P1 Score: {AScore}",font=("courier",30,"normal"))
#Same As Above but for Paddle B
if ball.xcor() < -950:
ball.goto(0,0)
ball.x *= -1
BScore = BScore + 1
ScoreSystemB.clear()
ScoreSystemB.write(f"P2 Score: {BScore}", font=("courier",30,"normal"))
#Winning Condition writes Player 1(A) Won and stops the Game
if AScore == 3:
AWin = turtle.Turtle()
AWin.pencolor("White")
AWin.hideturtle()
AWin.penup()
AWin.setposition(0,0)
AWin.pendown()
AWin.write("P1 Wins!",align="center",font=("courier",60,"normal"))
turtles.clear()
turtle.done()
#Same As Above but for Paddle B
if BScore == 3:
BWin = turtle.Turtle()
BWin.pencolor("White")
BWin.hideturtle()
BWin.penup()
BWin.setposition(0,0)
BWin.pendown()
BWin.write("P2 Wins!",align="center",font=("courier",60,"normal"))
turtles.clear()
turtle.done()
#Colission System first 2 conditions are for ball x coordinate to check if it's at the same x value as the paddle
#Third if ball is less than paddle y cor for top half of the paddle
#Fourth if ball is greater than paddle y cor for bottom half of the paddle
if ball.xcor() < -900 and ball.xcor() > -950 and (ball.ycor() < paddleA.ycor() + 72 and ball.ycor() > paddleA.ycor() - 72):
ball.x = ball.x * -1
#Same As Above but for Paddle B
if ball.xcor() > 900 and ball.xcor() < 950 and (ball.ycor() < paddleB.ycor() + 72 and ball.ycor() > paddleB.ycor() - 72):
ball.x = ball.x * -1
here is the bit i'm struggling with:
#Start Click Function
def clickStart(x,y):
if x > startGame.xcor() - 200 and x < startGame.xcor() + 200 and y > startGame.ycor() - 75 and y < startGame.ycor() + 75:
time.sleep(0.5)
mainTitle.clear()
pong.bgcolor("black")
startGame.hideturtle()
#Get rid of Main Menu
mainCanvas.color("black")
mainCanvas.goto(0,0)
mainCanvas.begin_fill()
#List to change canvas to desired color once clicked
fd_list=[(90, 540), (0, 960), (270, 1080),(180,1920),(90,1080),(0,960)]
for hd, fwd in fd_list:
mainCanvas.setheading(hd)
mainCanvas.fd(fwd)
mainCanvas.end_fill()
#Hide Button
startGame.goto(0,5000)
#Key Binding Main Menu
pong.listen()
pong.onscreenclick(clickStart,1)
any help is appreciated
i tried: making a condition where if click happens then the game loop starts, when i did that and i clicked the canvas just turned all black, i think it returned none
i tried: making a second game loop, that stops when clicking the start button, that just broke
What i expected: i run code, game opens and does nothing, till i press the start button then the game starts and it plays.
You've made this difficult to implement by putting too much functionality at the top level of the code instead of encapsulated in functions. I've reworked your code to shoehorn in this functionality below. Your "start" button is just a giant circle as I don't have your artwork:
from turtle import Screen, Turtle
SMALL_FONT = ("Courier", 30, "normal")
BIG_FONT = ("Courier", 60, "normal")
MENU_FONT = ("a Absolute Empire", 60, "normal")
WINDOW_WIDTH, WINDOW_HEIGHT = 1920, 1080
fd_list = [(90, WINDOW_HEIGHT/2), (0, WINDOW_WIDTH/2), (270, WINDOW_HEIGHT), (180, WINDOW_WIDTH), (90, WINDOW_HEIGHT), (0, WINDOW_WIDTH/2)]
def clickStart(x, y):
if startGame.xcor() - 200 < x < startGame.xcor() + 200 and startGame.ycor() - 75 < y < startGame.ycor() + 75:
screen.onscreenclick(None)
mainTitle.clear()
screen.bgcolor("black")
startGame.hideturtle()
# Get rid of Main Menu
mainCanvas.clear()
startGame.hideturtle()
# Moves Paddle A(1) up and down the y axis with (w) and (s) key respectively
screen.onkeypress(paddleAUp, "w")
screen.onkeypress(paddleADown, "s")
paddleA.showturtle()
# Moves Paddle B(2) up and down the y axis with (Up_Arrow) and (Down_Arrow) key respectively
screen.onkeypress(paddleBUp, "Up")
screen.onkeypress(paddleBDown, "Down")
paddleB.showturtle()
screen.listen()
play()
# Movings Functions
# Paddle A Up with (w) key for player A(1)
def paddleAUp():
paddleA.forward(20)
# Paddle A Down with (s) Key for player A(1)
def paddleADown():
paddleA.backward(20)
# Paddle B Up with (Up_Arrow) Key for player B(2)
def paddleBUp():
paddleB.forward(20)
# Paddle B Down (Down_Arrow) key for player B(2)
def paddleBDown():
paddleB.backward(20)
# Scores
AScore = 0
BScore = 0
# Main Loop To check canvas and update it each millisecond
def play():
global AScore, BScore
# Make Ball Move
ball.setx(ball.xcor() + ball.x)
ball.sety(ball.ycor() + ball.y)
# Ball Bouncing when it hits edge
if ball.ycor() > 510:
ball.sety(510)
ball.y *= -1
elif ball.ycor() < -510:
ball.sety(-510)
ball.y *= -1
# Counting scoring system, when Ball goes Behind Paddle the Ball Resets and Goes in the Other Direction
# Which will then update the Score Text at the upper Left Corner
if ball.xcor() > 950:
ball.goto(0, 0)
ball.x *= -1
AScore += 1
ScoreSystemA.clear()
ScoreSystemA.write(f"P1 Score: {AScore}", align='center', font=SMALL_FONT)
elif ball.xcor() < -950:
ball.goto(0, 0)
ball.x *= -1
BScore += 1
ScoreSystemB.clear()
ScoreSystemB.write(f"P2 Score: {BScore}", align='center', font=SMALL_FONT)
# Winning Condition writes Player 1(A) Won and stops the Game
if AScore == 3:
midLine.clear()
ball.hideturtle()
AWin = Turtle()
AWin.hideturtle()
AWin.pencolor("White")
AWin.write("P1 Wins!", align="center", font=BIG_FONT)
screen.update()
return
if BScore == 3:
midLine.clear()
ball.hideturtle()
BWin = Turtle()
BWin.hideturtle()
BWin.pencolor("White")
BWin.write("P2 Wins!", align="center", font=BIG_FONT)
screen.update()
return
# Colission System first 2 conditions are for ball x coordinate to check if it's at the same x value as the paddle
# Third if ball is less than paddle y cor for top half of the paddle
# Fourth if ball is greater than paddle y cor for bottom half of the paddle
if -950 < ball.xcor() < -900 and paddleA.ycor() - 72 < ball.ycor() < paddleA.ycor() + 72:
ball.x *= -1
elif 900 < ball.xcor() < 950 and paddleB.ycor() - 72 < ball.ycor() < paddleB.ycor() + 72:
ball.x = ball.x * -1
screen.update()
screen.ontimer(play)
screen = Screen()
screen.title("My First Project")
screen.bgcolor("black")
screen.setup(WINDOW_WIDTH, WINDOW_HEIGHT)
# screen.register_shape("start_400x150.gif") # PNG for start button
screen.tracer(0)
# Create Paddle A, Player 1 (left Side)
paddleA = Turtle()
paddleA.hideturtle()
paddleA.shape("square")
paddleA.shapesize(1, 9)
paddleA.color("white")
paddleA.penup()
paddleA.setheading(90)
paddleA.setx(-900)
# Create Paddle B, Player 2 (Right Side)
paddleB = paddleA.clone()
paddleB.setx(900)
# Create Ball making it move in diagonal direction in fixed speed
ball = Turtle()
ball.shape("square")
ball.color("white")
ball.shapesize(1.8)
ball.penup()
ball.x = 5 # user properties
ball.y = 5
# Middle Line
midLine = Turtle()
midLine.hideturtle()
midLine.color("white")
midLine.pensize(2)
midLine.penup()
midLine.sety(-WINDOW_HEIGHT/2)
midLine.pendown()
midLine.sety(WINDOW_HEIGHT/2)
# Scoring System for Player A(1)
ScoreSystemA = Turtle()
ScoreSystemA.hideturtle()
ScoreSystemA.color("White")
ScoreSystemA.penup()
ScoreSystemA.setposition(-480, 420)
ScoreSystemA.write(f"P1 Score: {AScore}", align='center', font=SMALL_FONT)
# Scoring System for Player B(2)
ScoreSystemB = Turtle()
ScoreSystemB.hideturtle()
ScoreSystemB.color("White")
ScoreSystemB.penup()
ScoreSystemB.setposition(480, 420)
ScoreSystemB.write(f"P2 Score: {BScore}", align='center', font=SMALL_FONT)
# Create Menu
mainCanvas = Turtle()
mainCanvas.hideturtle()
mainCanvas.color("cyan")
mainCanvas.begin_fill()
for heading, distance in fd_list:
mainCanvas.setheading(heading)
mainCanvas.forward(distance)
mainCanvas.end_fill()
# Create Title
mainTitle = Turtle()
mainTitle.hideturtle()
mainTitle.penup()
mainTitle.sety(270)
mainTitle.write("Main Menu", align="center", font=MENU_FONT)
# Create Start Option
startGame = Turtle()
startGame.penup()
startGame.sety(100)
# startGame.shape("start_400x150.gif")
startGame.shape('circle')
startGame.shapesize(20)
# Key Binding Main Menu
screen.onscreenclick(clickStart)
screen.update()
screen.mainloop()
As you can see, I've also made a number of other changes to streamline your code and make it behave properly in an event-driven environment.

I have problem with my game, when the ball goes over the block, it is not deleting from my screen

Someone can help me please?
I spent many hours to understand the problem.. (Without success 🤣)
I tried to built a 80s hit game.
The problem is that when the ball goes on one of the stones, I catch the event (shows me in the console) and update the list of blocks but the block is not deleted from the screen as if nothing happened and I did not update any list
this is my code:
import time
from turtle import Screen, Turtle
import random
screen = Screen()
screen.bgcolor("black")
screen.setup(width=800, height=600)
screen.tracer(0)
player = Turtle("square")
player.shapesize(1.0, 4.0, 0)
player.color("blue")
player.penup()
player.goto(0, -250)
screen.tracer(0)
blue_turtle = []
blue_positions = []
for i in range(7):
turtle = Turtle("square")
turtle.shapesize(2.0 ,4.0, 0)
turtle.color("blue")
turtle.penup()
blue_positions.append((-300 + i * 100, 200))
blue_turtle.append(turtle)
def renderBlocks(b):
for i in range(len(b) - 1):
if b[i] == None:
print("Skipped")
continue
else:
x, y= blue_positions[i]
b[i].goto(x=x, y=y)
# total += 100
ball = Turtle("circle")
ball.color("white")
game_on = True
def move():
x = ball.xcor() + 10
y = ball.ycor()+ 10
ball.goto(x=x, y=y)
while game_on:
move()
renderBlocks(blue_turtle)
for i in range(len(blue_turtle) - 1):
if (blue_turtle[i] != None) and ball.distance(blue_turtle[i]) < 20:
blue_turtle[i] = (None)
time.sleep(0.1)
screen.update()
screen.exitonclick()
I believe the problem is here:
blue_turtle[i] = (None)
You tell your code that the turtle has been eliminated but you don't tell turtle graphics that it should be removed. Instead consider:
blue_turtle[i].hideturtle()
blue_turtle[i] = None
My rework of your code addressing this issue and some others:
from turtle import Screen, Turtle
def renderBlocks(b):
for i in range(len(b) - 1):
if b[i]:
x, y = blue_positions[i]
b[i].goto(x, y)
def move():
if game_on:
x = ball.xcor() + 10
y = ball.ycor() + 10
ball.goto(x, y)
renderBlocks(blue_turtles)
for i in range(len(blue_turtles) - 1):
if blue_turtles[i] and ball.distance(blue_turtles[i]) < 20:
blue_turtles[i].hideturtle()
blue_turtles[i] = None
screen.update()
screen.ontimer(move, 100) # milliseconds
screen = Screen()
screen.setup(width=800, height=600)
screen.bgcolor('black')
screen.tracer(0)
player = Turtle('square')
player.shapesize(1, 4, 0)
player.color('blue')
player.penup()
player.sety(-250)
blue_turtles = []
blue_positions = []
for i in range(7):
turtle = Turtle('square')
turtle.shapesize(2, 4, 0)
turtle.color('blue')
turtle.penup()
blue_positions.append((-300 + i * 100, 200))
blue_turtles.append(turtle)
ball = Turtle('circle')
ball.color('white')
game_on = True
move()
screen.exitonclick()

Start the game when SPACE is pressed (Turtle module)

I've been trying to code the Pong minigame using Turtle Graphics. Everything seems to work perfectly except for the beginning. I want the main loop to start iterating ONLY once the space key is pressed.
Here is the part i've been having trouble with:
## Start the game
start = False
def start_game():
startmessage.clear() #This is a turtle i created to show the message "Press SPACE to start"
start = True
ball_start() #This is a function i created to get the ball moving
wn.onkeypress(start_game, "space")
## Main loop
while start == True:
I've included .listen() and .mainloop(), so that's not the problem.
The full code is below. If i run the program with that code, this is what it does:
It asks for the user to enter the max points. The black window appears, the score table also appears, but for some reason the border doesn't.
When the max points value is entered in the shell, the message "Press SPACE to start" appeats in the black screen.
As soon as Space is pressed, that message disappears and nothing else occurs.
Here is the full code in case I'm missing something important:
import turtle
import random
import time
## Screen setup
wn = turtle.Screen()
wn.title("Pong!")
wn.bgcolor("black")
wn.setup(width = 900, height = 700)
wn.tracer(0)
# Border
collisions = 0
border = turtle.Turtle()
border.penup()
border.color("white")
border.setposition(-400,-300)
border.pendown()
for side in range(2):
border.forward(800)
border.left(90)
border.forward(600)
border.left(90)
border.hideturtle()
# Scores
scoreA = 0
scoreB = 0
score_marker = turtle.Turtle()
score_marker.shape("blank")
score_marker.color("yellow")
score_marker.speed(0)
score_marker.penup()
score_marker.setposition(0, 310)
score_marker.pendown()
score_marker.write("Player A : {} Player B: {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))
# Select number of points
maxpoints = int(input("Enter max points: "))
print("The player who first gets to {} points wins the game!".format(maxpoints))
# Start message
startmessage = turtle.Turtle()
startmessage.speed(0)
startmessage.color("white")
startmessage.shape("blank")
startmessage.penup()
startmessage.setposition(0,75)
startmessage.pendown()
startmessage.write("Press SPACE to start", align = "center", font = ("Courier", 20, "bold"))
# End message
endmessage = turtle.Turtle()
endmessage.speed(0)
endmessage.color("green")
endmessage.shape("blank")
endmessage.penup()
endmessage.setposition(0,0)
endmessage.pendown()
## Paddles
paddleB_speed = 25
paddleA_speed = paddleB_speed
wn.listen()
# Paddle A
paddleA = turtle.Turtle()
paddleA.speed(0)
paddleA.shape("square")
paddleA.color("white")
paddleA.shapesize(3.2,0.7)
paddleA.penup()
paddleA.goto(-350,0)
# Paddle A movement
def a_up():
y = paddleA.ycor() + paddleA_speed
paddleA.sety(y)
def a_down():
y = paddleA.ycor() - paddleA_speed
paddleA.sety(y)
wn.onkeypress(a_up,"w")
wn.onkeypress(a_down,"s")
# Paddle B
paddleB = turtle.Turtle()
paddleB.speed(0)
paddleB.shape("square")
paddleB.color("white")
paddleB.shapesize(3.2,0.7)
paddleB.penup()
paddleB.goto(350,0)
# Paddle B movement
def b_up():
y = paddleB.ycor() + paddleB_speed
paddleB.sety(y)
def b_down():
y = paddleB.ycor() - paddleB_speed
paddleB.sety(y)
wn.onkeypress(b_up,"Up")
wn.onkeypress(b_down,"Down")
## Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.shapesize(0.5,0.5)
ball.penup()
ball.setposition(0,0)
ballspeed = 0.3
ballspeed_increase = 0.01
# Ball starting movement
def ball_start():
angle_ranges = list(range(30,60)) + list(range(120,150)) + list(range(210,240)) + list(range(300,330))
angle = random.choice(angle_ranges)
ball.setheading(angle)
ball_start()
## Exit the game
def exit_game():
wn.bye()
## Start the game
start = False
def start_game():
startmessage.clear()
start = True
ball_start()
wn.onkeypress(start_game, "space")
## Main loop
while start == True:
wn.update()
### MOVEMENT
## Ball movement
ball.forward(ballspeed)
### COLLISIONS
## Paddles and border
# Paddle A
if paddleA.ycor() > 268:
paddleA.sety(268)
if paddleA.ycor() < -268:
paddleA.sety(-268)
# Paddle B
if paddleB.ycor() > 268:
paddleB.sety(268)
if paddleB.ycor() < -268:
paddleB.sety(-268)
## Ball and paddles
if paddleA.distance(ball) <= 10:
collisions += 1
#direction = ball.heading()
#ball.setheading(180 - random.randint(0,30) - direction)
ball.setheading(random.randint(110,250) + 180)
ball.forward(ballspeed + ballspeed_increase)
if paddleB.distance(ball) <= 10:
collisions += 1
#direction = ball.heading()
#ball.setheading(180 - random.randint(0,30) - direction)
ball.setheading(random.randint(110,250))
ball.forward(ballspeed + ballspeed_increase)
## Ball and border
# Top and bottom borders
if ball.ycor() < - 296 or ball.ycor() > 296:
collisions += 1
direction = ball.heading()
ball.setheading(360 - direction)
ball.forward(ballspeed + ballspeed_increase)
# Left and right borders
if ball.xcor() < -396: #--> Player B wins the point
delay = 0.1
time.sleep(1)
collisions += 1
ball.setposition(0,0)
scoreB += 1
score_marker.clear()
score_marker.write("Player A : {} Player B: {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))
ball_start()
if ball.xcor() > 396: #--> Player A wins the poin
delay = 0.1
time.sleep(1)
collisions += 1
ball.setposition(0,0)
scoreA += 1
score_marker.clear()
score_marker.write("Player A : {} Player B: {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))
ball_start()
# End of the game
if scoreA == maxpoints or scoreB == maxpoints:
if scoreA == maxpoints:
print("Player A wins the game!")
endmessage.write("Player A wins the game!\nA scored {} points\nB scored {} points".format(scoreA,scoreB), align = "center", font = ("Courier", 18, "bold"))
time.sleep(1)
endmessage.penup()
endmessage.setposition(0,-100)
endmessage.pendown()
endmessage.color("red")
endmessage.write("Press ESC to exit game", align = "center", font = ("Courier", 14, "normal"))
wn.onkeypress(exit_game, "Escape")
break
if scoreB == maxpoints:
print("Player B wins the game!")
endmessage.write("Player B wins the game!\nA scored {} points\nB scored {} points".format(scoreA,scoreB), align = "center", font = ("Courier", 18, "bold"))
time.sleep(1)
endmessage.penup()
endmessage.setposition(0,-100)
endmessage.pendown()
endmessage.color("red")
endmessage.write("Press ESC to exit game", align = "center", font = ("Courier", 14, "normal"))
wn.onkeypress(exit_game, "Escape")
break
wn.mainloop()
This code looks like it resets start but it doesn't -- it sets a local start and ignores the global start:
start = False
def start_game():
startmessage.clear()
start = True
ball_start()
You need a global statement:
start = False
def start_game():
global start
startmessage.clear()
start = True
ball_start()
The above is necessary but not sufficient. The next problem is the way you use a top level while loop instead of a timer event. The way I'd expect this game to start up and run would be more like:
from turtle import Screen, Turtle
running = False
def start_game():
global running
start_message.clear()
running = True
ball_start()
def ball_start():
start_message.write("We've started the game!", align="center", font=("Courier", 20, "bold"))
# what really ball_start() really does replaces the above...
def move_one_step():
if running:
screen.update()
# ...
screen.ontimer(move_one_step, 100)
screen = Screen()
start_message = Turtle()
start_message.hideturtle()
start_message.penup()
start_message.sety(75)
start_message.write("Press SPACE to start", align="center", font=("Courier", 20, "bold"))
screen.onkeypress(start_game, 'space')
screen.listen()
move_one_step()
screen.mainloop()
I think it might be the way you used the space key value. You put in space instead of return.
wn.onkeypress(start_game, "return")

When press a key to move the turtle up, my other turtles freeze

When I run my code and I move my turtle up with the space bar, all the obstacles, that are supposed to be moving, stop moving. What causes the problem and how do I fix this?
I have no idea what can cause this problem and I've tried Googling but can't find anything. Since this is my first week of trying out Python, or programming in general, I have no idea what I've done wrong.
import turtle
import math
import random
#starting conditions
player = turtle.Turtle()
player.hideturtle()
player.penup()
player.shape("turtle")
player.setheading(90)
player.setpos(-200,0)
player.speed(1)
player.color("yellow")
canvas = turtle.Screen()
canvas.bgcolor("black")
canvas.title("gamescreen")
gameover = turtle.Turtle()
gameover.penup()
gameover.hideturtle()
gameover.color("red")
gameover.speed(0)
gameover.setpos(-150, 330)
scoreboard = turtle.Turtle()
scoreboard.hideturtle()
scoreboard.color("blue")
scoreboard.penup()
scoreboard.setpos(-300,320)
#borders
box = turtle.Turtle()
box.speed(0)
box.hideturtle()
box.setheading(0)
box.color("blue")
box.pensize(3)
box.penup()
box.setpos(-300,-300)
for i in range(4):
box.pendown()
box.forward(600)
box.left(90)
player.showturtle()
#movement
spd = 50
def playerup():
player.sety(player.ycor()+ spd)
if (player.ycor()+ spd) > 287:
player.speed(0)
player.sety(287)
player.speed(1)
def playerdown():
player.sety(player.ycor()- spd)
if (player.ycor()+ spd) < -287:
player.speed(0)
player.sety(-287)
player.speed(1)
turtle.listen()
gravity = 3
obsspd = 3
#collision
def hit(t1, t2):
xdistance = t1.xcor()-t2.xcor()
ydistance = t1.ycor()-t2.ycor()
if (abs(xdistance) < 20) and (abs(ydistance) < 130):
return True
else:
return False
#obstacle list
number_obstacles = 2
obstacles = []
numberslistx = list(range(-100,280))
numberslisty = list(range(143,190))
for i in range(number_obstacles):
obstacles.append(turtle.Turtle())
for obstacle in obstacles:
obstacle.hideturtle()
obstacle.speed(0)
obstacle.color("green")
obstacle.penup()
obstacle.shape("square")
obstacle.turtlesize(12,3)
xobs = random.choice(numberslistx)
yobs = random.choice(numberslisty)
obstacle.setposition(xobs,yobs)
obstacle.showturtle()
#obstacle2 list
number_obstacles2 = 2
obstacles2 = []
numberslistx = list(range(-100,280))
numberslisty = list(range(160,190))
for i in range (number_obstacles2):
obstacles2.append(turtle.Turtle())
for obstacle2 in obstacles2:
obstacle2.hideturtle()
obstacle2.speed(0)
obstacle2.color("green")
obstacle2.penup()
obstacle2.shape("square")
xobs = random.choice(numberslistx)
yobs = random.choice(numberslisty)
obstacle2.turtlesize(12,3)
obstacle2.setposition(xobs,-yobs)
obstacle2.showturtle()
if(obstacle.xcor()-obstacle2.xcor())> 10:
obstacle.setposition(xobs,yobs)
obstacle2.setposition(xobs,-yobs)
#border
def fall():
if (player.ycor()< -300):
return True
def ceiling():
if (player.ycor() > 300):
return True
colors = ["red", "green","yellow","blue","purple","pink"]
points = 1
while True:
player.sety(player.ycor()-gravity)
xresetpos = random.choice(range(230,300))
yresetpos = random.choice(range(140,190))
for obstacle in obstacles:
obstacle.setx(obstacle.xcor()-obsspd)
if (obstacle.xcor()-obsspd) < -270:
obstacle.hideturtle()
obstacle.setx(xresetpos)
obstacle.sety(yresetpos)
obstacle.showturtle()
obsspd+=1
points += 1
display = points
scoreboard.clear()
scoreboard.write(display)
player.color(random.choice(colors))
obstacle.color(random.choice(colors))
for obstacle2 in obstacles2:
obstacle2.setx(obstacle2.xcor()-(obsspd))
if (obstacle2.xcor()-obsspd) < -270:
obstacle2.hideturtle()
obstacle2.setx(xresetpos)
obstacle2.sety(-(int(yresetpos))-15)
obstacle2.showturtle()
player.color(random.choice(colors))
obstacle2.color(random.choice(colors))
if hit(player, obstacle):
player.hideturtle()
player.setpos(400,0)
gameover.color("red")
gameover.setpos(-150,-20)
gameover.write("Game over",False,"left",("Arial",50,))
gameover.setpos(-160,-200)
gameover.write("Press x to play again",False,"left",("Arial",30,))
break
if hit(player, obstacle2):
player.hideturtle()
player.setpos(400,0)
gameover.setpos(-150,-20)
gameover.write("Game over",False,"left",("Arial",50,))
gameover.setpos(-160,-200)
gameover.write("Press x to play again",False,"left",("Arial",30,))
break
if fall():
player.hideturtle()
player.setpos(400,0)
gameover.setpos(-150,-20)
gameover.write("Game over",False,"left",("Arial",50,))
gameover.setpos(-160,-200)
gameover.write("Press x to play again",False,"left",("Arial",30,))
break
if ceiling():
player.setycor(280)
#if score(player,obstacle1):
# points += 1
# display = points
# scoreboard.clear()
# scoreboard.write(display)
turtle.onkeypress(playerup, "space")
#turtle.onkeypress(playerdown, "Down")
#if player.xcor() is obstacle1.xcor():
# points += 1
# scoreboard.clear()
# scoreboard.write(points)
#balken stoppen niet als jij beweegt
One problem is that your horizontal motion is controlled, out of sync, by a while True: loop but your vertical motion is controlled, in sync, by a keyboard event. We need to get both motions in sync using events via replacing your while True: with an ontimer() event. Here's my complete rework of your code along these lines with a few simplifications for example purposes:
from turtle import Screen, Turtle
from random import choice, randrange
COLORS = ["red", "green", "yellow", "blue", "purple", "pink"]
PLAYER_SPEED = 50
GRAVITY = 3
NUMBER_OBSTACLES_UPPER = 2
NUMBER_OBSTACLES_LOWER = 2
# movement
def playerup():
screen.onkeypress(None, 'space') # disable handler inside handler
player.sety(player.ycor() + PLAYER_SPEED)
if player.ycor() > 287:
player.speed('fastest')
player.sety(287)
player.speed('slowest')
screen.onkeypress(playerup, 'space')
# collision
def hit(t1, t2):
xdistance = abs(t1.xcor() - t2.xcor())
if xdistance >= 20:
return False
ydistance = abs(t1.ycor() - t2.ycor())
return ydistance < 130
# border
def fall():
return player.ycor() < -300
def ceiling():
return player.ycor() > 300
# main program loop
def move():
global points, obstacle_speed_upper, obstacle_speed_lower
player.sety(player.ycor() - GRAVITY)
for obstacle in obstacles_upper:
obstacle.setx(obstacle.xcor() - obstacle_speed_upper)
if obstacle.xcor() < -270:
obstacle.hideturtle()
obstacle.setposition(randrange(230, 300), randrange(140, 190))
obstacle.showturtle()
obstacle_speed_upper += 1
points += 1
scoreboard.clear()
scoreboard.write(points, font=('Arial', 30,))
if hit(player, obstacle):
player.hideturtle()
gameover.write("Game Over", align='center', font=('Arial', 50,))
return
for obstacle in obstacles_lower:
obstacle.setx(obstacle.xcor() - obstacle_speed_lower)
if obstacle.xcor() < -270:
obstacle.hideturtle()
obstacle.setposition(randrange(230, 300), - randrange(160, 190))
obstacle.showturtle()
obstacle_speed_lower += 1
points += 1
scoreboard.clear()
scoreboard.write(points, font=('Arial', 30,))
if hit(player, obstacle):
player.hideturtle()
gameover.write("Game Over", align='center', font=('Arial', 50,))
return
if ceiling() or fall():
player.hideturtle()
gameover.write("Game Over", align='center', font=('Arial', 50,))
return
screen.ontimer(move, 100)
# starting conditions
screen = Screen()
screen.setup(750, 750)
screen.bgcolor('black')
screen.title("Game Screen")
# borders
box = Turtle()
box.hideturtle()
box.color('blue')
box.speed('fastest')
box.pensize(3)
box.penup()
box.setpos(-300, -300)
box.pendown()
for _ in range(4):
box.forward(600)
box.left(90)
gameover = Turtle()
gameover.hideturtle()
gameover.color('red')
gameover.penup()
gameover.sety(-25)
points = 0
scoreboard = Turtle()
scoreboard.hideturtle()
scoreboard.color('blue')
scoreboard.penup()
scoreboard.setpos(-300, 320)
scoreboard.write(points, font=('Arial', 30,))
player = Turtle()
player.hideturtle()
player.shape('turtle')
player.speed('slowest')
player.color('yellow')
player.setheading(90)
player.penup()
player.setx(-200)
player.showturtle()
# obstacle list
obstacle_speed_upper = 3
obstacles_upper = []
for _ in range(NUMBER_OBSTACLES_UPPER):
obstacle = Turtle()
obstacle.hideturtle()
obstacle.shape('square')
obstacle.turtlesize(12, 3)
obstacle.speed('fastest')
obstacle.color(choice(COLORS))
obstacle.penup()
xobs = randrange(-100, 280)
yobs = randrange(145, 190)
obstacle.setposition(xobs, yobs)
obstacle.showturtle()
obstacles_upper.append(obstacle)
# lower obstacles list
obstacle_speed_lower = 3
obstacles_lower = []
for _ in range(NUMBER_OBSTACLES_LOWER):
obstacle = Turtle()
obstacle.hideturtle()
obstacle.shape('square')
obstacle.turtlesize(12, 3)
obstacle.speed('fastest')
obstacle.color(choice(COLORS))
obstacle.penup()
xobs = randrange(-100, 280)
yobs = randrange(160, 190)
obstacle.setposition(xobs, -yobs)
obstacle.showturtle()
obstacles_lower.append(obstacle)
screen.onkeypress(playerup, 'space')
screen.listen()
move()
screen.mainloop()

Pong Created in Python Turtle

I'm new to Python but I've coded in other languages, mainly for hardware. I made pong in Python using turtle but it's a little glitchy. I was wondering if any of you could check it out and give advice. I also want to add a start screen and end screen but am a little unsure how to. Also if you have any advice on how to improve collision detection, please let me know.
I'm pasting code below
import os
import math
import random
import time
#set up screen
screen = turtle.Screen()
screen.bgcolor("green")
screen.title("Pong")
# set up border
border_pen = turtle.Turtle()
border_pen.speed(0)
border_pen.color("white")
border_pen.penup()
border_pen.setposition(-300,-300)
border_pen.pendown()
border_pen.pensize(3)
for side in range(4):
border_pen.fd(600)
border_pen.lt(90)
border_pen.hideturtle()
#set score to 0
score = 0
#set time to zero
time = 0
seconds = 0
#Draw score
score_pen = turtle.Turtle()
score_pen.speed(0)
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290, 310)
scorestring = "Score %s" %score
score_pen.write(scorestring, False, align="left", font= ("Arial", 14, "normal"))
score_pen.hideturtle()
#Draw timer
time_pen = turtle.Turtle()
time_pen.speed(0)
time_pen.color("white")
time_pen.penup()
time_pen.setposition(260, 310)
timestring = "Time %s" %time
time_pen.write(timestring, False, align="left", font= ("Arial", 14, "normal"))
time_pen.hideturtle()
#create the player turtle
player = turtle.Turtle()
player.color("blue")
player.shape("square")
player.shapesize(0.5, 4)
player.penup()
player.speed(0)
player.setposition(-280,-250)#(x,y)
player.setheading(90)
playerspeed = 15
#create the AIplayer turtle
AIplayer = turtle.Turtle()
AIplayer.color("black")
AIplayer.shape("square")
AIplayer.shapesize(0.5, 4)
AIplayer.penup()
AIplayer.speed(0)
AIplayer.setposition(280,250)#(x,y)
AIplayer.setheading(90)
AIplayerspeed = 15
#create the pong
pong = turtle.Turtle()
pong.color("red")
pong.shape("circle")
pong.shapesize(0.5, 0.5)
pong.penup()
pong.speed(10)
pong.setposition(0,0)#(x,y)
pongspeed = 15
pong.goto(0, 265)
pong.dy = -5
pong.dx = 5
#Move player up and down
def move_up():
y = player.ycor()
y += playerspeed
if y > 265:
y = 260
player.sety(y)
def move_down():
y = player.ycor()
y -= playerspeed
if y < -265:
y = -260
player.sety(y)
#keyboard bindings
turtle.listen()
turtle.onkey(move_up, "Up")
turtle.onkey(move_down, "Down")
#turtle.onkey(fire_bullet, "space")
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()- t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 20:
return True
else:
return False
#main game loop
while True:
#move pong ball
pong.sety(pong.ycor() +pong.dy)
pong.setx(pong.xcor() +pong.dx)
#check for bounce and redirect it
if pong.ycor() < -300:
pong.dy *= -1
if pong.ycor() > 300:
pong.dy *= -1
if pong.xcor() < -300:
pong.dx *= -1
print("Game Over")
exit()
if pong.xcor() > 300:
pong.dx *= -1
#move AI paddle (might speed up pong movement)
y = pong.ycor()
y += AIplayerspeed
AIplayer.sety(y)
if AIplayer.ycor() > 265:
AIplayerspeed *= -1
if AIplayer.ycor() < -250:
AIplayerspeed *= -1
#collision pong and player
if isCollision(pong, player):
pong.dy *= -1
pong.dx *= -1
#Update the score
score += 10
scorestring = "Score: %s" %score
score_pen.clear()
score_pen.write(scorestring, False, align="left", font=("Arial", 14, "normal"))
#collision pong and AIplayer
if isCollision(pong, AIplayer):
pong.dy *= -1
pong.dx *= -1
#updates timer and increases ball speed
if seconds > 29:
pong.dy *= -2
pong.dx *= -2
if seconds > 59:
pong.dy *= -3
pong.dx *= -3
#displays timer but makes game laggy
# seconds += 0.1
# time = seconds
# timestring = "Time: %s" %time
# time_pen.clear()
# time_pen.write(timestring, False, align="Left", font=("Arial", 14, "normal"))
Some issues I see:
You've stretched a 20 by 20 square to be 10 by 80:
AIplayer.shapesize(0.5, 4)
But your collision distance is only 20 from center, so your ball can
cross over the bottom or top of the paddle without actually
colliding.
Your isCollision() function is mostly redundant with turtle's own
.collision() method.
You shouldn't have while True: in an event-driven world like turtle
as it potentially prevents some events from firing. Better to
replace it with a timer event.
Some of your collisions change both x and y deltas when they should
only change one of them.
You should avoid redundant queries of the turtle in your main loop as well as checking conditions that are negated by other logic clauses. I.e. do as little as you can get away with in the main loop.
Below is my rework of your game along the above lines, plus lots of other style and logic changes:
from turtle import Turtle, Screen
FONT = ("Arial", 16, "normal")
def isCollision(t1, t2):
return t1.distance(t2) < 15
# set up screen
screen = Screen()
screen.bgcolor("darkgreen")
screen.title("Pong")
# set up border
border_pen = Turtle(visible=False)
border_pen.speed('fastest')
border_pen.color('white')
border_pen.pensize(3)
border_pen.penup()
border_pen.setposition(-300, -300)
border_pen.pendown()
for _ in range(4):
border_pen.forward(600)
border_pen.left(90)
# set score to 0
score = 0
# set time to zero
seconds = 0
# Draw score
score_pen = Turtle(visible=False)
score_pen.color("white")
score_pen.penup()
score_pen.setposition(-290, 310)
score_pen.write("Score {}".format(score), False, align="left", font=FONT)
# Draw timer
time_pen = Turtle(visible=False)
time_pen.color("white")
time_pen.penup()
time_pen.setposition(260, 310)
time_pen.write("Time {}".format(int(seconds)), False, align="left", font=FONT)
# create the player turtle
player = Turtle("square", visible=False)
player.shapesize(0.5, 3)
player.speed('fastest')
player.setheading(90)
player.color("blue")
player.penup()
player.setposition(-280, -250) # (x,y)
player.showturtle()
playerspeed = 15
# create the AIplayer turtle
AIplayer = Turtle("square", visible=False)
AIplayer.shapesize(0.5, 3)
AIplayer.speed('fastest')
AIplayer.setheading(90)
AIplayer.color("black")
AIplayer.penup()
AIplayer.setposition(280, 250) # (x,y)
AIplayer.showturtle()
AIplayerspeed = 15
# create the pong
pong = Turtle("circle", visible=False)
pong.shapesize(0.5, 0.5)
pong.speed('fast')
pong.color("red")
pong.penup()
pong.sety(265)
pong.showturtle()
pongspeed = 15
pong_dx, pong_dy = 5, -5
# Move player up and down
def move_up():
player.forward(playerspeed)
y = player.ycor()
if y > 265:
y = 260
player.sety(y)
screen.update()
def move_down():
player.backward(playerspeed)
y = player.ycor()
if y < -265:
y = -260
player.sety(y)
screen.update()
# keyboard bindings
screen.onkey(move_up, "Up")
screen.onkey(move_down, "Down")
screen.listen()
# main game loop
def move():
global pong_dx, pong_dy, AIplayerspeed, seconds, score
# move pong ball
x, y = pong.position()
x += pong_dx
y += pong_dy
pong.setposition(x, y)
if isCollision(pong, player): # collision pong and player
pong_dx *= -1
# Update the score
score += 10
score_pen.undo()
score_pen.write("Score: {}".format(score), align="left", font=FONT)
elif isCollision(pong, AIplayer): # collision pong and AIplayer
pong_dx *= -1
elif y < -300 or y > 300: # check for bounce and redirect it
pong_dy *= -1
elif x > 300:
pong_dx *= -1
elif x < -300:
print("Game Over")
screen.bye()
return
# move AI paddle (might speed up pong movement)
AIplayer.forward(AIplayerspeed)
y = AIplayer.ycor()
if y < -250 or y > 250:
AIplayerspeed *= -1
# display timer
seconds += 0.05
time_pen.undo()
time_pen.write("Time: {}".format(int(seconds)), False, align="Left", font=FONT)
screen.ontimer(move, 50)
screen.update()
screen.tracer(False)
move()
screen.mainloop()
I couldn't make sense of your "increases ball speed" logic so I left it out. I used a darker background color as the original was difficult to look at on my screen.
The issue related to the pong/ball speed can be due to your CPU. The ball moves 5 pixels in both (x and y) direction every screen update and the update rate depends on the CPU speed. The processes being executed by the CPU aren't constant and thus the CPU speed fluctuates. Also because we have screen.tracer() set to False it doesn't show animations. Thus, due to lack of animation and inconsistency of CPU speed, we see the speed of pong/ball increasing/decreasing.
For screen.tracer() explanation refer https://youtu.be/LH8WgrUWG_I?t=123
For "the increasing speed" explanation refer https://youtu.be/Hw1H3rG3POM?t=40
To get a bit more consistent behavior, you could add a long enough pause into your loop in order to offset the variability of the computing times and to avoid drawing useless frames. You can do this using time
import time
# Initialization
...
while True:
time.sleep(1 / 60)
# The rest of your game logic
...

Categories

Resources