I've just started coding a little game using turtle, but my very first prototype is already very laggy.
import turtle
import keyboard
# Player 1 x and y cords
p1x = -350
p1y = 250
wn = turtle.Screen()
wn.title("Actua")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
# Player 1 Setup
player_1 = turtle.Turtle()
player_1.speed(0)
player_1.shape("square")
player_1.color("red")
player_1.penup()
player_1.goto(p1x, p1y)
player_1.shapesize(1, 1)
win = turtle.Screen()
while True:
win.update()
# Controlls
if keyboard.read_key:
if keyboard.read_key() == "esc":
quit()
if keyboard.read_key() == "d" or keyboard.read_key() == "D":
p1x = p1x+10
if keyboard.read_key() == "a" or keyboard.read_key() == "A":
p1x = p1x-10
if keyboard.read_key() == "w" or keyboard.read_key() == "W":
p1y = p1y+10
if keyboard.read_key() == "s" or keyboard.read_key() == "S":
p1y = p1y-10
player_1.goto(p1x, p1y)
It's probably lagging because of the "while True:" but I don't know how to improve it. Are there just too many if-statements or do I first have to set specific FPS?
Further information:
I'm using VSCode,
my operating system is Windows 10,
my PC should normally be able to handle such a short code.
Oh, and please go easy on me with the technical terms, I'm kinda new to coding.
Edit: I just tested it again, it's definitely due to the if-statements themselves. However I still don't know how I could fix it.
Your code doesn't run at all on my system. My recommendation is to toss the keyboard module and use turtle's own built-in key event handler, as we should never have while True: in an event-driven world like turtle:
from turtle import Screen, Turtle
from functools import partial
# Players X and Y coordinates
p1x, p1y = -350, 250
p2x, p2y = 350, -250
def right(player):
player.setx(player.xcor() + 10)
screen.update()
def left(player):
player.setx(player.xcor() - 10)
screen.update()
def up(player):
player.sety(player.ycor() + 10)
screen.update()
def down(player):
player.sety(player.ycor() - 10)
screen.update()
screen = Screen()
screen.setup(width=800, height=600)
screen.bgcolor('black')
screen.tracer(False)
player_1 = Turtle()
player_1.shape('square')
player_1.color('red')
player_1.penup()
player_1.goto(p1x, p1y)
player_2 = player_1.clone()
player_2.color('green')
player_2.goto(p2x, p2y)
screen.onkey(partial(left, player_1), 'a')
screen.onkey(partial(right, player_1), 'd')
screen.onkey(partial(up, player_1), 'w')
screen.onkey(partial(down, player_1), 's')
screen.onkey(partial(left, player_2), 'Left')
screen.onkey(partial(right, player_2), 'Right')
screen.onkey(partial(up, player_2), 'Up')
screen.onkey(partial(down, player_2), 'Down')
screen.onkey(screen.bye, 'Escape')
screen.listen()
screen.update()
screen.mainloop()
I've added a second player on the arrow keys to make sure my code is compatible with two players.
hi you are using too many keyboard.read_kry() fun: means every if statment the program should call the fun again and again:
i think now its not laggy:
import turtle
import keyboard
# Player 1 x and y cords
p1x = -350
p1y = 250
wn = turtle.Screen()
wn.title("Actua")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
# Player 1 Setup
player_1 = turtle.Turtle()
player_1.speed(0)
player_1.shape("square")
player_1.color("red")
player_1.penup()
player_1.goto(p1x, p1y)
player_1.shapesize(1, 1)
win = turtle.Screen()
win.update()
while True:
key = keyboard.read_key()
if key == "esc":
quit()
elif key == "d" or key == "D":
p1x = p1x + 10
win.update()
elif key == "a" or key == "A":
p1x = p1x - 10
win.update()
elif key == "w" or key == "W":
p1y = p1y + 10
win.update()
elif key == "s" or key == "S":
p1y = p1y - 10
win.update()
player_1.goto(p1x, p1y)
Not quite sure if that would help, but try changing wn.tracer(0) parameter to something bigger (ex.10/20). The number inside means (if I understand correctly) the amount of milliseconds before another refresh takes place. I had the same problem just today, as I tried to make a simple "pong" game and it seemed to help.
Ps. on my machine it wouldn't even work with 0 as an argument
PPs. - I was wrong - see the comment below
Related
I'm trying to make a program that is essentially an etchasketck, with some minor tweaks for my school project(the required use of a main function, wasd as movement controls, and q to quit the program and p to pick up or drop down the turtle pen). I was testing this code in trinket.io and it was working fine. You can see it working there with this link: https://trinket.io/python/99fd3ec305. However, when I go to run it from pycharm, cmd, or the python IDLE, it always leaves the turtle hanging and unresponsive. I get no errors, just the turtle to pop up for a few seconds, then it hangs, and I'm unable to do anything.
Here's my code:
import sys
import turtle
arg_len = len(sys.argv)
# store length of arguments
if arg_len < 3:
print("Too less arguments, using default values..")
WIDTH = 200
HEIGHT = 200
else:
WIDTH = int(sys.argv[1])
HEIGHT = int(sys.argv[2])
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
# create a turtle instance
t = turtle.Turtle()
t.speed(0)
# slow down the turtle
# declare flags
move = False
exit_flag = False
def up():
global move
move = True
t.setheading(90)
def down():
global move
move = True
t.setheading(270)
def left():
global move
move = True
t.setheading(180)
def right():
global move
move = True
t.setheading(0)
# toggle pen up and down
def toggle_pen():
if t.isdown():
t.penup()
else:
t.pendown()
# set exit flag
def quit_program():
global exit_flag
exit_flag = True
def check_border():
if t.xcor() == WIDTH / 2:
t.penup()
t.setx(-WIDTH / 2)
elif t.xcor() == -WIDTH / 2:
t.penup()
t.setx(WIDTH / 2)
if t.ycor() == HEIGHT / 2:
t.penup()
t.sety(-HEIGHT / 2)
elif t.ycor() == -HEIGHT / 2:
t.penup()
t.sety(HEIGHT / 2)
def listen_keys():
screen.listen()
screen.onkey(up, "w")
screen.onkey(down, "s")
screen.onkey(left, "a")
screen.onkey(right, "d")
screen.onkey(toggle_pen, "p")
screen.onkey(quit_program, "q")
# main loop
def main():
listen_keys()
while not exit_flag:
global move
if move:
t.forward(0.5)
screen.update()
check_border()
else:
t.done()
main()
I'm using python 3.10, and I mainly use pycharm for the running.
I was trying to get the turtle to move indefinitly without user input after the first user input, I was going to achieve this with the while loop, but it just leaves my program unresponsive. Can anyone tell me what's wrong that I'm not seeing?
You've effectively put a while True: loop in an event-driven program where one should never be used. If I were writing this for the command line, with the constraints listed, I might go about it this way (dropping command line processing for example simplicity):
from turtle import Screen, Turtle
WIDTH, HEIGHT = 200, 200
def up():
turtle.setheading(90)
start_motion()
def down():
turtle.setheading(270)
start_motion()
def left():
turtle.setheading(180)
start_motion()
def right():
turtle.setheading(0)
start_motion()
def toggle_pen():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def quit_program():
screen.bye()
def check_border():
x, y = turtle.position()
if x >= WIDTH / 2:
turtle.penup()
turtle.setx(-WIDTH / 2)
elif x <= -WIDTH / 2:
turtle.penup()
turtle.setx(WIDTH / 2)
if y >= HEIGHT / 2:
turtle.penup()
turtle.sety(-HEIGHT / 2)
elif y <= -HEIGHT / 2:
turtle.penup()
turtle.sety(HEIGHT / 2)
def main():
screen.onkey(up, 'w')
screen.onkey(down, 's')
screen.onkey(left, 'a')
screen.onkey(right, 'd')
screen.onkey(toggle_pen, 'p')
screen.onkey(quit_program, 'q')
screen.listen()
screen.mainloop()
def move():
turtle.forward(1)
check_border()
screen.ontimer(move, 25)
moving = False
def start_motion():
global moving
if not moving:
moving = True
move()
screen = Screen()
screen.setup(WIDTH, HEIGHT)
turtle = Turtle()
turtle.speed('fastest')
main()
See if this still works with trinket.io, IDLE and PyCharm, or if it can be made to do so.
I have got a problem with how to end my turtle python game. The code seems to function if I place the turtles at the starting/ending point from the beginning of the code, but it does not register when the turtle reaches the endpoint in gameplay. From what I know I think my maths for the end function is right. I am new and appreciate the help. I am currently offline though.
CODE:
import time
import turtle
from turtle import *
wn = turtle.Screen()
name=textinput("Question", "what is your name")
#display
pencolor("white")
penup()
goto(0,170)
write("hello " +name,align='center',font=('Comic Sans', 20))
#wn = turtle.screen() if the code doesn't work
#diffrent turtles here
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t3 = turtle.Turtle()
#starting psoition
turtle.penup()
t1.penup()
turtle.goto(-1, -230)
t1.goto(-1, -170)
#starting line postion
def f():
fd(10)
def b():
bk(10)
def l():
left(10)
def r():
right(10)
#testing
def fo():
t1.fd(10)
def ba():
t1.bk(10)
def le():
t1.left(10)
def ri():
t1.right(10)
#turtle coordinates
first=turtle.ycor()
second=turtle.xcor()
third=t1.ycor()
fourth=t1.xcor()
#when to end the game
if (turtle.ycor()>= (-160)) and (turtle.ycor()<= (-240)):
if (turtle.xcor()>= (0)) and (turtle.xcor()<= (11)):
print("Finally working")
#replaced with write who the winner is later
if (t1.ycor()>= (-160)) and (t1.ycor()<= (-240)):
if (t1.xcor()>= (0)) and (t1.xcor()<= (11)):
print("Finally")
# onkey creates the key board = turtle.onkey("function, key") You have to keep pressing keys for it to move
turtle.onkey(f, "w")
turtle.onkey(b, "s")
turtle.onkey(l, "a")
turtle.onkey(r, "d")
wn.onkey(fo, "Up")
wn.onkey(ba, "Down")
wn.onkey(le, "Left")
wn.onkey(ri, "Right")
listen()
#WINDOW SETUP
window = Screen()
window.setup(800, 800)
window.title("Turtle game")
turtle.bgcolor("forestgreen")
t3.color("black")
t3.speed(0)
t3.penup()
t3.setpos(-140, 250)
t3.write("THE TURTLE RACE", font=("Comic Sans", 30, "bold"))
t3.penup()
#turtle ask name
#add images here
#turtle controls
# def creates a function. : means opperation f means move turtle foward. fd push turtle forward
# onkey creates the key board = turtle.onkey("function, key") You have to keep pressing keys for it to move
t2.speed(0)
t2.color("grey")
t2.pensize(100)
t2.penup()
t2.goto(-200, -200)
t2.left(90)
t2.pendown()
t2.forward(300)
t2.right(90)
t2.forward(500)
t2.right(90)
t2.forward(300)
t2.right(90)
t2.forward(500)
turtle.penup()
Firstly, your maths is not quite right - a coordinate can never be both <= -240 and >= -160. It should be t.ycor() >= -240 and t.ycor() <= -160, or more briefly, -240 <= t.ycor() <= -160.
Secondly, the condition as it stands is only checked once, when the code is first run. Instead, you need to get the program to check it regularly. You can do this by adding a general onkeypress event handler which is checked every time any key is pressed.
def check_status():
for player, t in enumerate([turtle, t1]):
if 0 <= t.xcor() <= 11 and -240 <= t.ycor() <= -160:
print(f"Player {player} is at the endpoint")
...
wn.onkeypress(check_status)
listen()
I want to make a code for turtles to conquer asteroids. But if you run the code, it falls into an infinite loop and doesn't work. Maybe the while part is the problem, but I don't know how to solve it. Please help me.
I'm so sorry for the long post because it's my first time posting.
I really want to fix the error. Thank you.
import turtle
import random
import math
player_speed = 2
score_num = 0
player = turtle.Turtle()
player.color('blue')
player.shape('turtle')
player.up()
player.speed(0)
screen = player.getscreen()
ai1_hide = False
ai1 = turtle.Turtle()
ai1.color('blue')
ai1.shape('circle')
ai1.up()
ai1.speed(0)
ai1.goto(random.randint(-300, 300), random.randint(-300, 300))
score = turtle.Turtle()
score.speed(0)
score.up()
score.hideturtle()
score.goto(-300,300)
score.write('score : ')
def Right():
player.setheading(0)
player.forward(10)
def Left():
player.setheading(180)
player.forward(10)
def Up():
player.setheading(90)
player.forward(10)
def Down():
player.setheading(270)
player.forward(10)
screen.onkeypress(Left, "Left")
screen.onkeypress(Right, "Right")
screen.onkeypress(Up, "Up")
screen.onkeypress(Down, "Down")
screen.listen()
Code thought to be an error :
while True:
distance = math.sqrt(math.pow(player.xcor() - ai1.xcor(), 2) + math.pow(player.ycor() - ai1.ycor(), 2))
if distance <= 20:
ai1.hideturtle()
score.clear()
if ai1_hide == False:
score_num += 1
ai1_hide = True
ai1.goto(0, 0)
score.write('score : ' + str(scoreNum))
if ai1.isvisible() != True:
break
You forgot to add update() method for screen
while True:
distance = math.sqrt(math.pow(player.xcor() - ai1.xcor(), 2) + math.pow(player.ycor() - ai1.ycor(), 2))
if distance <= 20:
ai1.hideturtle()
score.clear()
if ai1_hide == False:
score_num += 1
ai1_hide = True
ai1.goto(0, 0)
score.write('score : ' + str(scoreNum))
if not ai1.isvisible(): # boolean condition can also be simplified.
break
screen.update() # ADD this to your code
Add a variable
running = True
Then your loop can be
while running:
Over time you can change the variable so your loop can stop or the opposite.
Also, the break function won't work since your loop is a while true.
After weeks of trying, I have not come up with a solution to this issue, in which one turtle comes to a complete stop and the other goes 2x - 3x faster. How can I fix this? You must move them both around for a little bit to encounter the issue. Also this is on the site: repl.it
I have tried moving the wn.listen() command but that only switched which turtle stopped and which one didn't. I have unsuccessfully tried to switch the forward() command to goto() and I have tried to use direction specific movement (also unsuccessfully):
import turtle
import sys
player1 = turtle.Turtle()
player1.up()
player1.goto(0,350)
player1.right(90)
player1.down()
player2 = turtle.Turtle()
wn = turtle.Screen()
#preGame setup
player2.up()
player2.goto(0,-350)
player2.left(90)
player2.down()
player2.color("blue")
player1.color("red")
#main game loop
player1.speed(0)
player2.speed(0)
k = 0
def kr():
player1.left(90)
def kl():
player1.right(90)
wn.onkey(kr, "d")
wn.onkey(kl, "a")
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(k1, "k")
wn.onkey(k2, "l")
wn.listen()
while True:
player1.forward(1)
player2.forward(1)
while player1.xcor() < (-350) or player1.xcor() > (350) or player1.ycor() > (350) or player1.ycor() < (-350):
player1.back(30)
while player2.xcor() < (-350) or player2.xcor() > (350) or player2.ycor() > (350) or player2.ycor() < (-350):
player2.back(30)
if player1.pos() == player2.pos():
print ("DONT CRASH INTO THE OTHER PLAYER")
sys.exit()
I expected them both to continue moving indefinitely, but one always stops, and the other is going 2x the speed.
Move the keylisteners outside your loop - having them inside the while loop will reattach them and redefine the functions all the time and confuse turtle.
You need to set them up once not every few milliseconds:
import turtle
player1 = turtle.Turtle()
player2 = turtle.Turtle()
player1.goto(350, 0)
player2.goto(-350, 0)
player1.right(180)
wn = turtle.Screen()
def kl():
player1.left(90)
def kr():
player1.right(90)
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(kl, "d") # changed to lowercase
wn.onkey(kr, "a")
wn.onkey(k1, "j") # changed to other letters
wn.onkey(k2, "l")
wn.listen()
while True: # not changing k so just use while True
player1.forward(1) # changed speed
player2.forward(1)
Your nested while loop structure is working against you and isn't valid for an event-driven environment like turtle. Here's a rework of your program to fix this issue and clean up the code:
from turtle import Screen, Turtle
import sys
# preGame setup
player1 = Turtle()
player1.hideturtle()
player1.up()
player1.goto(0, 350)
player1.down()
player1.right(90)
player1.color('red')
player1.speed('fastest')
player1.showturtle()
def r1():
player1.left(90)
def l1():
player1.right(90)
player2 = Turtle()
player2.hideturtle()
player2.up()
player2.goto(0, -350)
player2.down()
player2.left(90)
player2.color('blue')
player2.speed('fastest')
player2.showturtle()
def r2():
player2.right(90)
def l2():
player2.left(90)
# main game loop
def move():
player1.forward(5)
if not (-350 < player1.xcor() < 350 and -350 < player1.ycor() < 350):
player1.backward(30)
player2.forward(5)
if not (-350 < player2.xcor() < 350 and -350 < player2.ycor() < 350):
player2.backward(30)
if player1.distance(player2) < 5:
print("DON'T CRASH INTO THE OTHER PLAYER!")
sys.exit()
screen.ontimer(move, 100)
screen = Screen()
screen.onkey(r1, 'd')
screen.onkey(l1, 'a')
screen.onkey(r2, 'k')
screen.onkey(l2, 'l')
screen.listen()
move()
screen.mainloop()
See if this behaves more like you expect/desire.
I am making a game where the player gets to move on a line at the bottom of the screen.
At this time to move it the user repeatedly hits the arrow keys, but I want to make it move continuously when the key is pressed.
How do I fix this?
You will want to use the get_pressed() function of key, Link.
import pygame
pygame.init()
# Variables
black_background = (0, 0, 0)
screen = pygame.display.set_mode((1280, 960))
running = True
turtle_image = pygame.image.load('location/to/turtle/image.png')
turtle_rect = turtle_image.get_rect() # Using rect allows for collisions to be checked later
# Set spawn position
turtle_rect.x = 60
turtle_rect.y = 60
while running:
keys = pygame.key.get_pressed() #keys pressed
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if keys[pygame.K_LEFT]:
turtle_rect.x -= 1
if keys[pygame.K_RIGHT]:
turtle_rect.x += 1
screen.fill(black_background)
screen.blit(turtle_image, turtle_rect)
Remember, this is just a basic layout and you'll have to read a little more into how you want to accomplish collisions and/or movement with other keys. Intro Here.
Below is my turtle-based solution. It uses a timer to keep the turtle moving at the bottom of the window but lets the timer expire when nothing's happening (turtle has stopped at an edge) and restarts the timer as needed:
from turtle import Turtle, Screen
CURSOR_SIZE = 20
def move(new_direction=False):
global direction
momentum = direction is not None # we're moving automatically
if new_direction:
direction = new_direction
if direction == 'right' and turtle.xcor() < width / 2 - CURSOR_SIZE:
turtle.forward(1)
elif direction == 'left' and turtle.xcor() > CURSOR_SIZE - width / 2:
turtle.backward(1)
else:
direction = None
if ((not new_direction) and direction) or (new_direction and not momentum):
screen.ontimer(move, 10)
screen = Screen()
width, height = screen.window_width(), screen.window_height()
turtle = Turtle('turtle', visible=False)
turtle.speed('fastest')
turtle.penup()
turtle.sety(CURSOR_SIZE - height / 2)
turtle.tilt(90)
turtle.showturtle()
direction = None
screen.onkeypress(lambda: move('left'), "Left")
screen.onkeypress(lambda: move('right'), "Right")
screen.listen()
screen.mainloop()
Use the left and right arrows to control the turtle's direction.
use the function: onkeypress.
here is an example were onkeypress is a higher order function:
def move_forward():
t.forward(10)
screen.onkeypress(key='w', fun= move_forward)
You can use onkeypress(fun, key=None)
instead of using onkey() or onkeyrelease(). These two only register the input when the key is released.
onkeypress(fun, key=None) registers it while the key is pressed down.
Here's a link to it in the Turtle documentation.