Turtle from image won't draw over another turtle's stamp - python

This code sets up a background of stamps placed by one turtle. Another turtle, (whose shape is from an imported image file) moves around over the background. But the second turtle is not visible whenever it is positioned over a stamp placed by the first turtle. If I make the moving turtle one of the standard shapes, eg circle, then it stays visible. So there's something odd about using an imported image for the turtle, which causes it to disappear whenever it's on top of one of the stamps.
#!/usr/bin/python3
from turtle import *
from time import sleep
scr = Screen()
scr.register_shape('player.gif')
mover = Turtle()
bgnd = Turtle()
bgnd.color('blue')
mover.shape('player.gif')
bgnd.shape('square')
for i in range(5):
bgnd.goto(i*20,0)
bgnd.stamp()
for i in range(5):
mover.goto((8-i)*20,0)
sleep(1)
The accompanying image is the one I've referred to as player.gif (I can see it at the bottom of the post, but it's very small).
Can anyone help explain why this is and how to get around it?

I'm not sure if this is a bug or subtlety, but stamps aren't pixels on the screen like dot() -- the stamp() function returns an ID that allows selectively removing them. My guess is it's a layering issue with the underlying tkinter. In turtle, if you have a layering issue, sometimes it helps to do things in a different order:
from turtle import Screen, Turtle
from time import sleep
background = Turtle()
background.hideturtle()
background.color('blue')
background.shape('square')
for i in range(5):
background.goto(i * 20, 0)
background.stamp()
screen = Screen()
screen.register_shape('player.gif')
mover = Turtle()
mover.shape('player.gif')
for i in range(5):
mover.goto((8 - i) * 20, 0)
sleep(1)
screen.exitonclick()
In the long run, time.sleep() isn't a friend of event-based turtle. It's fine for examples like this but anything more and it will cause more problems than it solves. Look into the ontimer() method of the screen.

Related

Why is there a second Turtle?

