Alternative to using turtle.goto() in Python - python

This program creates a bouncing ball using turtle.goto(), is there an alternative?
from random import *
from turtle import *
from base import vector
# The ball is drawn, the actions are used from the base file
def draw():
ball.move(aim)
x = ball.x
y = ball.y
if x < -200 or x > 200:
aim.x = -aim.x
if y < -200 or y > 200:
aim.y = -aim.y
clear()
# Can this program serve a purpose without it?
goto(x, y)
dot(10, 'blue')
ontimer(draw,50)
Generally, what is the point of having a goto() function?

Yes, you can create a bouncing ball without using turtle.goto(), here's a rough example:
from turtle import Screen, Turtle
def draw():
ball.forward(10)
x, y = ball.position()
if not (-200 < x < 200 and -200 < y < 200):
ball.undo() # undo 'forward()'
ball.setheading(ball.heading() + 90)
ball.forward(10)
screen.update()
screen.ontimer(draw, 50)
screen = Screen()
screen.tracer(False)
box = Turtle('square')
box.hideturtle()
box.fillcolor('white')
box.shapesize(20)
box.stamp()
ball = Turtle('circle')
ball.color('blue')
ball.setheading(30)
ball.penup()
draw()
screen.exitonclick()

Related

How to bind enter key to a function using turtle

I'm trying to make a tic tac toe game where you use arrow keys to move a turtle around the board, and when you press the enter key it draws a circle (nought in the code) or a cross.
I've tried using similar code to what I used for the movement keys but replace it for the enter key and C key (for cross) but they don't work and automatically draw the cross when it starts up. I've also tried using monkey but that doesn't work.
import turtle
sc = turtle.Screen()
bo = turtle.Turtle()
#screen
sc.bgcolor("black")
sc.title("tic tac toe")
#board
bo.color("white")
bo.penup()
bo.speed(0)
bo.setposition(-100, -300)
bo.pendown()
bo.setposition(-100, 300)
bo.penup()
bo.setposition(100, 300)
bo.pendown()
bo.setposition(100, -300)
bo.penup()
bo.setposition(-300, 100)
bo.pendown()
bo.setposition(300, 100)
bo.penup()
bo.setposition(300, -100)
bo.pendown()
bo.setposition(-300,-100)
bo.penup()
bo.setposition(0,0)
#naught and cross function
def c() :
bo.pendown()
x = bo.xcor()-80
y = bo.ycor()+80
bo.penup()
bo.setposition(x,y)
bo.pendown()
x = bo.xcor()+160
y = bo.ycor()-160
bo.setposition(x,y)
bo.penup()
x = bo.xcor()-160
bo.setposition(x,y)
bo.pendown()
x = bo.xcor()+160
y = bo.ycor()+160
bo.setposition(x,y)
bo.penup()
bo.setposition(0,0)
def n() :
y = bo.ycor()-80
x = bo.xcor()
bo.setposition(x, y)
bo.pendown()
bo.circle(80)
bo.penup()
bo.setposition(0,0)
#movment
def move_left(event):
x = bo.xcor()
x -= 200
if x < -300:
x = -200
bo.setx(x)
def move_right(event):
x = bo.xcor()
x += 200
if x > 300:
x = 200
bo.setx(x)
def move_down(event):
y = bo.ycor()
y -= 200
if y < -300:
y = -200
bo.sety(y)
def move_up(event):
y = bo.ycor()
y += 200
if y > 300:
y = 200
bo.sety(y)
#Keybinding
turtle.listen()
turtle.getcanvas().bind("<Left>", move_left)
turtle.getcanvas().bind("<Right>", move_right)
turtle.getcanvas().bind("<Up>", move_up)
turtle.getcanvas().bind("<Down>", move_down)
I'd eventually like to have it where once you draw a cross, and press enter, it draws a circle where there isn't a cross.
There's no need to drop down to the Tk Canvas to configure your key events:
turtle.getcanvas().bind("<Left>", move_left)
You can do the same from turtle itself:
sc.onkey(move_left, "Left")
I've reworked your code below, adding a key event for "Return" that draws the naughts and crosses. Since you don't have an underlying data structure for your game, I set it up to simply alternate between the two:
from turtle import Screen, Turtle
# naught and cross functions
def cross():
x, y = board.position()
board.penup()
board.setposition(x - 80, y - 80)
board.pendown()
board.setposition(x + 80, y + 80)
board.penup()
board.setx(x - 80)
board.pendown()
board.setposition(x + 80, y - 80)
board.penup()
board.home()
def naught():
board.sety(board.ycor() - 80)
board.pendown()
board.circle(80)
board.penup()
board.home()
first_player = True
def choose():
global first_player
if first_player:
naught()
else:
cross()
first_player = not first_player
# movement
def move_left():
x = board.xcor() - 200
if x < -300:
x = -200
board.setx(x)
def move_right():
x = board.xcor() + 200
if x > 300:
x = 200
board.setx(x)
def move_down():
y = board.ycor() - 200
if y < -300:
y = -200
board.sety(y)
def move_up():
y = board.ycor() + 200
if y > 300:
y = 200
board.sety(y)
# screen
screen = Screen()
screen.bgcolor("black")
screen.title("tic tac toe")
# board
board = Turtle()
board.color("white")
board.speed('fastest')
# vertical lines
board.penup()
board.setposition(-100, -300)
board.pendown()
board.sety(300)
board.penup()
board.setx(100)
board.pendown()
board.sety(-300)
board.penup()
# horizontal lines
board.setposition(-300, 100)
board.pendown()
board.setx(300)
board.penup()
board.sety(-100)
board.pendown()
board.setx(-300)
board.penup()
board.home()
# Keybinding
screen.onkey(move_left, "Left")
screen.onkey(move_right, "Right")
screen.onkey(move_up, "Up")
screen.onkey(move_down, "Down")
screen.onkey(choose, "Return")
screen.listen()
screen.mainloop()
This allows two people to play the game and should be something you can build upon.

