How to make the snowflake rotate more smoothly? - python

I am new to python animation, although have managed to use animation to make the snowflake rotate but it is not rotating so smoothly...
I have attached the code below, can anyone please suggest me what do I do to make it rotate more smoothly?
import turtle
import time
bob = turtle.Turtle()
bob.ht()
screen = turtle.Screen()
bob.speed(100)
screen.tracer(0, 0)
n = 0
bob.pencolor("blue")
bob.pensize(5)
def vshape():
bob.rt(25)
bob.fd(50)
bob.backward(50)
bob.lt(50)
bob.fd(50)
bob.backward(50)
bob.rt(25)
def snowflakeArm():
for x in range(4):
bob.fd(30)
vshape()
bob.backward(120)
def snowflake(n, x, y):
bob.seth(n)
bob.pu()
bob.setpos(x ,y)
bob.pd()
for x in range(6):
snowflakeArm()
bob.rt(60)
while True:
time.sleep(0.02)
bob.update()
bob.clear()
snowflake(n, 0, 0)
snowflake(n, 350, 0)
snowflake(n, -350, 0)
snowflake(n, 0, 350)
snowflake(n, 0, -350)
n += 10
I have tried to decrease the sleep time as well as decrease the amount of rotation but still no result...

It concerns me that you're able to call bob.update() successfully as update() isn't a method of Turtle in the standard turtle.py released with Python 3 nor Python 2. You may be using an older, or non-standard, turtle implementation so some of the below may need to be adjusted.
Rather than introduce time.sleep(), which is out of sync with turtle's own event handler, let's use a turtle ontimer() event:
from turtle import Screen, Turtle
def vshape():
turtle.right(25)
turtle.forward(50)
turtle.backward(50)
turtle.left(50)
turtle.forward(50)
turtle.backward(50)
turtle.right(25)
def snowflakeArm():
for _ in range(4):
turtle.forward(30)
vshape()
turtle.backward(120)
def snowflake(angle, position):
turtle.setheading(angle)
turtle.penup()
turtle.setposition(position)
turtle.pendown()
for _ in range(360 // 60):
snowflakeArm()
turtle.right(60)
angle = 0
def snowflakes():
global angle
turtle.clear()
snowflake(angle, (0, 0))
snowflake(angle, (350, 0))
snowflake(angle, (-350, 0))
snowflake(angle, (0, 350))
snowflake(angle, (0, -350))
screen.update()
angle = (angle + 10) % 360
screen.ontimer(snowflakes, 25) # repeat 25 milliseconds from now
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.pencolor('blue')
turtle.pensize(5)
snowflakes()
screen.exitonclick()
This should also allow us to exit the program cleanly, by clicking on the window, without generating all those warning messages.

Related

How do I make a python turtle program wait a bit?

So I'm making a game where the two turtles race each other, but I want them to wait a bit before they start (to display a 3,2,1) screen. But I can't figure it out! I used time.sleep, and turtle.delay, but both did not work. What can I do? Here is the code :)
import turtle
import random
import time
turt = turtle.Turtle()
turt2 = turtle.Turtle()
turtle.Screen() .bgcolor("green")
turt.speed(10)
turt.penup()
turt.goto(200,100)
turt.pendown()
turt.right(90)
turt.width(10)
turt.forward(450)
turt.right(180)
turt.forward(800)
#position 1
turt.penup()
turt.goto(-400,200)
turt.pendown()
turt.right(90)
turt.forward(100)
#position 2
turt2.width(10)
turt2.penup()
turt2.goto(-400,-200)
turt2.pendown()
turt2.forward(100)
Contrary to the advice so far, I'd avoid sleep() in my turtle program and use ontimer() instead to countdown the start of the race:
from turtle import Screen, Turtle
from random import choice
FONT = ('Arial', 36, 'bold')
def race():
while turtle_1.xcor() < 200 > turtle_2.xcor():
choice([turtle_1, turtle_2]).forward(10)
def countdown(seconds=3):
pen.clear()
if seconds < 1:
screen.ontimer(race)
else:
pen.write(seconds, align='center', font=FONT)
screen.ontimer(lambda: countdown(seconds - 1), 1000)
screen = Screen()
screen.bgcolor('green')
marker = Turtle()
marker.hideturtle()
marker.speed('fastest')
marker.color('white')
marker.width(5)
marker.penup()
marker.goto(200, 300)
marker.pendown()
marker.right(90)
marker.forward(600)
pen = Turtle()
pen.hideturtle()
turtle_1 = Turtle()
turtle_1.shape('turtle')
turtle_1.color('red')
turtle_1.penup()
turtle_1.goto(-400, 200)
turtle_2 = turtle_1.clone()
turtle_1.color('blue')
turtle_2.goto(-400, -200)
countdown()
screen.exitonclick()

How do you make a conditional loop with onkeypress()?