I am learning turtle graphics in python and for some reason there is a second turtle on the screen and I haven't even created a second turtle. How can I get rid of the second turtle?
import turtle
s = turtle.getscreen()
t = turtle.Turtle()
for i in range(4):
t.fd(100)
t.rt(90)
turtle.exitonclick()
The second turtle at the starting location appears because of the line s = turtle.getscreen().
This line is not needed (you do not use s), and if you remove it this turtle disappears but the rest of the code seems to work as before.
The turtle library exposes two interfaces, a functional one (for beginners) and an object-oriented one. You got that extra turtle because you mixed the two interfaces (and #mkrieger1's solution doesn't fix that completely).
I always recommend an import like:
from turtle import Screen, Turtle
screen = Screen()
turtle = Turtle()
for _ in range(4):
turtle.forward(100)
turtle.right(90)
screen.exitonclick()
This gives you access to the object-oriented interface and blocks the functional one. Mixing the two leads to all sorts of bugs and artifacts.
To combine the answer from mkrieger1 and cdlane, you could replace
s = turtle.getscreen()
with
s = turtle.Screen()
You've still got a variable holding the screen (in case you should ever need it), and it doesn't generate that extra turtle in the center.

Run a turtle program in full screen when initiated

I wrote a Python 3.7 program with Turtle Graphics. It is a simple program and works fine, but I want it to run full-screen when I initiate the program. How can I do this? There is no full-screen option in the Turtle documentation.
import turtle
from turtle import *
a = turtle.Turtle()
a.speed(10)
a.color('red', 'blue')
# a.begin_fill()
for i in range(90):
a.fd(200)
a.lt(169)
# a.end_fill()
turtle.done()
The width and height arguments to the setup() method take integer (pixel) and floating point (percentage of screen). By supplying 1.0 you'll get the largest window that turtle can make:
from turtle import Screen, Turtle
screen = Screen()
screen.setup(width=1.0, height=1.0)
a = Turtle()
a.speed('fastest')
a.color('red', 'blue')
# a.begin_fill()
for _ in range(36):
a.forward(200)
a.left(170)
# a.end_fill()
screen.mainloop()
But this isn't necessarily the operating systems sense of Full Screen where the window overlays everything. It's just the largest window turtle can create given available screen real estate.

Python turtle drawing updated for turtle.tracer(0,0)

I am a newbie using python 3.2.3
When I ran the module in the python IDLE, the turtle drew a square without any update on the screen, so the window appeared blank, and after I input any key, the turtle and the square appeared due to the call of turtle.update().
However, when I double-clicked the .py file storing the below code in my document and executed it directly, the square always showed up before I input any key.
The interesting part is that the turtle was not shown but only the square was shown.
It seems that there was a turtle update only for the square after drawing even if I had already set turtle tracer to (0,0).
Is this considered a bug and how can I solve it? Thanks for the help.
import turtle
def drawSquare():
turtle.down();
turtle.begin_fill();
turtle.goto(10, 0);
turtle.goto(10, 10);
turtle.goto(0, 10);
turtle.goto(0, 0);
turtle.end_fill();
turtle.up();
def tUpdate():
turtle.update();
turtle.tracer(0,0);
drawSquare();
input("Not updated. Press any key.");
tUpdate();
print("Updated");
turtle.mainloop();
You've got a couple of things working against you: the poor documenation provided for tracer() and the fact that end_fill() and up() cause updates to occur. tracer() is not really meant to hide things from the user until you're ready to display them -- it's a speed optimization so that the user doesn't have to see every drawing step in a complicated image. You don't have full control over when updates will occur.
Here's a rework of your example that displays the behaviour you want at the cost of it no longer being a filled square. I've swapped your input() trigger for a mouse click on the window instead but your approach will work just as well here too:
from turtle import Turtle, Screen
def drawSquare(turtle):
turtle.goto(100, 0)
turtle.goto(100, 100)
turtle.goto(0, 100)
turtle.goto(0, 0)
screen = Screen()
screen.tracer(0, 0)
screen.onclick(lambda x, y: screen.update())
turtle = Turtle()
drawSquare(turtle)
screen.mainloop()
I also made which are turtle methods, and which are screen methods, more explicit. The beginning programmer friendly design of the turtle library tends to blur these in the interest of ease of use.

How to make a turtle object look at where the mouse has clicked

I want to write a turtle program where the turtle goes to wherever you click. So far I have this:
from turtle import *
screen = Screen()
turtle = Turtle()
screen.onscreenclick(turtle.goto)
But the problem is the turtle object just stays facing in the same direction. I want to somehow make it look towards where it's going. How can I achieve this?
This will do what you describe:
import turtle
screen = turtle.Screen()
turtle = turtle.Turtle()
def turtle_headto(x, y):
turtle.left(turtle.towards(x, y) - turtle.heading())
turtle.goto(x, y)
screen.onscreenclick(turtle_headto)
screen.mainloop()
But the motion of the arrow/turtle isn't always optimal, i.e. sometimes it spins the long way 'round, but that's something for you to optimize (e.g. when to call left() and when to call right())

Python - Move Two Turtle Objects At Once

I would like to create a program where one turtle object moves to where a user clicks their mouse, and a different turtle object moves at the same time. I have the first part, but I can't seem to get the rest to work.
Any help would be appreciated.
This is my code. (Credit for the first part of this goes to #Cygwinnian)
from turtle import *
turtle = Turtle()
screen = Screen()
screen.onscreenclick(turtle.goto)
turtle.getscreen()._root.mainloop()
turtle2 = Turtle()
while True:
turtle2.back(100)
turtle2.forward(200)
turtle2.back(100)
I am by no means an expert at Python's turtle module, but here's some code that I think does what you want. The second turtle will be moving back and forth any time the first turtle is not:
from turtle import *
screen = Screen() # create the screen
turtle = Turtle() # create the first turtle
screen.onscreenclick(turtle.goto) # set up the callback for moving the first turtle
turtle2 = Turtle() # create the second turtle
def move_second(): # the function to move the second turtle
turtle2.back(100)
turtle2.forward(200)
turtle2.back(100)
screen.ontimer(move_second) # which sets itself up to be called again
screen.ontimer(move_second) # set up the initial call to the callback
screen.mainloop() # start everything running
This code creates a function that moves the second turtle repeatedly back and forth from its starting position. It uses the ontimer method of the screen to schedule itself over and over. A slightly more clever version might check a variable to see if it is supposed to quit, but I didn't bother.
This does make both turtles move, but they don't actually move at the same time. Only one can be moving at any given moment. I'm not sure if there is any way of fixing that, other than perhaps splitting up the moves into smaller pieces (e.g. have the turtles alternate moving one pixel at a time). If you want fancier graphics you probably need to move on from the turtle module!

Categories

Resources