Ball bounce in pong

I have written some code but can't get the ball to bounce on the floor or the ceiling naturally. Please help!
I've already tried getting the ball heading with ball_heading = ball.heading, but that didn't work
#Python 3.6.3
from turtle import *
import math
import random
#Screen Setup
bgcolor("black")
wn = Screen()
wn.title("Pong")
#Drawing Border
bd = Turtle()
bd.pencolor("white")
bd.pensize(3)
bd.hideturtle()
bd.penup()
bd.setposition(-400, -300)
bd.pendown()
bd.speed(0)
bd.pendown()
for line in range(2):
bd.forward(800)
bd.left(90)
bd.forward(600)
bd.left(90)
bd.penup()
bd.setposition(0, 300)
bd.setheading(270)
bd.pendown()
for dash in range(30):
bd.forward(10)
bd.penup()
bd.forward(10)
bd.pendown()
#Creating Paddles
#Paddle 1
player1 = Turtle()
player1.color("white")
player1.shape("square")
player1.shapesize(stretch_wid=5, stretch_len=1)
player1.penup()
player1.setposition(-370, 0)
#Paddle 2
player2 = Turtle()
player2.color("white")
player2.shape("square")
player2.shapesize(stretch_wid=5, stretch_len=1)
player2.penup()
player2.setposition(370, 0)
#Creating the ball
ball = Turtle()
ball.color("white")
ball.shape("square")
ball.speed(0)
ball.penup()
ball.setposition(0, 0)
ball.setheading(random.randint(0, 360))
#Moving the player
playerspeed = 15
#p1
def move_up():
y = player1.ycor()
y += playerspeed
#Setting the boundries
if y > 245:
y = 245
player1.sety(y)
def move_down():
y = player1.ycor()
y -= playerspeed
#Setting the boundries
if y < -245:
y = -245
player1.sety(y)
#p2
def move_up2():
y = player2.ycor()
y += playerspeed
#Setting the boundries
if y > 245:
y = 245
player2.sety(y)
def move_down2():
y = player2.ycor()
y -= playerspeed
#Setting the boundries
if y < -245:
y = -245
player2.sety(y)
#Ball movement
def ball_fd():
ball.forward(3)
#Ball ceiling / floor bounce
def ball_bounce():
by = ball.ycor()
if by > 279:
by = 279
ball.sety(by)
bx = ball.ycor()
if bx < -279:
bx = -279
ball.setx(bx)
#binding
listen()
onkey(move_up, "Up")
onkey(move_down, "Down")
onkey(move_up2, "w")
onkey(move_down2, "s")
#Making the ball move / main game loop
while True:
ball_fd()
ball_bounce()
Sorry the code is kind of long, but feel free to copy + paste it into IDLE or whatever.
Thank you
You didn't turn the ball when it hit the floor or ceiling.
while True:
ball.fd(3)
by = ball.ycor()
if abs(by) > 279:
ball.setheading(-ball.heading())

