How to make turtle move continuously without multiple key presses? - python

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.

Related

How to make multiple turtles move in a line at the same time

My goal is to be able to make a snake(three turtles next to each other) move at the same time and also make the snake turn using arrow keys. I have tried the ontimer method/function but it does not work as expected. Here is my code:
import make_snake
from turtle import Turtle, Screen
game_is_on = True
screen = Screen()
screen.setup(600, 600)
screen.bgcolor("black")
screen.title("Snake Game")
snake_seg1 = make_snake.snake_segments[0]
snake_seg2 = make_snake.snake_segments[1]
snake_seg2.setheading(snake_seg1.heading())
snake_seg3 = make_snake.snake_segments[2]
snake_seg3.setheading(snake_seg2.heading())
def move_forward():
snake_seg1.forward(20)
def move_backward():
snake_seg1.backward(20)
def turn_left():
snake_seg1.left(90)
def turn_right():
snake_seg1.right(90)
screen.onkey(move_forward, "Up")
screen.onkey(move_backward, "Down")
screen.onkey(turn_left, "Left")
screen.onkey(turn_right, "Right")
while game_is_on:
for seg in make_snake.snake_segments:
seg.forward(20)
# def follow_head():
# snake_seg1.forward(20)
# snake_seg2.setheading(snake_seg1.heading())
# snake_seg2.forward(20)
# snake_seg3.setheading(snake_seg2.heading())
# snake_seg3.forward(20)
# screen.ontimer(follow_head, 0)
screen.exitonclick()
File make_snake:
from turtle import Turtle
start_positions = [0, 20, 40]
snake_segments = []
for position in start_positions:
snake_part = Turtle(shape="square")
snake_part.color("white")
snake_part.penup()
snake_part.backward(position)
snake_segments.append(snake_part)
What can I fix in my code to make it stop moving one turtle at a time?
Your program has at least one problem: you use onkey() but forgot to call listen() to allow key events.
Here's a minimalist rework of your code to get basic snake movement working, it just supports right and left turns:
from turtle import Turtle, Screen
SEGMENT_SIZE = 20
START_COORDINATES = [-SEGMENT_SIZE * count for count in range(5)]
def turn_left():
snake_segments[0].left(90)
screen.update()
def turn_right():
snake_segments[0].right(90)
screen.update()
def move_forward():
for index in range(len(snake_segments) - 1, 0, -1):
snake_segments[index].goto(snake_segments[index - 1].position())
snake_segments[0].forward(SEGMENT_SIZE)
screen.update()
screen.ontimer(move_forward, 250)
screen = Screen()
screen.setup(600, 600)
screen.title("Snake Game")
screen.tracer(False)
snake_segments = []
for position in START_COORDINATES:
snake_segment = Turtle(shape='circle', visible=False)
snake_segment.penup()
snake_segment.setx(position)
snake_segment.showturtle()
snake_segments.append(snake_segment)
snake_segments[0].color('red')
screen.onkey(turn_left, 'Left')
screen.onkey(turn_right, 'Right')
screen.listen()
screen.update()
move_forward()
screen.exitonclick()
Be careful, it's easy to lose the snake off the edge of the window and not be able to get it back again!
The thing you might be looking for here is called multiprocessing. There is an eponymous library to execute lines of code simultaneously in Python. For reference look at the following thread:
Python: Executing multiple functions simultaneously

How to make multiple clones run at the same time in python turtle

I am trying to make a code where you can press the spacebar and an object will move forwards constantly. I am hoping to be able to have multiple of these objects moving at once without having to code hundreds of them separately.
This is my current code:
Bullet:
bullet = turtle.Turtle()
bullet.speed(0)
bullet.shape("circle")
bullet.color("red")
bullet.shapesize(stretch_wid=0.5, stretch_len=0.5)
bullet.penup()
bullet.goto(-200, -200)
bullet.hideturtle()
Movement:
def shoot_bullet():
stop = False
bullet2 = bullet.clone()
bullet2.showturtle()
while stop == False:
y = bullet2.ycor()
bullet2.sety(y + 20)
wn.update()
time.sleep(0.5)
...
onkeypress(shoot_bullet, "space")
This works until I press space again and the bullet just stops as 'bullet2' has been redefined as the new bullet I create when I press space. Is there a way to create multiple clones which can run on top of each other?
Your while stop == False: loop and time.sleep(0.5) have no place in an event-driven environment like turtle. Instead, as we fire each bullet, the below code attaches a timer event that moves it along until it disappears. At which point the bullet is recycled.
This simplified example just shoots bullets in random directions from the center of the screen. You can keep hitting the space bar to generate simultaneous bullets that all move in their own direction until they get far enough away:
from turtle import Screen, Turtle
from random import randrange
def move_bullet(bullet):
bullet.forward(15)
if bullet.distance((0, 0)) > 400:
bullet.hideturtle()
bullets.append(bullet)
else:
screen.ontimer(lambda b=bullet: move_bullet(b), 50)
screen.update()
def shoot_bullet():
screen.onkey(None, 'space') # disable handler inside hander
bullet = bullets.pop() if bullets else bullet_prototype.clone()
bullet.home()
bullet.setheading(randrange(0, 360))
bullet.showturtle()
move_bullet(bullet)
screen.onkey(shoot_bullet, 'space') # reenable handler on exit
bullet_prototype = Turtle('circle')
bullet_prototype.hideturtle()
bullet_prototype.dot(10) # just for this example, not for actual code
bullet_prototype.shapesize(0.5)
bullet_prototype.color('red')
bullet_prototype.penup()
bullets = []
screen = Screen()
screen.tracer(False)
screen.onkey(shoot_bullet, 'space')
screen.listen()
screen.mainloop()