I'm working on a python project for my intro class where I want to make a blizzard with the turtle module. So far, I've been able to make a "snowflake" appear on each keypress but I'm not sure how to make it into a conditional loop where when I click, it becomes true and keeps looping without me having to click again.
Here's the code I have right now:
def snowing(x, y):
w.speed(0)
flake_size = randint(1, 5)
rx = randint(-250, 250)
ry = randint(-300, 300)
w.color(colours[5])
w.setposition(rx, ry)
w.pendown()
w.begin_fill()
w.circle(flake_size)
w.end_fill()
w.penup()
listen()
onscreenclick(snowing, add=None)
when I click, it becomes true and keeps looping without me having to
click again.
We can make a separate event handler that is a toggle, using a global to switch between on and off on subsequent clicks. We'll combine that with a timer event to keeps the flakes coming:
from turtle import Screen, Turtle
from random import randint, choice
COLOURS = ['light gray', 'white', 'pink', 'light blue']
is_snowing = False
def toggle_snowing(x, y):
global is_snowing
if is_snowing := not is_snowing:
screen.ontimer(drop_flake)
def drop_flake():
flake_radius = randint(1, 5)
x = randint(-250, 250)
y = randint(-300, 300)
turtle.setposition(x, y)
turtle.color(choice(COLOURS))
turtle.begin_fill()
turtle.circle(flake_radius)
turtle.end_fill()
if is_snowing:
screen.ontimer(drop_flake)
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
turtle.penup()
screen = Screen()
screen.setup(500, 600)
screen.bgcolor('dark blue')
screen.onclick(toggle_snowing)
screen.listen()
screen.mainloop()
When you click on the screen, the flakes will start appearing. When you click again, they will stop.

How do I make this a 6 sized snowflake instead of 8?

Not originally my code:
import turtle
wn = turtle.Screen()
wn.bgcolor('Black')
wn.setup( width = 250, height = 250)
turtle = turtle.Turtle()
def snowflake (size, pensize, x, y):
""" function that draws a snowflake """
turtle.speed(100)
turtle.penup()
turtle.goto(x, y)
turtle.forward(10*size)
turtle.left(45)
turtle.pendown()
turtle.color('white')
for x in range (8):
branch(size)
turtle.left(45)
def branch (size):
for z in range (3):
for z in range (3):
turtle.forward(10.0*size/3)
turtle.backward(10.0*size/3)
turtle.right(45)
turtle.left(90)
turtle.backward(10.0*size/3)
turtle.left(45)
turtle.right(90)
turtle.forward(10.0*size)
snowflake(8, 6, 0, 0)
wn.exitonclick()
If it's not originally your code, your should provide proper blame, I mean credit for it. The issue with this code is that the base angle 45 is being used to generate the 8-sided snowflake as well as the angle of the small branches. So when we go to use 60 for a 6-sided snowflake, it's hard to know which 45's (or 90's) to replace and which to keep. The author of the original code didn't help any by starting the branch logic in the snowflake() function, before calling the branch() function. So let's tease out the two different uses of 45 degrees, make the code more explicit, and switch just the sides to 60 degrees:
from turtle import Screen, Turtle
SIDES = 6
BRANCH_ANGLE = 45
def snowflake(size, x, y):
""" function that draws a snowflake """
turtle.penup()
turtle.goto(x, y)
turtle.forward(size)
turtle.left(BRANCH_ANGLE)
turtle.pendown()
for _ in range(SIDES):
branch(size)
turtle.left(BRANCH_ANGLE)
def branch(size):
for _ in range(3):
for _ in range(3):
turtle.forward(size / 3)
turtle.backward(size / 3)
turtle.right(BRANCH_ANGLE)
turtle.left(2 * BRANCH_ANGLE)
turtle.backward(size / 3)
turtle.left(BRANCH_ANGLE)
turtle.right(BRANCH_ANGLE + 360 / SIDES)
turtle.forward(size)
screen = Screen()
screen.bgcolor('black')
screen.setup(width=250, height=250)
turtle = Turtle()
turtle.color('white')
turtle.speed('fastest')
snowflake(80, 0, 0)
turtle.hideturtle()
screen.exitonclick()

How to create a button with python turtle

So I want to create a button that you can click on in python.
I am making a very simple game with the python turtle module.
here's my code x is the x position of the click and y is the y position of the click.
screen = turtle.Screen() #for some context
def click(x, y):
if (x <= 40 and x <= -40) and (y <= 20 and y <= -20):
#code here
screen.onscreenclick(click)
I want it to do the run some code when i click in a specific area but
this code doesn't work for me.
any help would be appreciated.
Thanks!
Approach the problem a different way. Don't draw a button with the turtle and try to determine if the user clicked within the drawing, make a button out of a turtle and do something when the user clicks on it:
from turtle import Screen, Turtle
def click(x, y):
button.hideturtle()
button.write("Thank you!", align='center', font=('Arial', 18, 'bold'))
screen = Screen()
button = Turtle()
button.shape('square')
button.shapesize(2, 4)
button.fillcolor('gray')
button.onclick(click)
screen.mainloop()
If you insist on doing it your way, then the equivalent code might be:
from turtle import Screen, Turtle
def click(x, y):
if -40 <= x <= 40 and -20 <= y <= 20:
turtle.write("Thank you!", align='center', font=('Arial', 18, 'bold'))
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
turtle.fillcolor('gray')
turtle.goto(-40, -20)
turtle.begin_fill()
for _ in range(2):
turtle.forward(80)
turtle.left(90)
turtle.forward(40)
turtle.left(90)
turtle.end_fill()
turtle.goto(0, 30)
screen.onclick(click)
screen.mainloop()