Keyboard input and score. Python turtle

I have found a "flappy game" project and I am modifying it to my liking.
I would like to know how I can control the definition "tap" with the keyboard and not with the mouse (I have tried the online code "onkey" and it did not work) and I would like to know if I can add a score.
Next I attach the code that I have in possession at the moment and I would appreciate some feedback.
from random import *
from turtle import *
from freegames import vector
bird = vector(0, 0)
balls = []
def tap(x, y):
"Move bird up in response to screen tap."
up = vector(0, 30)
bird.move(up)
def inside(point):
"Return True if point on screen."
return -200 < point.x < 200 and -200 < point.y < 200
def draw(alive):
"Draw screen objects."
clear()
goto(bird.x, bird.y)
if alive:
dot(10, 'green')
else:
dot(10, 'red')
for ball in balls:
goto(ball.x, ball.y)
dot(20, 'black')
update()
def move():
"Update object positions."
bird.y -= 5
for ball in balls:
ball.x -= 3
if randrange(10) == 0:
y = randrange(-199, 199)
ball = vector(199, y)
balls.append(ball)
while len(balls) > 0 and not inside(balls[0]):
balls.pop(0)
if not inside(bird):
draw(False)
return
for ball in balls:
if abs(ball - bird) < 15:
draw(False)
return
draw(True)
ontimer(move, 50)
setup(420, 420, 370, 0)
hideturtle()
up()
tracer(False)
onscreenclick(tap)
move()
done()
I've tried all kinds of functions and none has worked.
I would like to know how I can control the definition "tap" with the
keyboard and not with the mouse
That should be as simple as replacing:
onscreenclick(tap)
with
onkey(tap, "Up")
listen()
and dropping the x and y arguments to tap(). I've reworked your code below to make this change as well as eliminate:
from freegames import vector
and make it run just with what's available in turtle. I also changed the logic of keeping vectors and having the default turtle draw dots in their locations to instead making the balls and bird all turtles and just moving them as needed. Since turtles aren't garbage collected normally, I keep a list of balls that have gone off screen to reuse again:
from random import randrange
from turtle import Turtle, Screen
BIRD_RADIUS = 10
BALL_RADIUS = 20
CURSOR_SIZE = 20
WINDOW_WIDTH, WINDOW_HEIGHT = 420, 420
GALLERY_WIDTH, GALLERY_HEIGHT = WINDOW_WIDTH - BALL_RADIUS, WINDOW_HEIGHT - BIRD_RADIUS
def click():
"Move bird up in response to screen key click."
bird.forward(min(BIRD_RADIUS * 3, WINDOW_HEIGHT/2 - bird.ycor())) # flying higher
def is_ball_inside(turtle):
"Return True if point on screen."
x = turtle.xcor()
return -GALLERY_WIDTH/2 < x
def is_bird_inside(turtle):
"Return True if point on screen."
y = turtle.ycor()
return -GALLERY_HEIGHT/2 < y < GALLERY_HEIGHT/2
def draw(is_alive):
"Draw screen objects."
if not is_alive:
bird.color('red')
screen.update()
def move():
"Update object positions."
if not is_bird_inside(bird):
draw(False) # flew or fell out of gallery
return
bird.backward(BIRD_RADIUS/2) # falling to earth
for ball in balls:
ball.forward(3)
for ball in balls:
if ball.distance(bird) < (BIRD_RADIUS + BALL_RADIUS) / 2:
draw(False)
return
while balls and not is_ball_inside(balls[0]):
ball = balls.pop(0)
ball.hideturtle()
spare_balls.append(ball) # reduce, reuse, recycle
if randrange(10) == 0:
ball = spare_balls.pop() if spare_balls else Turtle("circle", visible=False)
ball.shapesize(BALL_RADIUS / CURSOR_SIZE)
ball.setheading(180)
ball.penup()
ball.goto(GALLERY_WIDTH/2, randrange(BALL_RADIUS - GALLERY_HEIGHT/2, GALLERY_HEIGHT/2 - BALL_RADIUS))
ball.showturtle()
balls.append(ball)
draw(True)
screen.ontimer(move, 50)
screen = Screen()
screen.setup(WINDOW_WIDTH, WINDOW_HEIGHT + 10) # little bit added for title bar
bird = Turtle("circle", visible=False)
bird.shapesize(BIRD_RADIUS / CURSOR_SIZE)
bird.color("green")
bird.setheading(90)
bird.penup()
bird.showturtle()
balls = []
spare_balls = []
screen.tracer(False)
screen.onkey(click, "Up")
screen.listen()
move()
screen.mainloop()
To make the turtle window the keyboard listener, you need to touch it with the mouse, to make it active, before hitting the up arrow key.
Before adding the current score to the window, you need to define how one scores. (Is it the number of ball successfully dodged?) Here I would use an additional, invisible turtle stationed in a fixed position that just does undo() and write() to update the scrore.

