I'm learning how to use Turtle for Python, so I'm drawing basic shapes for now. I noticed that when I try to draw a perfect square or other perfect polygon, the result looks "squished". The shape is always wider than it is tall, even though I have one set length value.
Is something wrong with my logic of how I draw the shapes?
Here's the code I have:
import turtle
bgColor = "teal"
worldX = 100
worldY = 100
turtle.screensize(bg=bgColor)
turtle.setworldcoordinates(0,worldX,worldY,0)
#Canvas is 100 x 100, with (0,0) being the upper left corner and (100,100) being the lower right corner
tr = turtle.Turtle()
tr.speed(6)
tr.color("black")
length = 5 #Length of sides you want
sides = 4 #Number of sides for shape
tr.penup()
tr.goto(worldX/2, worldY/2) #Go to center of canvas
tr.pendown()
for i in range(sides):
tr.forward(length)
tr.right(360/sides)
turtle.done()
I figured it out, it had to do with my screen size. If my screen size is more wide than tall, then my world coordinates are off. For example, suppose my screen size is 400x800. Because my screen is twice as wide compared to it's height, moving my turtle one point to the right or left would require the turtle to move twice the distance compared to moving the turtle one point up or down. Meaning that if I draw a 5x5 square based on my coordinate system, it would actually be a rectangle, even though it's 5x5 on my coordinate system.
Anyway, here's my new code that takes this into account:
import turtle
import random
bgColor = "teal"
worldX = 100
worldY = 100
screenX = 400
screenY = 400
screen = turtle.Screen()
screen.setup(screenX,screenY)
turtle.screensize(bg=bgColor)
turtle.setworldcoordinates(0,worldX,worldY,0)
#Canvas is 100 x 100, with (0,0) being the upper left corner and (100,100) being the lower right corner
print(turtle.screensize())
tr = turtle.Turtle()
tr.speed(6)
tr.color("black")
length = 20 #Length of sides you want
sides = 4 #Number of sides for shape
tr.penup()
tr.goto(worldX/2, worldY/2) #Go to center of canvas
tr.pendown()
for i in range(sides):
tr.forward(length)
tr.right(360/sides)
turtle.done()
Related
current code
#import the turtle modules
import turtle
#Start a work Screen
ws=turtle.Screen()
#Define a Turtle Instance
geekyTurtle=turtle.Turtle()
#executing loop 6 times for 6 sides
for i in range(6):
#Move forward by 90 units
geekyTurtle.forward(90)
#Turn left the turtle by 300 degrees
geekyTurtle.left(300)
My goal is to make a hexagon grid pattern and I am failing to do it properly. My first issue is if you run the code you get a hexagon but the top is flat, I can't get it to get the pointy corners to get on top. Second I tried to make the grid and it failed and I am not sure why I am unable to copy the same hexagon and clone it next to the other. I will or should have a file of the image that I am going for below.
The output I am getting:
The output I am trying to get:
Before going into loop, turn 30 degrees.
geekyTurtle.right(30)
In order to have its clone beside, just put the turtle to the new place and draw the shape again:
for i in range(6):
geekyTurtle.forward(90)
geekyTurtle.left(300)
geekyTurtle.up()
geekyTurtle.goto(90 * 3 ** .5, 0)
geekyTurtle.down()
for i in range(6):
geekyTurtle.forward(90)
geekyTurtle.left(300)
Put it in a loop to have it for more than two times
You can use the idea of .up() and .goto(x, y) and .down() to draw grids.
It seems like this is a problem that recursion could simplify in a fractal-like way. Each side of the initial hexagon is itself a hexagon, and so forth, filling the available space:
from turtle import Screen, Turtle
SIDE = 75 # pixels
def hexagon(side, depth):
if depth > 0:
for _ in range(6):
turtle.forward(side)
turtle.right(60)
hexagon(side, depth - 1)
turtle.left(120)
screen = Screen()
screen.tracer(False) # because I have no patience
turtle = Turtle()
turtle.penup()
turtle.width(2)
turtle.sety(-SIDE) # center hexagons on window
turtle.pendown()
turtle.left(30) # optional, orient hexagons
hexagon(SIDE, depth=6) # depth depends on coverage area
turtle.hideturtle()
screen.tracer(True)
screen.exitonclick()
We would like to create a rectangle with width w and height h, on a surface whose width is a and whose height is b.
What would be the values of left, top, width, height that we have to pass to the pygame.Rect function, if the rectangle needs to be at a distance x_offset from the left edge of the surface and centered vertically on the surface?
I got this question and I know that left would be equal to x_offset but I have no idea how to figure out any of the other ones I've tried drawing it out.
Just create your Rect object first with the values you know:
rect = pygame.Rect(x_offset, 0, w, h)
and center the rect by using its centery attribute:
rect.centery = the_other_surface.get_rect().centery
It can help if you rename the variables into something readable.
For example:
rect_width = w
rect_height = h
surface_width = a
surface_height = b
rect_width and rect_height will be the Rect's width and height.
The x_offset will be the left.
rect_left = x_offset
To center it vertically, find the vertical center:
surface_center_v = surface_height / 2
Then place the rectangle there.
rect_top = surface_center_v
However this only places the rectangle's top edge, and we want the vertical center.
So adjust the rectangle's position upwards by half of the rectangle's height, to make the rectangle's vertical center align with the surface's vertical center.
rect_top -= rect_height / 2
Now you have all of rect_left, rect_top, rect_width and rect_height.
To use all of the specified variables (rather than hard-coding absolute sizes into the program), I would make use of pygame's Rectangle object for both the surface and the rectangle we want to draw.
import pygame
from time import sleep
pygame.init()
# Declare our variables and initialize
a,b = 0,0 # Declare screen dimensions.
w,h = 0,0 # Declare rectangle dimensions.
x,y = 0,0 # Declare placement locations on screen surface.
# Now set specific values to our variables
a = 500 # Screen Width
b = 500 # Screen Height
# We could use any surface here (such as for a sprite), but let's use the screen.
screen = pygame.display.set_mode((a,b),32) # Create a screen surface of size a X b
screen.fill(pygame.Color("DARKBLUE")) # Fill it with Dark Blue.
screen_rect = screen.get_rect() # Create a rectangle object for the screen.
w = 200 # Make the rectangle 200 wide.
h = 100 # Make the rectangle 100 high.
rec = pygame.Rect((x,y,w,h)) # Create a rectangle object for our drawn rectangle.
# Rec holds all of the placement and size values for the rectangle we want to draw.
rec_color = (255,0,0) # Let's draw a red rectangle.
distance_x = 50 # Place the rectangle 50 pixels over from the left side of the screen.
rec.x = distance_x # Set rec's x value equal to distance_x.
rec.centery = screen_rect.centery # Set rec's y value to center of the screen y-axis
# Pygame's Rectangle Object handles the calculations for us. NICE!
pygame.draw.rect(screen,rec_color,rec,2) # Draw a rectangle on the screen using a line
# that is 2-pixels wide. (Use 0 to fill.)
pygame.display.flip() # Show the screen.
print("\nrec =",rec,end="\n\n") # Let's see rec's final values.
sleep(3) # Sleep for 3 seconds.
exit() # Quit
I got a simple figure using turtle. But the problem is I dunno how to put that figure inside circle.
Code:
import turtle
painter = turtle.Turtle()
painter.pencolor("blue")
for i in range(50):
painter.forward(100)
painter.left(123*2)
painter.circle(70)
turtle.done()
A bit of trigonometry in my head and I figured the angle. Not sure if I got the radius correct though. Ideally figure out the coordinates of the center instead, but a quick and dirty solution is:
import turtle
painter = turtle.Turtle()
painter.pencolor("blue")
for i in range(50):
painter.forward(100)
painter.left(123*2)
painter.right(123)
painter.right(90)
painter.penup()
painter.forward(10)
painter.left(90)
painter.pendown()
painter.circle(70)
turtle.done()
You will need to move the turtle to the correct starting position. NOTE that's not the circle's center! It starts drawing the circle from its rightmost position - i.e., if you want a circle with radius 70 around (0,0), then move to (70,0), e.g.:
painter.penup()
painter.goto(70,0)
painter.pendown()
painter.circle(70)
FYI: I can't immediately figure out where the center of your drawing is, but I suspect it is NOT at (0,0). In all cases, you should place the turtle to the right of your shape's center, offset by the circle's radius, to make the circle go around it.
Another approach would be to average the positions of your arbitrary image and then use that average as the center of the surrounding circle:
from turtle import Screen, Turtle, Vec2D
CIRCLE_RADIUS = 70
POLYGON_LENGTH = 100
POINTS = 50
screen = Screen()
painter = Turtle()
painter.speed('fastest')
painter.pencolor("blue")
total = Vec2D(0, 0)
for _ in range(POINTS):
painter.forward(POLYGON_LENGTH)
total += painter.position()
painter.left(246)
x, y = total * (1.0 / POINTS) # Vec2D can multiply by scalar but not divide
painter.penup()
painter.goto(x, y - CIRCLE_RADIUS)
painter.setheading(0)
painter.pendown()
painter.circle(CIRCLE_RADIUS)
screen.exitonclick()
So I'm still very new to python and trying to learn through making small projects.
The game I'm making is meant to test your mouse accuracy by creating a bunch of random circles which the player is meant to click in a given amount of time. At the end of the game, it should tell the player their score, and how many misclicks they had.
I've been using turtle to try and do this, but I'm stuck:
import turtle
import random
t = turtle.Pen()
win = turtle.Screen()
win.bgcolor("lightgreen")
win.title("clicky")
def mycircle(red, green, blue):
t.color(red, green, blue)
t.begin_fill()
x = random.randint(10,50)
t.circle(x)
t.end_fill()
t.up()
y = random.randint(0,360)
t.seth(y)
if t.xcor() < -300 or t.xcor() > 300:
t.goto(0, 0)
elif t.ycor() < -300 or t.ycor() > 300:
t.goto(0, 0)
z = random.randint(0,100)
t.forward(z)
t.down()
for i in range(0, 20):
a = random.randint(0,100)/100.0
b = random.randint(0,100)/100.0
c = random.randint(0,100)/100.0
mycircle(a, b, c)
The main issues I've been trying to figure out are:
How can I make the circles spawn further from each other? They overlap
quite often and I want that to be avoided.
How can I make the circles spawn instantly rather than having to be
drawn?
How can I make the circles spawn further from each other?
We can keep track of circles already created and make sure their centers are at least a diameter away from each other. Your current circle placement logic is too complicated along with being faulty. Let's try to simplify it and make sure circles are drawn completely within the window.
How can I make the circles spawn instantly rather than having to be
drawn?
We could stamp them rather than draw them. However, since you are drawing so few circles, we can make every circle a turtle. This makes determining if you clicked on a circle, and removing that circle, simpler. I've added code, for you to expand on, that removes any circle that you click on:
from turtle import Turtle, Screen
from random import random, randint
CURSOR_SIZE = 20
def my_circle(color):
radius = randint(10, 50)
circle = Turtle('circle', visible=False)
circle.shapesize(radius / CURSOR_SIZE)
circle.color(color)
circle.penup()
while True:
nx = randint(2 * radius - width // 2, width // 2 - radius * 2)
ny = randint(2 * radius - height // 2, height // 2 - radius * 2)
circle.goto(nx, ny)
for other_radius, other_circle in circles:
if circle.distance(other_circle) < 2 * max(radius, other_radius):
break # too close, try again
else: # no break
break
circle.showturtle()
circle.onclick(lambda x, y, t=circle: t.hideturtle()) # expand this into a complete function
return radius, circle
screen = Screen()
screen.bgcolor("lightgreen")
screen.title("clicky")
width, height = screen.window_width(), screen.window_height()
circles = []
for _ in range(0, 20):
rgb = (random(), random(), random())
circles.append(my_circle(rgb))
screen.mainloop()
One issue you need to work out is making sure your circle color isn't too similar to (or the same as) your background color, otherwise you'll be hunting an invisible circle. Also, we might be able to speed up the circle drawing process even more, if needed.
I was showing a grandson patterns drawn with Python's Turtle module,
and he asked to see concentric circles.
I thought it would be faster to use the turtle's circle() to draw them
than to write my own code for generating a circle. Ha! I am stuck.
I see that the circle produced begins its circumference at the turtle's
current location and its direction of drawing depends on turtle's current
direction of motion, but I can't figure out what I need to do to get
concentric circles.
I am not at this point interested in an efficient way of producing
concentric circles: I want to see what I have to do to get
this way to work:
def turtle_pos(art,posxy,lift):
if lift:
art.penup()
art.setposition(posxy)
art.pendown()
def drawit(tshape,tcolor,pen_color,pen_thick,scolor,radius,mv):
window=turtle.Screen() #Request a screen
window.bgcolor(scolor) #Set its color
#...code that defines the turtle trl
for j in range(1,11):
turtle_pos(trl,[trl.xcor()+mv,trl.ycor()-mv],1)
trl.circle(j*radius)
drawit("turtle","purple","green",4,"black",20,30)
You can do it like this:
import turtle
turtle.penup()
for i in range(1, 500, 50):
turtle.right(90) # Face South
turtle.forward(i) # Move one radius
turtle.right(270) # Back to start heading
turtle.pendown() # Put the pen back down
turtle.circle(i) # Draw a circle
turtle.penup() # Pen up while we go home
turtle.home() # Head back to the start pos
Which creates the picture below:
Basically it moves the turtle down one radius lenght to keep the center point for all the circles in the same spot.
From the documentation:
The center is radius units left of the turtle.
So wherever the turtle is when you start to draw a circle, the center of that circle is some distance to the right. After each circle, just move left or right some number of pixels and draw another circle whose radius is adjusted for the distance the turtle moved. For example, if you draw a circle with a radius of 50 pixels, then move right 10 pixels, you would draw another circle with a radius of 40, and the two circles should be concentric.
I am not at this point interested in an efficient way of producing
concentric circles: I want to see what I have to do to get this way to
work
To address the OP's question, the change to their original code to make it work is trivial:
turtle_pos(trl, [trl.xcor() + mv, trl.ycor() - mv], 1)
trl.circle(j * radius)
becomes:
turtle_pos(trl, [trl.xcor(), trl.ycor() - mv], 1)
trl.circle(j * mv + radius)
The complete code with the above fix and some style changes:
import turtle
def turtle_pos(art, posxy, lift):
if lift:
art.penup()
art.setposition(posxy)
art.pendown()
def drawit(tshape, tcolor, pen_color, pen_thick, scolor, radius, mv):
window = turtle.Screen() # Request a screen
window.bgcolor(scolor) # Set its color
#...code that defines the turtle trl
trl = turtle.Turtle(tshape)
trl.pencolor(pen_color)
trl.fillcolor(tcolor) # not filling but makes body of turtle this color
trl.width(pen_thick)
for j in range(10):
turtle_pos(trl, (trl.xcor(), trl.ycor() - mv), True)
trl.circle(j * mv + radius)
window.mainloop()
drawit("turtle", "purple", "green", 4, "black", 20, 30)
So now i am giving you the exact code that can draw concentric circles.
import turtle
t=turtle.Turtle()
for i in range(5):
t.circle(i*10)
t.penup()
t.setposition(0,-(i*10))
t.pendown()
turtle.done()