Obstacle freezes during player input - Python Turtle

My Python turtle game obstacle freezes when the player receives input and continues afterward:
# Written in Python 3
# By
# February 4th, 2019
# Purpose: Mimic the no-wifi Google Chrome dinosaur game
# Bonus 6
import turtle # Used for graphics
from turtle import Screen # Used for inputs
import random# Used to generate a random number
import time
# Creates a turtle with the proper size and color
player = turtle.Turtle()
player.shape("square")
player.color("#cc0000")
player.turtlesize(1.5, 1.5)
player.penup()
player.goto(-50, 0)
# Creates the ground
ground = turtle.Turtle()
ground.shape("square")
ground.turtlesize(0.25, 300)
ground.penup()
ground.goto(0, -18)
# This function makes the square jump, unbinds 'Up', return to the ground, then rebinds 'Up'
def jump():
Screen().onkey(null, 'Up')
player.speed(2)
if player.ycor() == 0:
player.goto((player.xcor()), (player.ycor()+100))
print("G")
player.speed(1.5)
player.goto(-50, 0)
Screen().onkey(jump, 'Up')
# Blank function
def null():
n =1
Screen().onkey(jump, 'Up')
Screen().listen()
# Ignore this
x = 3 * random.sample(range(4), 4)
print (x)
print (x[1])
# Creating obstacles (not finished, just moves)
obst1 = turtle.Turtle()
obst1.shape("square")
obst1.turtlesize(3, 2)
obst1.penup()
obst1.goto(300,0)
obst1.speed(1)
obst1.setx(-300)
I want the obstacle to continue moving while I jump. I only have Python 3 and its standard modules. I cannot download PIP or anything else like it, for some reason. I'm trying to mimic the dinosaur game from Google Chrome. I'm new to this sort of thing so please explain any suggestions in as much detail as possible. Thanks a lot!
The way you wrote your code, you can only move one turtle at a time. Below is a rework of your code where the user controls the player, but the obstacle is controlled by a timer so they can move at the same time:
from turtle import Screen, Turtle
# This function unbinds 'Up', makes the square jump, return to the ground, then rebinds 'Up'
def jump():
screen.onkey(None, 'Up')
if player.ycor() == 0:
player.forward(150)
player.backward(150)
screen.onkey(jump, 'Up')
def move():
obstacle.forward(6)
if obstacle.xcor() > -400:
screen.ontimer(move, 100)
# Creates the ground
ground = Turtle('square')
ground.turtlesize(0.25, 45)
ground.penup()
ground.sety(-15)
# Creates a turtle with the proper size and color
player = Turtle('square')
player.color('red')
player.turtlesize(1.5)
player.speed('slowest')
player.penup()
player.setx(-100)
player.setheading(90)
screen = Screen()
screen.onkey(jump, 'Up')
screen.listen()
# Creating obstacles (not finished, just moves)
obstacle = Turtle('square')
obstacle.turtlesize(3, 1.5)
obstacle.speed('fastest')
obstacle.penup()
obstacle.setposition(400, 15)
obstacle.setheading(180)
move()
screen.mainloop()
This should more closely simulate the type of motion you're trying to achieve.

Turtle.onkeypress isn't firing