How to make this wheel spin?

I have created the wheel, but when I try to make code to spin it will not work.
I have already tried to make it using a loop but that was near impossible for me. I am basically drawing the wheel over. Here is some code from the spinning wheel part:
turtle.listen()
if turtle.onkeypress("space"):
colors = ['#880000','#884400','#884400','#888800',
'#888800','#008800','#008800','#008800',
'#008800','#008800','#008888','#008888',
'#008888','#008888','#008888','#000088',
'#000088','#000088','#000088','#000088']
for color in colors:
slice_angle = 360 / len(colors)
heading, position = 90, (center[0] + radius, center[1])
turtle.color(color, color)
turtle.speed(0)
turtle.penup()
turtle.goto(position)
turtle.setheading(heading)
turtle.pendown()
turtle.begin_fill()
turtle.circle(radius, extent=slice_angle)
heading, position = turtle.heading(), turtle.position()
turtle.penup()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
time.sleep(0.2)
colors = ['#884400','#884400','#888800',
'#888800','#008800','#008800','#008800',
'#008800','#008800','#008888','#008888',
'#008888','#008888','#008888','#000088',
'#000088','#000088','#000088','#000088','#880000']
for color in colors:
slice_angle = 360 / len(colors)
heading, position = 90, (center[0] + radius, center[1])
turtle.color(color, color)
turtle.speed(0)
turtle.penup()
turtle.goto(position)
turtle.setheading(heading)
turtle.pendown()
turtle.begin_fill()
turtle.circle(radius, extent=slice_angle)
heading, position = turtle.heading(), turtle.position()
turtle.penup()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
time.sleep(0.2)
The code keeps on going to make the wheel 'spin'.
This is what I get:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/turtle.py", line 701, in eventfun
fun()
TypeError: 'str' object is not callable
My impression is that you're not trying to make the wheel spin but rather make it look like it's spinning by cycling its colors. Here's my example of doing such which uses tracer() and update() to turn off drawing while remaking the circle with the colors shifted. It uses a timer event to trigger redraws. Rather than your fixed list of colors, I'm going to use continuous hues, but you should be able to use any colors you wish:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
RADIUS = 100
NUMBER_OF_WEDGES = 20
SLICE_ANGLE = 360 / NUMBER_OF_WEDGES
screen = Screen()
screen.tracer(False)
turtle = Turtle(visible=False)
turtle.penup()
center = turtle.position()
turtle.sety(turtle.ycor() - RADIUS)
hues = [color / NUMBER_OF_WEDGES for color in range(NUMBER_OF_WEDGES)] # precompute hues
index = 0
def draw_circle():
global index
for hue in range(NUMBER_OF_WEDGES):
turtle.color(hsv_to_rgb(hues[(hue + index) % NUMBER_OF_WEDGES], 1.0, 1.0))
turtle.pendown()
turtle.begin_fill()
turtle.circle(RADIUS, extent=SLICE_ANGLE)
position = turtle.position()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
turtle.goto(position)
screen.update()
index = (index + 1) % NUMBER_OF_WEDGES
screen.ontimer(draw_circle, 40)
draw_circle()
screen.exitonclick()
This works, but, on my system, inexplicably slows down over time.
Let's try a different approach that doesn't redraw anything at the Python level during the cycling of colors. We're going to design a new cursor shape, "wedge" and build our circle out of turtles! All the wedges will be prepositioned and not move nor be redrawn. The timer event handler will simply ask each turtle to take on the color of its neighbor:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
RADIUS = 100
NUMBER_OF_WEDGES = 20
SLICE_ANGLE = 360 / NUMBER_OF_WEDGES
screen = Screen()
screen.tracer(False)
# create a pie wedge-shaped cursor
turtle = Turtle(visible=False)
turtle.begin_poly()
turtle.sety(turtle.ycor() - RADIUS)
turtle.circle(RADIUS, extent=SLICE_ANGLE)
turtle.home()
turtle.end_poly()
screen.register_shape("wedge", turtle.get_poly())
# create a turtle for each wedge in the pie
turtles = []
for hue in range(NUMBER_OF_WEDGES):
turtle = Turtle("wedge")
turtle.color(hsv_to_rgb(hue / NUMBER_OF_WEDGES, 1.0, 1.0))
turtle.setheading(hue * SLICE_ANGLE)
turtles.append(turtle)
def draw_circle():
# have each turtle take on the color of its neighbor
for index, turtle in enumerate(turtles):
turtle.color(*turtles[(index + 1) % NUMBER_OF_WEDGES].color())
screen.update()
screen.ontimer(draw_circle, 40)
draw_circle()
screen.exitonclick()
Notice how much simpler our main loop, draw_circle(), is and that the spinning doesn't slow down.

Categories

Resources