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.
Related
I a currently trying to animate this bicycle in PYTHON TURTLE. I am struggling if anyone can teach me how to animate it with code, I will be grateful for that. I am adding more details as I am only trying to make the bicycle wheels move from one place to another like the bicycle wheels animation and the bicycle moves while the wheels are also moving thank you a lot!
import turtle
turtle.delay(10)
turtle.pensize(20)
# Move the turtle to the right position of the left tyre
turtle.penup()
turtle.setposition(-87.5, -50)
turtle.setheading(90)
# Draw the left tyre
turtle.begin_fill()
turtle.circle(62.5)
turtle.end_fill()
# Move the turtle to the right position of the right tyre
turtle.penup()
turtle.setposition(212.5, -50)
turtle.setheading(90)
# Draw the right tyre
turtle.begin_fill()
turtle.circle(62.5)
turtle.end_fill()
# Draw the handle
turtle.penup()
turtle.setposition(137.5, 0)
turtle.pendown()
turtle.setposition(75, 150)
# Draw the straight part of the handle
turtle.setheading(0)
turtle.setposition(125, 150)
# Draw the circular part of the handle
turtle.penup()
turtle.setposition(125, 100)
turtle.pendown()
turtle.circle(25, 180)
# Draw the seat tube
turtle.penup()
turtle.setposition(12.5, -50)
turtle.pendown()
turtle.setposition(-62.5, 137.5)
# Draw the saddle
turtle.setheading(180)
turtle.setposition(-100, 137.5)
# Draw the top tube
turtle.penup()
turtle.setposition(100, 75)
turtle.pendown()
turtle.setposition(-37.5, 75)
# Draw the down tube
turtle.penup()
turtle.setposition(100, 75)
turtle.pendown()
turtle.setposition(12.5, -50)
# Draw the seat stay
turtle.penup()
turtle.setposition(-37.5, 75)
turtle.pendown()
turtle.setposition(-150, -50)
# Draw the chain stay
turtle.penup()
turtle.setposition(12.5, -50)
turtle.pendown()
turtle.setposition(-150, -50)
Here is the code I came with for the animation of two wheels and some kind of handlebar :
import turtle
import time
def moving_wheel(turtle):
turtle.fillcolor('orange')
turtle.begin_fill()
turtle.circle(20)
turtle.end_fill()
def moving_handle(turtle):
pos = turtle.pos()
turtle.left(90)
turtle.forward(70)
turtle.left(120)
turtle.forward(110)
turtle.penup()
turtle.goto(pos)
turtle.right(210)
turtle.pendown()
if __name__ == "__main__":
screen = turtle.Screen()
screen.setup(600, 600)
screen.bgcolor('green')
screen.tracer(0)
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t3 = turtle.Turtle()
# set a turtle object color
t1.color('red')
t2.color('red')
t3.color('red')
# set turtle object speed
t1.speed(0)
t2.speed(0)
t3.speed(0)
t1.width(2)
t2.width(2)
t3.width(1.5)
t1.hideturtle()
t2.hideturtle()
t3.hideturtle()
# turtle object in air
t1.penup()
t2.penup()
t3.penup()
# set initial position
t1.goto(-250, 0)
t2.goto(-150,0)
t3.goto(-150,20)
t3.pendown()
# move turtle object to surface
t1.pendown()
t2.pendown()
# infinite loop
while True:
# clear turtle work
t1.clear()
t2.clear()
t3.clear()
# call function to draw ball
moving_wheel(t1)
moving_wheel(t2)
moving_handle(t3)
# update screen
screen.update()
# forward motion by turtle object
t1.forward(0.1)
t2.forward(0.1)
t3.forward(0.1)
You can modify the code for the handle part, I'm not an artist haha
Something similar to the picture attached. I tried modifying the code I got online. But my code goes to infinity loop
[1]: https://i.stack.imgur.com/HfKog.png
def draw_circle(radius):
turtle.up()
turtle.goto(0, radius) # go to (0, radius)
turtle.pendown() # pen down
times_y_crossed = 0
x_sign = 1.0
while times_y_crossed <= 1:
turtle.dot(5, "Red")
turtle.forward(5) # move by 1/360
turtle.right(1.0)
turtle.penup()
turtle.forward(5) # move by 1/360
turtle.right(1.0)
x_sign_new = math.copysign(1, turtle.xcor())
if x_sign_new != x_sign:
times_y_crossed += 10
x_sign = x_sign_new
turtle.up() # pen up
return
There are some issues with your code, like it does not count with the radius and the color for the pen was not set and as I've checked it did a half circle for me.
I show you a simple working example, first a dashed version because your original code looks like you wanted a dashed circle
import turtle
import math
def draw_circle_dashed(radius):
turtle.up()
turtle.goto(0, radius) # go to (0, radius)
times_y_crossed = 0
dist=2*math.pi*radius/360
turtle.pencolor("red")
for _ in range(180):
turtle.pendown()
turtle.forward(dist) # move by 1/360
turtle.right(1.0)
turtle.penup()
turtle.forward(dist) # move by 1/360
turtle.right(1.0)
turtle.up() # pen up
return
draw_circle_dashed(200)
and a dotted variant as well because of the question title
import turtle
import math
def draw_circle_dotted(radius):
turtle.up()
turtle.goto(0, radius) # go to (0, radius)
dist=2*math.pi*radius/360
for _ in range(360):
turtle.dot(2,"red")
turtle.forward(dist) # move by 1/360
turtle.right(1.0)
turtle.up() # pen up
return
draw_circle_dotted(300)
We can use turtle's own circle() method to do this as we can arbitrarily start and stop it, leaving behind dots as we do:
from turtle import Screen, Turtle
from math import pi
DOT_DIAMETER = 5
def draw_circle(radius):
turtle.penup()
circumference = 2 * pi * radius
dot_extent = 360 * DOT_DIAMETER*2 / circumference # diameter to angle
extent = 0
while extent < 360:
turtle.dot(DOT_DIAMETER)
turtle.circle(radius, extent=dot_extent)
extent += dot_extent
screen = Screen()
turtle = Turtle()
turtle.color('red')
draw_circle(100)
turtle.hideturtle()
screen.exitonclick()
Using what we learned from that exercise, let's now fix your code. The issue I see is this:
turtle.right(1.0)
The angle to turn is dependent on the dot diameter, but we actually have to calculate it:
from turtle import Screen, Turtle
from math import pi, copysign
DOT_DIAMETER = 5
def draw_circle(radius):
turtle.penup()
turtle.sety(radius)
diameter = 2 * radius
circumference = pi * diameter
dot_extent = 360 * DOT_DIAMETER / circumference # diameter to angle
times_y_crossed = 0
x_sign = 1
while times_y_crossed < 2:
turtle.dot(DOT_DIAMETER, 'red') # draw the dot
turtle.right(dot_extent)
turtle.forward(DOT_DIAMETER)
turtle.right(dot_extent) # draw the gap
turtle.forward(DOT_DIAMETER)
x_sign_new = copysign(1, turtle.xcor())
if x_sign_new != x_sign:
times_y_crossed += 1
x_sign = x_sign_new
turtle.pendown()
screen = Screen()
turtle = Turtle()
turtle.color('red')
draw_circle(100)
turtle.hideturtle()
screen.exitonclick()
By not calculating the angle, and using a fixed angle of 1.0, you were off by a factor of two.
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()
I need some help. I want to center the hexagon into the larger hexagon but I don't now how to do it. Below I have the source code and an image link to the output.
import turtle
polygon = turtle.Turtle()
num_sides = 6
side_length = 20
move_left = 60
polygon.pensize(2)
polygon.pencolor((245, 176, 66))
for turtle_move in range(num_sides):
polygon.forward(side_length)
polygon.left(move_left)
polygon.penup()
polygon.left(2)
polygon.pendown()
side_length2 = 40
move_left2 = 60
I want to center the hexagon inside the larger hexagons, but I don't know what to do.
for turtle_move in range(num_sides):
polygon.forward(side_length2)
polygon.left(move_left2)
Here is the output:
There are any number of ways to do this if you read about the geometry of hexagons, eg. on Wikipedia:
from turtle import Screen, Turtle
NUM_SIDES = 6
SIDE_LENGTH = 20
ANGLE_LEFT = 60
screen = Screen()
turtle = Turtle()
for _ in range(NUM_SIDES):
turtle.forward(SIDE_LENGTH)
turtle.left(ANGLE_LEFT)
turtle.penup()
turtle.backward(SIDE_LENGTH / 2)
turtle.sety(-SIDE_LENGTH * 3**0.5/2)
turtle.pendown()
for _ in range(NUM_SIDES):
turtle.forward(SIDE_LENGTH*2)
turtle.left(ANGLE_LEFT)
turtle.hideturtle()
screen.exitonclick()
One alternate approach is to use the turtle circle() method to draw the hexagons, then it becomes a matter of centering two circles:
from turtle import Screen, Turtle
NUM_SIDES = 6
SIDE_LENGTH = 20
circumradius = SIDE_LENGTH
screen = Screen()
turtle = Turtle()
for _ in range(2):
turtle.penup()
turtle.sety(-circumradius)
turtle.pendown()
turtle.circle(circumradius, steps=NUM_SIDES)
circumradius *= 2
turtle.hideturtle()
screen.exitonclick()
I'm assuming by your use of pencolor((245, 176, 66)) you're using a site like Repl.it or some other non-standard Python turtle implementation, so you may need to adjust the examples above slightly to suit your environment.
I'm trying to draw on a small 200x200 screen using turtle, however the drawing doesn't pop up as full size, it opens a smaller window and I have to scroll up/down, left/right (just a bit) to see the whole drawing. I don't have this problem with larger windows. How do I prevent this?
import turtle
import random
height, width = 200, 200
screen = turtle.Screen()
screen.setup(width, height)
screen.setworldcoordinates(0, 0, width, height)
t = turtle.Turtle()
t.speed(1)
for _ in range(5):
t.penup()
t.goto(random.randint(20, width-20), random.randint(0, height-40))
t.pendown()
t.circle(20)
edit: screenshot, I want the actual size window instead of the scrolls
You could resize the window to 420×420.
If you don't want to resize your window, I suggest modifying the values for the keys "canvwidth" and "canvheight" keys in the turtle._CFG dictionary:
import turtle
import random
height, width = 200, 200
screen = turtle.Screen()
screen.setup(width, height)
screen.setworldcoordinates(0, 0, width, height)
turtle._CFG.update({"canvwidth": width-20, "canvheight": height-20}) # Removing the scroll bars
t = turtle.Turtle()
t.speed(1)
for _ in range(5):
t.penup()
t.goto(random.randint(20, width-20), random.randint(0, height-40))
t.pendown()
t.circle(20)
screen.exitonclick()
Using small windows in turtle is a can of worms. If #TheOneMusic's simple solution (+1) is good enough for your purposes, go for it! On my system, your setworldcoordinates() call gets rid of the scroll bars, so I don't even see the issue. So, another approximate solution might be to upgrade to current Python and tkinter.
However, neither is an exact solution. If we add code to draw a 200 x 200 box around our drawing area:
t.penup()
t.color('red')
t.goto(0, 0) # because of setworldcoordinates()
t.pendown()
for _ in range(4):
t.forward(200)
t.left(90)
We get the box skewed:
To solve this problem more precisely, involves uglier code:
from turtle import Screen, Turtle
from random import randint
TRUE_WIDTH, TRUE_HEIGHT = 200, 200
CURSOR_SIZE = 20 # for drawing frame around edge
RADIUS = 20
CHROME = 14 # magic number possibly derivable from tkinter
width, height = TRUE_WIDTH + CHROME, TRUE_HEIGHT + CHROME # needs to be slightly larger than 200 target
offset_x = CHROME / -2 + 2
offset_y = CHROME / 2 - 2
screen = Screen()
screen.setup(width, height)
screen.screensize(width/2, height/2) # backing store needs to be smaller than window
screen.setworldcoordinates(0, 0, TRUE_WIDTH, TRUE_HEIGHT)
# Draw red frame around edge to "prove" drawing area
frame = Turtle(shape='square', visible=False)
frame.shapesize(TRUE_HEIGHT / CURSOR_SIZE, TRUE_WIDTH / CURSOR_SIZE) # 200 x 200 frame
frame.color('red', 'white')
frame.penup()
frame.goto(TRUE_WIDTH/2 + offset_x, TRUE_HEIGHT/2 + offset_y)
frame.stamp()
turtle = Turtle()
turtle.speed('fastest') # because I have no patience
for _ in range(5):
turtle.penup()
turtle.goto(randint(RADIUS, TRUE_WIDTH - RADIUS) + offset_x, randint(0, TRUE_HEIGHT - RADIUS*2) + offset_y)
turtle.pendown()
turtle.circle(RADIUS)
screen.exitonclick()
But this sort of detail work could easily be undone by a future release of turtle and/or tkinter. If you can live with turtle's default window, life gets easier.