I'm very new to Python and have made a couple small games during a Python Learning course but never at home. So recently I began making a game, but after just 10 minutes I stumbled upon a problem:
Nothing happened when I pressed "W" although I had writen onkeypress in the code.
See for your self:
(It's designed for full screen)
import turtle
s = turtle.Screen()
g = turtle.Turtle()
t = turtle.Turtle()
#Ground
t.speed(0)
t.up()
t.goto(-1000,-200)
t.down()
t.goto(1000,-200)
#Player
g.speed(0)
PlayerX = -600
def moveX():
g.clear()
global PlayerX
g.up()
g.goto(PlayerX,-99)
g.down()
g.color("Slate Gray")
g.begin_fill()
g.circle(-50)
g.end_fill()
PlayerX = PlayerX - 1
turtle.onkeypress(moveX, "w")
moveX()
I'm fully aware I haven't made a go backwards button.
Along with #doctorlove's spot on correction (+1) of adding listen() to allow the window to receive keyboard events, a couple of comments:
First, click on the window with your mouse to make it active otherwise it won't respond to the keyboard. Second, it can be helpful to deactivate the event handler while in the event hander, and reactivate it on the way out, to avoid problems if someone repeatedly presses the key very fast.
Here's the second comment along with some other code suggestions:
from turtle import Turtle, Screen
screen = Screen()
screen.setup(1200, 500)
# Ground
ground = Turtle()
ground.speed('fastest')
ground.penup()
ground.goto(-1000, -200)
ground.pendown()
ground.forward(2000)
# Player
player = Turtle()
player.speed('fastest')
PlayerX = -600
def moveX():
global PlayerX
screen.onkeypress(None, "w") # disable handler in handler
player.clear()
player.penup()
player.goto(PlayerX, -99)
player.pendown()
player.color("Slate Gray")
player.begin_fill()
player.circle(-50)
player.end_fill()
PlayerX -= 1
screen.onkeypress(moveX, "w") # reenable handler
screen.listen()
moveX()
screen.mainloop() # change import & use turtle.mainloop() if Python 2
mainloop() isn't required to run but the program will exit after your initial moveX() call without it. mainloop() turns control over to the Tk event handler so some events may not fire without it.
You'll need to change onkeypress() to onkey() if this is Python 2 as well as change the way that mainloop() is invoked.
I think it's called onkey not onkeypress.
Also I think you need to listen (and add a mainloop if you want it to run):
turtle.onkey(moveX, "w")
turtle.listen()
moveX() # draw things first
turtle.mainloop()
You may need to revisit the numbers you are using to make sure the shape is on the window.
with my version of python none of the others are actually correct, here is the modified code that works for me:
from turtle import Turtle, Screen, setpos, hideturtle
screen = Screen()
screen.setup(500, 500)
#Ground
t = Turtle()
t.speed(0)
t.up()
t.goto(-1000,-200)
t.down()
t.goto(1000,-200)
#Player
player = Turtle()
hideturtle()
player.speed(0)
setpos(0,0)
PlayerX = 0
def moveX():
player.clear()
global PlayerX
player.up()
player.goto(PlayerX,0)
player.down()
player.color("Slate Gray")
player.begin_fill()
player.circle(-50)
player.end_fill()
PlayerX = PlayerX - 1
screen.onkey(moveX, "w")
screen.listen()
(this can definitely be improved on)
Not sure if the change is with Python3. But onkey function seems to be dragged under Screen().
turtle.Screen().onkey(movex, "w")
#This is a short code I made using space as down and w as up, feel free to
#extract from it what you can.
import turtle
player = turtle.Turtle()
y = 0
wn = turtle.Screen()
def p_up():
global y,up
up = True
while(up==True):
y += 10
player.sety(y)
def p_down():
global y,down
down = True
while(down==True):
y -= 10
player.sety(y)
def up_stop():
global up
up = False
def down_stop():
global down
down = False
wn.listen()
wn.onkeypress(p_up,"w")
wn.onkeypress(p_down,"space")
wn.onkeyrelease(up_stop,"w")
wn.onkeyrelease(down_stop,"space")
wn.mainloop()

Single player 'pong' game

I am just starting out learning pygame and livewires, and I'm trying to make a single-player pong game, where you just hit the ball, and it bounces around until it passes your paddle (located on the left side of the screen and controlled by the mouse), which makes you lose. I have the basic code, but the ball doesn't stay on the screen, it just flickers and doesn't remain constant. Also, the paddle does not move with the mouse. I'm sure I'm missing something simple, but I just can't figure it out. Help please! Here's what I have:
from livewires import games
import random
games.init(screen_width=640, screen_height=480, fps=50)
class Paddle(games.Sprite):
image=games.load_image("paddle.bmp")
def __init__(self, x=10):
super(Paddle, self).__init__(image=Paddle.image,
y=games.mouse.y,
left=10)
self.score=games.Text(value=0, size=25, top=5, right=games.screen.width - 10)
games.screen.add(self.score)
def update(self):
self.y=games.mouse.y
if self.top<0:
self.top=0
if self.bottom>games.screen.height:
self.bottom=games.screen.height
self.check_collide()
def check_collide(self):
for ball in self.overlapping_sprites:
self.score.value+=1
ball.handle_collide()
class Ball(games.Sprite):
image=games.load_image("ball.bmp")
speed=5
def __init__(self, x=90, y=90):
super(Ball, self).__init__(image=Ball.image,
x=x, y=y,
dx=Ball.speed, dy=Ball.speed)
def update(self):
if self.right>games.screen.width:
self.dx=-self.dx
if self.bottom>games.screen.height or self.top<0:
self.dy=-self.dy
if self.left<0:
self.end_game()
self.destroy()
def handle_collide(self):
self.dx=-self.dx
def end_game(self):
end_message=games.Message(value="Game Over",
size=90,
x=games.screen.width/2,
y=games.screen.height/2,
lifetime=250,
after_death=games.screen.quit)
games.screen.add(end_message)
def main():
background_image=games.load_image("background.bmp", transparent=False)
games.screen.background=background_image
paddle_image=games.load_image("paddle.bmp")
the_paddle=games.Sprite(image=paddle_image,
x=10,
y=games.mouse.y)
games.screen.add(the_paddle)
ball_image=games.load_image("ball.bmp")
the_ball=games.Sprite(image=ball_image,
x=630,
y=200,
dx=2,
dy=2)
games.screen.add(the_ball)
games.mouse.is_visible=False
games.screen.event_grab=True
games.screen.mainloop()
main()
I can't help you because you did not post the complete code here. At least, I do not see where you're updating the positions of the sprites (self.x += self.dx somewhere?) and updating the draw to screen. You're also not utilising your classes in the main() function.
That said, I'm seeing
def __init__(self, x=10):
and inside the constructor you never used the x variable. That worries me, too.
Consider using the Paddle and Ball class as a Sprite, like the following:
if __name__ == '__main__':
background_image = games.load_image("background.bmp", transparent=False)
games.screen.background = background_image
the_paddle = Puddle()
games.screen.add(the_paddle)
the_ball = Ball()
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
Note I've taken the liberty to make your code read more Pythonic. I have never used livewires, however, so my code may not function. But it should point you to the right direction. Good luck!
Why are you using livewires? You can use only pygame for a pong game.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480)) # window size
pygame.display.set_caption("Simple pong") # window title
# this is a rect that contains the ball
# at the beginning it is set in the center of the screen
ball_rect = pygame.Rect((312, 232), (16, 16))
# speed of the ball (x, y)
ball_speed = [4, 4]
# this contains your paddle
# vertically centered on the left side
paddle_rect = pygame.Rect((8, 200), (8, 80))
# 1 point if you hit the ball
# -5 point if you miss the ball
score = 0
# load the font for displaying the score
font = pygame.font.Font(None, 30)
# mainloop
while True:
# event handler
for event in pygame.event.get():
# quit event => close the game
if event.type == pygame.QUIT:
exit(0)
# control the paddle with the mouse
elif event.type == pygame.MOUSEMOTION:
paddle_rect.centery = event.pos[1]
# correct paddle position if it's going out of window
if paddle_rect.top < 0:
paddle_rect.top = 0
elif paddle_rect.bottom >= 480:
paddle_rect.bottom = 480
# this test if up or down keys are pressed
# if yes move the paddle
if pygame.key.get_pressed()[pygame.K_UP] and paddle_rect.top > 0:
paddle_rect.top -= 5
elif pygame.key.get_pressed()[pygame.K_DOWN] and paddle_rect.bottom < 480:
paddle_rect.top += 5
# update ball position
# this move the ball
ball_rect.left += ball_speed[0]
ball_rect.top += ball_speed[1]
# these two if block control if the ball is going out on the screen
# if it's going it reverse speed to simulate a bounce
if ball_rect.top <= 0 or ball_rect.bottom >= 480:
ball_speed[1] = -ball_speed[1]
if ball_rect.right >= 640:
ball_speed[0] = -ball_speed[0]
# this control if the ball touched the left side
elif ball_rect.left <= 0:
score -= 5
# reset the ball to the center
ball_rect = pygame.Rect((312, 232), (16, 16))
# test if the ball is hit by the paddle
# if yes reverse speed and add a point
if paddle_rect.colliderect(ball_rect):
ball_speed[0] = -ball_speed[0]
score += 1
# clear screen
screen.fill((255, 255, 255))
# draw the ball, the paddle and the score
pygame.draw.rect(screen, (0, 0, 0), paddle_rect) # paddle
pygame.draw.circle(screen, (0, 0, 0), ball_rect.center, ball_rect.width/2) # ball
score_text = font.render(str(score), True, (0, 0, 0))
screen.blit(score_text, (320-font.size(str(score))[0]/2, 5)) # score
# update screen and wait 20 milliseconds
pygame.display.flip()
pygame.time.delay(20)

Categories

Resources