Making snake in Python, can't get bodies to follow head etc

I wanted to make a snake game in turtle but I can't seem to get the tail segments to follow the leader. As if to say I can't get the first body part to follow the head, and then the second body part to follow the first body, etc.
I tried using what maths I have but I can't seem to get it to calculate where the head just was or where the body in front of it just was.
here is my code:
#libraries
import turtle
import random
import math
#screen
the_screen = turtle.Screen()
the_screen.bgcolor("lightgreen")
the_screen.title("Catapillar")
#border
border_writer = turtle.Turtle()
border_writer.speed(0)
border_writer.color("green")
border_writer.penup()
border_writer.setposition(-275, -275)
border_writer.pendown()
border_writer.pensize(7)
for side in range(4):
border_writer.fd(550)
border_writer.lt(90)
border_writer.hideturtle()
#player
player = turtle.Turtle()
player.color("yellow")
player.shape("circle")
player.penup()
player.speed(0)
player.setposition(0,0)
player.setheading(0)
playerspeed = 2
#fruit
fruit = 1
fruit = turtle.Turtle()
fruit.color("red")
fruit.shape("circle")
fruit.penup()
fruit.speed(0)
fruit.shapesize(0.6, 0.6)
x = random.randint(-200, 200)
y = random.randint(100, 250)
fruit.setposition(x, y)
#moving and collision checker
def turnleft():
player.left(24.5)
def turnright():
player.right(24.5)
def increasespeed():
global playerspeed
playerspeed += 1
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(), 2) + math.pow(t1.ycor()-t2.ycor(), 2))
if distance < 24:
return True
else:
return False
#making the tail(s) and hiding them
tail1 = turtle.Turtle()
tail1.hideturtle()
tail1.color("yellow")
tail1.shape("circle")
tail1.penup()
tail1.speed(0)
tail1.setposition(+700,700)
tail1.shapesize(0.6, 0.6)
tail1state = 'off'
#key presses
turtle.listen()
turtle.onkeypress(turnleft, "Left")
turtle.onkeypress(turnright, "Right")
turtle.onkeypress(increasespeed, "Up")
#main loop player always moves forward, out of bound set, reset fruit
#randomly when collided, create tail1...
while True:
player.forward(playerspeed)
#gameovers'
if (player.xcor() > 275) or (player.xcor() < -275):
playerspeed += 7
print("GAME OVER")
if (player.ycor() > 275) or (player.ycor() < -275):
playerspeed += 7
print("GAME OVER")
#collision check between fruit and head
if isCollision(player, fruit):
#resets the fruit, moves it randomly
fruit.hideturtle()
if tail1state == 'off':
uuu = player.xcor()
vvv = player.ycor()
tail1.setposition(uuu,vvv)
tail1.showturtle()
tail1state = 'on'
#reset the fruit
x = random.randint(-200, 200)
y = random.randint(-100, 250)
fruit.setposition(x, y)
fruit.showturtle()
#playerspeed +=1
If you have any idea on how you think I should approach it, please let me know what you think.
Thank you.
Since this comes up over and over (but effort to effect it is rarely shown) here's my minimal, generic, slithering around a screen effect that you should be able to adapt for your own purposes:
from turtle import Turtle, Screen
SNAKE_LENGTH = 10
SNAKE_SIZE = 15
WIDTH, HEIGHT = 375, 375
CURSOR_SIZE = 20
def slither():
segment = snake[-1].clone() if len(snake) < SNAKE_LENGTH else snake.pop(0)
screen.tracer(False) # segment.hideturtle()
segment.setposition(snake[-1].position())
segment.setheading(snake[-1].heading())
segment.forward(SNAKE_SIZE)
while not -WIDTH/2 < segment.xcor() < WIDTH/2 or not -HEIGHT/2 < segment.ycor() < HEIGHT/2:
segment.undo()
segment.right(95)
segment.forward(SNAKE_SIZE)
screen.tracer(True) # segment.showturtle()
snake.append(segment)
screen.ontimer(slither, 100)
boundary = Turtle(shape='square', visible=False)
boundary.shapesize(HEIGHT / CURSOR_SIZE, WIDTH / CURSOR_SIZE)
boundary.fillcolor("white")
boundary.stamp()
head = Turtle("circle")
head.shapesize(SNAKE_SIZE / CURSOR_SIZE)
head.penup()
snake = [head]
screen = Screen()
slither()
screen.exitonclick()

