I am trying to double the size of the turtle in the window every time I press x on my keyboard. I tried using .turtlesize(2,2,2), but that's not right. I need to double every time the key is pressed so if the turtle size is (1,1,1), it will become (2,2,2) then (4,4,4) and so on each time I press x.
This is what I have so far:
import turtle
turtle.setup(500,500)
wn = turtle.Screen()
wn.title("Commands")
wn.bgcolor("black")
tess = turtle.Turtle()
tess.shape("triangle")
tess.color("red")
tess.left(90)
def increaseSize():
size = tess.turtlesize()
increase = tuple([2 * num for num in size])
tess.turtlesize(increase) #this is where the error occurs
wn.onkey(increaseSize, "x")
wn.listen()
Change this line:
tess.turtlesize(increase)
to instead be:
tess.turtlesize(*increase)
turtlesize() wants three separate values but you were passing one tuple of three values so we need to spread that tuple across the argument list.
The default size of a Turtle object is 20 pixels, which is the equivalent of the ratio 1 when resizing the Turtle.
For example:
import turtle
tess = turtle.Turtle()
print(tess.shapesize())
Output:
(1.0, 1.0, 1)
The first two 1.0s in the tuple represents how many units 20 pixels the Turtle's width and height are, and the last 1 represents the width of the Turtle's outline.
You won't be able to see the outline if you only pass one argument into the tess.color() brackets, because by default, there is no outline.
To increase the Turtle's size, simply pass in the number of 20 pixels you want each of the Turtle's dimensions to be into tess.shapesize() or tess.turtesize():
import turtle
tess = turtle.Turtle()
tess.shapesize(2, 3, 1) # Sets the turtle's width to 60px and height to 90px
The other answer points out that the turtlesize function does not take in an
array; it takes in ints or floats, so you'll need to unpack the tuple with a *
when you pass the tuple into the function.
In your increaseSize function, the tuple and [] wrappers aren't necessary,
and only wastes efficiency. Simply use ():
def increaseSize():
size = tess.turtlesize()
increase = (2 * num for num in size)
tess.turtlesize(*increase)
On top of your code there is
turtle.setup(500,500)
wn = turtle.Screen()
Since you defined a Screen object, wn, it's cleaner to use wn.setup() instead of turtle.setup():
wn = turtle.Screen()
wn.setup(500,500)
All together:
import turtle
wn = turtle.Screen()
wn.setup(500,500)
tess = turtle.Turtle("triangle")
tess.color("red")
tess.left(90)
def increaseSize():
size = tess.turtlesize()
increase = (2 * num for num in size)
tess.turtlesize(*increase)
wn.onkey(increaseSize, "x")
wn.listen()
Output:
Related
So I'm writing a tron game in python turtle and I want to make the two bikes start at whatever the screen width is/2, and height/2. (Same thing for the other but negative width). Sadly this doesn't seem to work because you can't divide a function by an int. Does anyone know how to do it?
This is what I tried:
width = turtle.window_width
height = turtle.window_height
def tron():
#Drawing the starting turtles
blueplayer = turtle.Turtle()
redplayer = turtle.Turtle()
screen = turtle.Screen()
screen.setup(width, height)
screen.bgpic('TronBg.png')
screen.bgcolor('black')
screen.addshape('BlueBike.gif')
screen.addshape('RedBike.gif')
blueplayer.shape('BlueBike.gif')
redplayer.shape('RedBike.gif')
redplayer.pencolor("red")
redplayer.pensize(3)
blueplayer.pencolor("blue")
blueplayer.pensize(3)
redplayer.pu()
blueplayer.pu()
-> blueplayer.goto(width/2, height/2)
-> redplayer.goto(-1*(width)/2, height/2)**
redplayer.pd()
blueplayer.pd()
#Box border
#Border
box = Turtle()
box.ht()
box.color('purple')
box.speed('fastest')
box.pensize(10)
box.pu()
box.setpos(-355, -345)
box.pd()
for i in range(5):
box.forward(700)
box.left(90)
tron()
Change your code as follows and the problem will go away:
import turtle
width = turtle.window_width()
height = turtle.window_height()
P.S. to obtain window width you call in case of the turtle module a function. To call a function it is necessary to provide () after the function name, else width will become just another name for turtle.window_width function.
If you don't put the brackets after turtle.window_width in width = turtle.window_width you can solve the problem by adding width = width() in the next line. Try this out to see that it works in order to gain better understanding of what an assignment operator = does.
By the way: you can check which type and which value the variable width has with print(type(width), width). Such print debugging is often helpful because sometimes it is necessary to use value = module.some_name and sometimes value = module.some_name() to get the right value.
I need to make 20x20 grid with three green squares next to each other like a snake with a 'for' function. In each Run and Check, the position must be different. I tried to mess around with coordinates a little. But I didn't find the solution. Can you help me?
Code:
import tkinter
import random
c=tkinter.Canvas()
c.pack()
c.config(width=600, height=600)
gw=26
gs=2
go="white"
gf="gray"
rf='green'
for i in range(gs,600, 30):
for j in range(gs,600, 30):
c.create_rectangle(i,j,i+gw,j+gw, width=gs, outline=go, fill=gf)
#this is the code for three green squares
for i in range(3):
rx=random.randrange(gs, 600, 30)
ry=random.randrange(gs, 600, 30)
c.create_rectangle(rx, ry, rx+gw, ry+gw, width=gs, fill=rf, outline=go)
c.mainloop()
The below code shows a method for calculating the position of the snake at random but placing the two subsequent squares next to the first.
Rather than drawing a new rectangle each time, I'm just changing the color of the squares on the grid for each "segment" of the snake.
import tkinter
import random
c=tkinter.Canvas()
c.pack()
c.config(width=600, height=600)
gw=26
gs=2
go="white"
gf="gray"
grid = {}
for i in range(gs,600, 30):
for j in range(gs,600, 30):
obj = c.create_rectangle(i,j,i+gw,j+gw, width=gs, outline=go, fill=gf)
grid[(i//30,j//30)] = obj
#Calculate starting position of the "snake"
#Limit the starting position between 3 and 17 so that we don't go off the edge to start with
rx=random.randint(3,17)
ry=random.randint(3,17)
#Create a list of the different parts of the snake
#Item 1 is random, item 2 and 3 are the next squares over
snake = []
snake.append((rx,ry))
snake.append((rx+1,ry))
snake.append((rx+2,ry))
#Iterate over each part of the snake, and set each square to green
for segX,segY in snake:
rf='green'
#c.create_rectangle(rx, ry, rx+gw, ry+gw, width=gs, fill=rf, outline=go)
c.itemconfigure(grid[segX,segY],fill=rf)
c.mainloop()
when the snake grows in size, you just append a new set of coordinates to the snake list. To move the snake, just set a new coordinate in the list at the front, and remove the item from the end.
EDIT: I've add the code from the turtle module at the end of this question. I can't see why there is self.screensize(wx-20, wy-20), but I expect that is the source of the issue.
I'm confused by setworldcoordinates() from the Python turtle module. I can't see why my code displays negative x-ccordinates when I click near the left-hand edge of the turtle window, as in the image below.
My code is below. Could someone please explain how to modify it to have the left-hand edge of the window be at exactly x=0?
import turtle
BLOCK_SIZE = 40
BORDER = 5
STAMP_SIZE = 20
ROWS = 10
COLUMNS = 12
def click_handler(x, y):
print(x, y)
screen = turtle.Screen()
screen.setup(COLUMNS * (BLOCK_SIZE + BORDER), ROWS * (BLOCK_SIZE + BORDER))
screen.setworldcoordinates(0, 0, screen.window_width(), screen.window_height())
screen.onclick(click_handler)
setworldcoordinates definition from turtle module:
def setworldcoordinates(self, llx, lly, urx, ury):
"""Set up a user defined coordinate-system.
Arguments:
llx -- a number, x-coordinate of lower left corner of canvas
lly -- a number, y-coordinate of lower left corner of canvas
urx -- a number, x-coordinate of upper right corner of canvas
ury -- a number, y-coordinate of upper right corner of canvas
Set up user coodinat-system and switch to mode 'world' if necessary.
This performs a screen.reset. If mode 'world' is already active,
all drawings are redrawn according to the new coordinates.
But ATTENTION: in user-defined coordinatesystems angles may appear
distorted. (see Screen.mode())
Example (for a TurtleScreen instance named screen):
>>> screen.setworldcoordinates(-10,-0.5,50,1.5)
>>> for _ in range(36):
... left(10)
... forward(0.5)
"""
if self.mode() != "world":
self.mode("world")
xspan = float(urx - llx)
yspan = float(ury - lly)
wx, wy = self._window_size()
self.screensize(wx-20, wy-20)
oldxscale, oldyscale = self.xscale, self.yscale
self.xscale = self.canvwidth / xspan
self.yscale = self.canvheight / yspan
srx1 = llx * self.xscale
sry1 = -ury * self.yscale
srx2 = self.canvwidth + srx1
sry2 = self.canvheight + sry1
self._setscrollregion(srx1, sry1, srx2, sry2)
self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
self.update()
There are three sizes to consider: size of the window on the screen; size of the visible area of the window we can draw on; size of the window's canvas backing store that we can scroll. I believe you can adjust the third using turtle's screensize() method.
Between the size of the window on the screen and the the size of the visible drawing area sits the chrome, the window's overhead of borders and border shadows, etc. It seems like turtle is simply estimating these instead of calculating them based on window system characteristics:
self.screensize(wx-20, wy-20)
This uncommented magic -20 appears nowhere else in the turtle code. I'd guess the tkinter underpinnings could provide an exact value.
The two problems I see are that turtle's estimate can be off and onclick() is registering clicks on a portion of the chrome (on my system), which doesn't make sense. The best I could come up with is compounding it with an estimated correction:
from turtle import Screen
BLOCK_SIZE = 40
BORDER = 5
ROWS = 10
COLUMNS = 12
WIDTH = COLUMNS * (BLOCK_SIZE + BORDER)
HEIGHT = ROWS * (BLOCK_SIZE + BORDER)
CHROME = 7 # correction guesstimate for OS X
def click_handler(x, y):
print(x, y)
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.setworldcoordinates(CHROME, CHROME, WIDTH, HEIGHT)
screen.onclick(click_handler)
screen.mainloop()
If you click on the left or bottom chrome, you should get values < zero (I won't say negative as -0.0 turns up here) until you click on the drawable part of the window. The right and top will produce values greater than the calculated width and height if you click on the chrome, but within them otherwise.
Again, I believe the real solution lies in turtle's tkinter underpinnings.
nowadays I'm writing a program to fetch 4 poker cards from 52 poker cards randomly and I have to draw these pokers by python turtle module. Now here's my question: cause there's an upside-down number in pokers, just like this(the bottom right corner number)
at first I want to use this code to generate the numbers:
import turtle as do
def generate_digital(number, x, y, start_angle, size):
'''
this function generate '2-10'
parameters:
number: this is number you want to write
x and y: this is the pen's initial location
start_angle: the pen's initial direction
size: the number's size
'''
do.penup()
do.goto(x, y)
do.pensize(30)
do.setheading(start_angle)
do.write(number, font=("Arial", size, "normal"))
I want to use
do.settheading() to set the angle of the number, but I found that it didn't work! I can get a 5 but I can't get a upside-down 5 using the do.write() method......
Now, the only way myself can think of is to use this
def generate_photo_2(x, y, start_angle, size):
'''
this function generate a '2'
parameters:
just like last function
'''
do.penup()
do.goto(x, y)
do.pensize(3)
do.setheading(start_angle)
do.pendown()
do.circle(-size, 200)
do.fd(2 * size)
do.left(45)
do.fd(0.6 * size)
do.left(90)
do.fd(2 * size)
code to 'draw' a number, and by setting the start angle, I can 'draw' a upside-side number 2, but it causes a lot of trouble, isn't it?
Could anybody tells me how to write() a upside-down number?
Thank you very much!!!
turtle doesn't have function to display text upside down.
But turtle is built on top of tkinter module and Canvas widget which has method
create_text(x, y, text=.., angle=..., ...)
Working example
import turtle
c = turtle.getcanvas()
item_id = c.create_text(0, 0, text='5', angle=180, font=("Arial", 30, "normal"))
turtle.mainloop() # run tkinter event loop
Later you can change angle using item_id
c.itemconfig(item_id, angle=45)
Effbot.org: Canvas in tkinter.
BTW: I found information that only the newest tkinter with Tk 8.6 has angle=.
You can check version
import tkinter
print(tkinter.TkVersion)
Hopefully I'll be able to explain this well. I'm currently using helper functions to draw a six-pointed star in the turtle graphics window of python. First, we had to create a function to draw a triangle. Here is my code:
import turtle
wn = turtle.Screen()
tess = turtle.Turtle()
tess.speed(30)
def triangle(sz):
for i in range(3):
tess.fd(sz)
tess.lt(120)
Then, we had to use the triangle function to draw a six-pointed star. Here is my code:
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd(80)
tess.rt(90)
tess.fd(120)
tess.pd()
tess.rt(180)
triangle(sz)
Now, for me, this all runs smoothly. But the parameters for our test run of those two functions was that sz = 120 (so in the shell we'd type sixPtdStar(120) and it would run. But then we had to draw a row of stars with a new function, and then a BOX outline by those rows of stars, in another function. Here is my code:
def rowOfStars(numInRow,sz):
for i in range(numInRow):
sixPtdStar(sz)
tess.pu()
tess.lt(90)
tess.fd(80)
tess.lt(90)
def sqrOfRows(numInRow, sz):
for i in range(4):
rowOfStars(numInRow, sz)
tess.rt(90)
While this accomplishes the task, it only does so if the sz = 120. And for our test run on the rowOfStars function, the parameters are supposed to be (6, 72) and for the test run on the sqrOfRows function, our parameters are supposed to be (6, 36).
So my issue is this. How can I make this work no matter what sz equals? When I run it as is (with (6, 72) for rowOfStars or (6, 36) for sqrOfRows), the pen moves too far because the triangles aren't as big anymore.
Please let me know if more info is needed! Thanks! (I'm using Python 3.5.2)
Anywhere you use a unit that has a dimension:
tess.fd(80)
tess.fd(120) # probably should be tess.fd(sz)
tess.fd(80)
you need to scale it by what ever logic you used to get from 120 (sz) to 80. However, as #wptreanor mentioned, that logic is slightly flawed as the points on your star are uneven:
Also, your rowOfStars() routine doesn't really draw a row of stars (math is off and the pen is in the wrong state at times.) Simply fixing the scaling won't fix this. Finally, your sqrOfRows() routine won't work until rowOfStars() is fixed, and to make it useful, you need to adjust the starting position on the screen to make room for the drawing.
Below is my rework of your code to address some of these issues. It uses a slightly different calculation of how to position from finishing the lower to starting the upper triangle so the numbers are slightly different:
from turtle import Turtle, Screen
WIDTH_RATIO = 2 * 3**0.5 / 3 # ratio of widest point in star to edge of triangle
def triangle(size):
for i in range(3):
tess.fd(size)
tess.lt(120)
def sixPtdStar(size):
triangle(size)
tess.lt(30)
tess.pu()
tess.fd(size * WIDTH_RATIO)
tess.lt(150)
tess.pd()
triangle(size)
def rowOfStars(numInRow, size):
for i in range(numInRow):
sixPtdStar(size)
tess.pu()
tess.lt(90)
tess.fd(size * WIDTH_RATIO / 2)
tess.lt(90)
tess.pd()
def sqrOfRows(numInRow, size):
tess.pu()
halfSize = numInRow * size / 2
tess.goto(-halfSize, halfSize) # center on screen
tess.pd()
for i in range(4):
rowOfStars(numInRow, size)
tess.rt(90)
screen = Screen()
tess = Turtle()
tess.speed("fastest") # numbers > 10 are all equivalent, safer to use symbols
sqrOfRows(6, 36)
screen.exitonclick()
The problem is in your sixPtdStar() function.
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd(80) # here
tess.rt(90)
tess.fd(120) # and here
tess.pd()
tess.rt(180)
triangle(sz)
If your function takes a size as a parameter, all functions involving movement (such as forward() or goto()) need to be scaled by the size as well. The following code should work:
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd((2.0/3.0)*sz) #formerly 80
tess.rt(90)
tess.fd(sz) #formerly 120
tess.pd()
tess.rt(180)
triangle(sz)
This will ensure that all forward movements are proportional to the size of the object you create. You will need to make similar tweaks to your rowOfStars() function. I've also noticed that your six pointed star isn't fully symmetrical. You could resolve that by replacing tess.fd((2.0/3.0)*sz) with tess.fd((7.0/12.0)*sz).