I have a script for a simple turtle race and I want the race to start when the user clicks the left-mouse-button so i have this code
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race())
turtle.mainloop()
Assume that I have all variables defined.
when I run this code the race starts automatically and doesn't wait for the click.
onscreenclick takes a function as its parameter. You shouldn't be calling tur_race, turtle will do that when there is a click, rather you should pass tur_race itself. This is called a callback, you provide a function or method to be called by some event listener(e.g. the mouse being clicked on the screen).
In addition to #nglazerdev excellent answer, this would be your code after you apply what he said.
from turtle import *
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
You take out the () in the tur_race function. Otherwise, it will be called immediately.
Hope this helps!!
You need turtle.onscreenclick( tur_race ) without () after tur_race
Python can assign function's name (without () and arguments) to variable and use it later - like in example
show = print
show("Hello World")
It can also use function's name as parameter in other function and this function will use it later.
Offen (in different programming languages) this funcion's name is called "callback"
In turtle.onscreenclick( tur_race ) you send name to function onscreenclick and turtle will use this function later - when you click screen.
If you use () in turtle.onscreenclick( tur_race() ) then you have situation
result = tur_race()
turtle.onscreenclick( result )
which doesn't work in you code but can be useful in another situations.
In addition to everyone's answer, you need to add x and y parameters in the tur_race function. This is because turtle passes x and y parameters to the function, so your code would look like:
from turtle import *
def tur_race(x, y):
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
Related
The code I am trying to write needs to make 5 different shapes, which only one is included. I am not worried about coding the other 4.
What I need to know is how do I set it up so every time I press enter, turtle will perform a different function based on how many times the key is pressed?
This is the code I currently have, again very unfinished code.
import turtle
def draw_triangle():
turtle.color('black')
draw_line_turn()
draw_line_turn()
draw_line_turn()
def draw_line_turn():
turtle.down()
turtle.forward(30)
turtle.left(120)
turtle.up()
def triangle_sequence1():
turtle.clear()
draw_triangle()
def draw_ts1():
turtle.listen()
turtle.onkey(triangle_sequence1, "Return")
draw_ts1()
turtle.done()
Pretty much, ts1 is the first of 5 shapes that need to be drawn by pressing only the Enter key. I think I need to make a counter but I do not know how to do that.
There are countless ways to implement this sort of event handler.
One of them would be to create a class or namespace that keeps track of the different functions calls that draw the shapes and also has a variable that increases by 1 every time the enter button is pressed. Then in the onkey callback, create a new function that reads the key count and matches it up with the corresponding function from the namespace and calls that function.
For Example:
import turtle
def draw_triangle():
turtle.color('black')
draw_line_turn()
draw_line_turn()
draw_line_turn()
def draw_line_turn():
turtle.down()
turtle.forward(30)
turtle.left(120)
turtle.up()
def draw_square(): # I just created this as an example
turtle.up()
turtle.home()
turtle.left(90)
turtle.forward(120)
turtle.down()
for _ in range(4):
turtle.left(90)
turtle.forward(240)
class EnterKey:
"""
This is a simple namespace class that will keep track of our
different shape functions and the number of times the enter
key is pressed.
"""
count = 0 # Number of times the Enter key has been pressed
funcs = { # <- shape functions
1: draw_triangle, # to change the order they called just change the key
2: draw_square,
#3: draw_cirlce, <- continue to add functions when you make new shapes
}
def triangle_sequence1():
turtle.clear()
draw_triangle()
def draw_ts1():
turtle.listen()
turtle.onkey(handle, "Return")
def handle(): # this is the handler that calls the shape functions
EnterKey.times += 1 # <- Increase the number of times enter has been pressed
EnterKey.funcs[EnterKey.times]() # <- call the corresponding function for
# the newly increased number
draw_ts1()
turtle.done()
I am a student taking my first python class and we are using Turtle to draw an image. In an effort to save time I am trying to create a mirror function that can flip one functions results over the y-axis by a given number of pixels. For the sake of simplicity I created some functions to speed up my coding. Here is how my code works:
units, north, east, south, west = desiredPixelsPerUnit, 90, 0, 270, 180
def main():
eye(30, 15)
eye(40, 15)
def left():
myTurtle.left(90)
def draw(count):
distance = units * count
myturtle.forward(distance)
def singleStep(xDirection, yDirection, stepCount):
down()
for step in range(stepCount):
if yDirection == north:
point(north)
draw(1)
if xDirection == east:
point(east)
draw(1)
etc..
def eye(xPosition, yPosition):
....
draw(3)
left()
draw(2)
left()
....
singleStep(east, north, 1)
singleStep(west, north, 2)
etc....
All of this gives me the following
Result of running eye() in main twice:
What I am trying to create is a function that is passed another function then will look at what is being executed. if it is left() or right() run the opposite. If it is point (x, y) add 180 to x. If it has a function call that inside the function then it checks that as well for lefts or rights. Something like this.
def mirror(function):
for action in function:
if action == left():
execute right()
...
elif action == singleStep():
newFunction = singleStep()
for action in newFunction:
if:
statement above
else:
statement below
else:
execute initial action
I am still very new to coding and programming. I have tried using arrays, associative arrays and lists, using eval and more. The time spent trying to figure it out has been far longer than writing a separate instruction list for the left and the right hahah but I really want to figure out how to do something like this.
You could step back from calling left() and right() directly. Just create your own functions your_left() and your_right() and use them everytime. Then use a global variable called mirror. This variable will work as a flag for you. So you just set mirror to True when you want to mirror the output.
Your functions your_right() and your_left() will be looking something like this:
def your_right():
left() if mirror else right()
def your_left():
right() if mirror else left()
And then you are free to mirror all your outputs, if you want to. I hope i could help!
Here is how you can do that using yield:
import turtle
def function(): # Your function here, with the action calls replaced with yielding the un-called action, along with the argument
for _ in range(4):
yield turtle.forward, 100
yield turtle.right, 90
def mirror(function):
actions = {turtle.right: turtle.left,
turtle.left: turtle.right,
turtle.forward: turtle.backward,
turtle.backward: turtle.forward}
for action, argument in function():
actions[action](argument)
mirror(function)
Breaking it down:
When defining the function that will be passed into the mirror function,
do not call the turtle commands. Instead, use yield to yield the functions and arguments
as tuples, so that the mirror function will be able to access which functions should be called.
In the mirror function, define a dictionary of turtle commands, actions, that would be used to mirror with.
Iterate through the yielded turtle actions from the function passed into the brackets of the mirror function, and unpack the tuples into action, argument pairs to be used to mirror.
In this code I can't see why it isn't printing a hexagon 24 times. I tell it to make a 6 sided shape with 60 degrees between lines ( a hexagon) and tell it do turn 15 degrees each time. This ends up being a even 24 for the picture I'm trying to draw.
import turtle
Hex_Count = 0
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count = Hex_Count + 1
x.left(15)
print(Hex_Count)
Hexagon
But, for some reason, when I run this code the turtle screen pops up for about a half second then closes. How do I get it to perform in the way I want it to?
You have several errors that I corrected for you; I added the explanation in the comments:
import turtle
hexagons_count = 0
my_turtle = turtle.Turtle() # x is not a good name for a Turtle object
# my_turtle.speed(.25) # see #cdlane comment reported in a note under.
def draw_hexagon(): # use explicit names respecting python conventions (no camel case)
global hexagons_count # need global to modify the variable in the function scope
for idx in range(24): # use different dummy variable names in your loops
for jdx in range(6): # use different dummy variable names in your loops
my_turtle.forward(100)
my_turtle.left(60)
hexagons_count += 1
my_turtle.left(15)
print(hexagons_count)
draw_hexagon() # need parenthesis to call the function
turtle.exitonclick() # this to exit cleanly
Note: I know you simply copied it from the OP but my_turtle.speed(.25)
doesn't make sense as the argument should be an int from 0 to 10 or a
string like 'slow', 'fastest', etc. I especially don't understand why
beginners with turtle code that isn't working call turtle.speed() at
all -- it seems to me a function to be tweaked after everything is
working. #cdlane
You have some reference issue, you just need to put the variable hex_count where it needs to be so you don't have error accessing it.
import turtle
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
Hex_Count = 0
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count += 1
x.left(15)
print(Hex_Count)
Hexagon()
prints 24
You have several problems with your program. One is that it will when after running through the program, closing the window it created. You can add turtle.exitonclick() to the end of your script which tells python to wait for a click in the graphics window, after which it will exit.
The second problem is that you don't call the Hexagon function because you're missing the parentheses. Even if a function takes no arguments, you still need to call it like:
Hexagon()
The final problem is that you need to define Hex_Count before you try to increment it. Hex_Count + 1 will thrown an error if Hex_Count wasn't already assigned to. You can fix this by putting
Hex_Count = 0
before your for loop in Hexagon.
An approach different in a lot of the details but primarily in its use of circle() to more rapidly draw the hexagons:
from turtle import Turtle, Screen # force object-oriented turtle
hex_count = 0 # global to count all hexagons drawn by all routines
def hexagons(turtle):
global hex_count # needed as this function *changes* hex_count
for _ in range(24): # don't need explicit iteration variable
turtle.circle(100, steps=6) # use circle() to draw hexagons
turtle.left(15) # 24 hexagons offset by 15 degrees = 360
hex_count += 1 # increment global hexagon count
print(hex_count)
screen = Screen()
yertle = Turtle(visible=False) # keep turtle out of the drawing
yertle.speed('fastest') # ask turtle to draw as fast as it can
hexagons(yertle)
screen.exitonclick() # allow dismiss of window by clicking on it
I'm trying to make Connect 4 in python, but I can't figure out how to get the coordinates of the screen click so I can use them. Right now, I want to draw the board, then have someone click, draw a dot, then go back to the top of the while loop, wipe the screen and try again. I've tried a couple different options but none have seemed to work for me.
def play_game():
"""
When this function runs, allows the user to play a game of Connect 4
against another person
"""
turn = 1
is_winner = False
while is_winner == False:
# Clears screen
clear()
# Draws empty board
centers = draw_board()
# Decides whose turn it is, change color appropriately
if turn % 2 == 0:
color = RED
else:
color = BLACK
# Gets coordinates of click
penup()
onscreenclick(goto)
dot(HOLE_SIZE, color)
turn += 1
As well intentioned as the other answers are, I don't believe either addresses the actual problem. You've locked out events by introducing an infinite loop in your code:
is_winner = False
while is_winner == False:
You can't do this with turtle graphics -- you set up the event handlers and initialization code but turn control over to the main loop event handler. My following rework show how you might do so:
import turtle
colors = ["red", "black"]
HOLE_SIZE = 2
turn = 0
is_winner = False
def draw_board():
pass
return (0, 0)
def dot(color):
turtle.color(color, color)
turtle.stamp()
def goto(x, y):
global turn, is_winner
# add code to determine if we have a winner
if not is_winner:
# Clears screen
turtle.clear()
turtle.penup()
# Draws empty board
centers = draw_board()
turtle.goto(x, y)
# Decides whose turn it is, change color appropriately
color = colors[turn % 2 == 0]
dot(color)
turn += 1
else:
pass
def start_game():
"""
When this function runs, sets up a new
game of Connect 4 against another person
"""
global turn, is_winner
turn = 1
is_winner = False
turtle.shape("circle")
turtle.shapesize(HOLE_SIZE)
# Gets coordinates of click
turtle.onscreenclick(goto)
start_game()
turtle.mainloop()
Run it and you'll see the desired behavior you described.
I'm assuming that your using Turtle in python(hence the name.)
If that's the case, Here's a link to a helpful post: Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates
I know, i know. I hate just link answers as much as the next guy. But The post I gave a link to can probably do a much better job of answering your question than I can.
~Mr.Python
Assuming you're using turtle as mentioned in your title:
>>> import turtle
>>> help(turtle.onscreenclick)
Help on function onscreenclick in module turtle:
onscreenclick(fun, btn=1, add=None)
Bind fun to mouse-click event on canvas.
Arguments:
fun -- a function with two arguments, the coordinates of the
clicked point on the canvas.
num -- the number of the mouse-button, defaults to 1
Example (for a TurtleScreen instance named screen)
>>> onclick(goto)
>>> # Subsequently clicking into the TurtleScreen will
>>> # make the turtle move to the clicked point.
>>> onclick(None)
That means that your callback function, which you have apparently named goto, will take two parameters, an X and Y location.
import turtle
def goto(x, y):
print('Moving to {}, {}'.format(x,y))
turtle.goto(x, y)
turtle.onscreenclick(goto)
turtle.goto(0,0)
Each click that you make will move the turtle to a different position. Note that turtle already has an event loop - you don't need one of your own. Just respond to the clicks.
basically, you need to add an 'x' and 'y' parameter for the onclick and onscreenclick functions. You don't need to use them, they're just dummy params. After filling those out the clicks will work no problem:
window = turtle.Screen()
This function uses the x, y params because i'm saving the clicks in order to specify an area to fill with turtles
def on_left_click_save_coordinates(x, y):
global counter, Fill_COORS1, Fill_COORS2
counter += 1
print(x, y)
if counter == 1:
Fill_COORS1 = (x, y)
elif counter == 2:
Fill_COORS2 = (x, y)
counter = 0
This one doesn't use the x,y params because they are dummies, this one is used to allow multiple options, one of which exits, another tells the turtle to fill in the specified area saved in clicks above.
def on_right_click_open_options(x, y):
global going
last_color = options(window, filler, Fill_COORS1, Fill_COORS2, LAST_BLOCK_USED)
if type(Last_COLOR) == type(bool):
going = True
window.onscreenclick(on_click, btn=1)
window.onscreenclick(open_options, btn=3)
This is an example of a snippet of my code. hope this helps.
btn 3 refers to the right click
btn 1 is the default and isn't necessary to specify and refers to left click
btn 2 is the scroll wheel click, not scroll.
and sorry if this isn't formatted the best, it's my first time posting to stackoverflow. Hope it helps nonetheless
I simply want to use the turtle method onscreenclick to find the coordinates of a mouse click. Currently, I have a grid on which I am playing Othello. I already have the algorithm to convert the raw coordinates to specific grid coordinates that can be interpreted by the game. I cannot seem to get the onscreenclick method working. On the docs, it says to use a 'fun' function with two arguments. I believe I have this, but it is not working. I am a beginner with python and turtle so any help would be appreciated :)
import turtle
xclick = 0
yclick = 0
def getcoordinates():
turtle.onscreenclick(modifyglobalvariables())
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
getcoordinates()
You got so close!
import turtle
xclick = 0
yclick = 0
def getcoordinates():
turtle.onscreenclick(modifyglobalvariables) # Here's the change!
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
getcoordinates()
Catch the change? Syntactically, remove the parentheses after modfiyglobalvariables. What you want is to pass the function, what you are doing is passing the output of the function.
If you ran the code, you would get an exception (TypeError) saying you haven't passed the correct arguments; that's because it's trying to actually call modifyglobalvariables. Reduced, what you wanted was
bind_to_mouseclick( my_function )
In which case, at each mouse click, my_function will be called. At that point, it may or may not have the correct arguments supplied. Instead you said
bind_to_mouseclick( my_function() )
Python evaluates my_function and binds the result of the call to the mouse click. If my_function happens to return a function, that's great (maybe what we intended). If it returns an integer or a string, no good. The key is the exception, as noted above; if the function had required no arguments, this may have been subtler to detect
It's actually alot easier to detect where you clicked it. Here's the code:
from turtle import *
mouseclickx = 0
mouseclicky = 0
def findcoords(x,y):
print(x)
print(y)
mouseclickx = x
mouseclicky = y
onscreenclick(findcoords,1)
EDIT:
That doesn't work... well idk but it should be something like that :/ if you want a thing so it goes where you click, its one line;onscreenclick(goto,1)
from turtle import Turtle, Screen
screen = Screen()
def get_mouse_click(x, y):
print(x, Y)
screen.onscreenclick(get_mouse_click)
screen.mailoop()