turtle - How to get mouse cursor position in window?

How would I go about finding the current position of the mouse pointer in the turtle screen? I want it so I have the mouse position before I click and while im moving the cursor. I have searched google and this website can't find anything besides how to get the position after a click.
turtle.getcanvas() returns a Tkinter Canvas.
Like with a Tkinter window, you can get the current mouse pointer coordinates by winfo_pointerx and .winfo_pointery on it:
canvas = turtle.getcanvas()
x, y = canvas.winfo_pointerx(), canvas.winfo_pointery()
# or
# x, y = canvas.winfo_pointerxy()
If you want to only react to movement instead of e.g. polling mouse pointer positions in a loop, register an event:
def motion(event):
x, y = event.x, event.y
print('{}, {}'.format(x, y))
canvas = turtle.getcanvas()
canvas.bind('<Motion>', motion)
Note that events only fire while the mouse pointer hovers over the turtle canvas.
All these coordinates will be window coordinates (with the origin (0, 0) at the top left of the turtle window), not turtle coordinates (with the origin (0, 0) at the canvas center), so if you want to use them for turtle positioning or orientation, you'll have to do some transformation.
Following up on this answer, here's an example of one way to normalize the Tkinter coordinates for turtle using the canvas.bind('<Motion>', motion) approach (canvas.winfo_pointerxy() didn't provide values that made sense to me, although I didn't look into it much):
import turtle
def on_motion(event):
x = event.x - turtle.window_width() / 2
y = -event.y + turtle.window_height() / 2
turtle.goto(x, y)
turtle.stamp()
print(x, y)
turtle.tracer(0)
turtle.penup()
turtle.getcanvas().bind("<Motion>", on_motion)
turtle.exitonclick()
Using this in a real-time app rather than only on motion:
import turtle
def on_motion(event):
global mouse_x, mouse_y
mouse_x = event.x - turtle.window_width() / 2
mouse_y = -event.y + turtle.window_height() / 2
def tick():
print(mouse_x, mouse_y)
turtle.goto(mouse_x, mouse_y)
turtle.stamp()
win.ontimer(tick, frame_delay_ms)
turtle.tracer(0)
mouse_x, mouse_y = 0, 0
turtle.getcanvas().bind("<Motion>", on_motion)
turtle.shape("circle")
turtle.penup()
frame_delay_ms = 1000 // 30
win = turtle.Screen()
tick()
turtle.exitonclick()
Putting it into a more full-featured app without global:
import turtle
from math import sin
def add_mouse_listener():
def on_motion(event):
nonlocal x, y
x = event.x - turtle.window_width() / 2
y = -event.y + turtle.window_height() / 2
turtle.getcanvas().bind("<Motion>", on_motion)
x, y = 0, 0
return lambda: (x, y)
def color(c, a):
return sin(c + a) / 2 + 0.5
def colors(r, ra, g, ga, b, ba):
return color(r, ra), color(g, ga), color(b, ba)
def main():
ra = 0
ba = 0
ga = 0
r = 0.5
b = 0
g = 1
frame_delay_ms = 1000 // 30
turtle.tracer(0)
turtle.pensize(40)
mouse_pos = add_mouse_listener()
win = turtle.Screen()
def tick():
nonlocal ra, ba, ga
turtle.color(colors(r, ra, g, ga, b, ba))
ra += 0.03
ba += 0.0311
ga += 0.032
x, y = mouse_pos()
turtle.setheading(turtle.towards(x, y))
turtle.forward(10)
turtle.update()
win.ontimer(tick, frame_delay_ms)
tick()
turtle.exitonclick()
if __name__ == "__main__":
main()

Categories