Reputation: 31
I created 2 turtle's that keep moving until one of them hits a wall which causes them to stop completely.
My question is how could I make it so when it hits a wall/the other turtle, it turns instead of stopping and continues? I have a rough idea of how to do it with 1 turtle however whenever I tried it with 2, it just isn't working.
import random
import turtle
def moveRandom(wn, t):
coin = random.randrange(0,2)
if coin == 0:
t.left(90)
else:
t.right(90)
t.forward(50)
def areColliding(t1, t2):
if t1.distance(t2) < 2:
return True
else:
return False
def isInScreen(w, t):
leftBound = - w.window_width() / 2
rightBound = w.window_width() / 2
topBound = w.window_height() / 2
bottomBound = -w.window_height() / 2
turtleX = t.xcor()
turtleY = t.ycor()
stillIn = True
if turtleX > rightBound or turtleX < leftBound:
stillIn = False
if turtleY > topBound or turtleY < bottomBound:
stillIn = False
return stillIn
t1 = turtle.Turtle()
t2 = turtle.Turtle()
wn = turtle.Screen()
t1.shape('turtle')
t2.shape('circle')
leftBound = -wn.window_width() / 2
rightBound = wn.window_width() / 2
topBound = wn.window_height() / 2
bottomBound = -wn.window_height() / 2
t1.up()
t1.goto(random.randrange(leftBound, rightBound),
random.randrange(bottomBound, topBound))
t1.setheading(random.randrange(0, 360))
t1.down()
t2.up()
t2.goto(random.randrange(leftBound, rightBound),
random.randrange(bottomBound, topBound))
t2.setheading(random.randrange(0, 360))
t2.down()
while isInScreen(wn, t1) and isInScreen(wn, t2):
moveRandom(wn, t1)
moveRandom(wn, t2)
wn.exitonclick()
Upvotes: 2
Views: 3051
Reputation: 6655
You actually need to reorganize your code, so as to not repeat yourself.
import random
import turtle
Let us build the properties of the world
wn = turtle.Screen()
leftBound = -wn.window_width() / 2
rightBound = wn.window_width() / 2
topBound = wn.window_height() / 2
bottomBound = -wn.window_height() / 2
And of its living creatures
t1 = turtle.Turtle()
t1.shape('turtle')
t2 = turtle.Turtle()
t2.shape('circle')
delta_move = 50
# Let us build a list so as to have all turtles in hands in one object
turtles = [
t1,
t2,
#t3,
#t4,
#...
]
for t in turtles:
t.speed(0) # To make turtles be faster (0 is the FASTEST SPEED)
t.setheading(random.randrange(0, 360))
# We do not need what follows anymore, since collisions
# will be managed thereafter
##t.goto(random.randrange(leftBound, rightBound),
## random.randrange(bottomBound, topBound))
Some physical constraints
def isCollidingOtherTurtle(t):
# Let us define the reciprocity between turtles
# using the just-defined list "turtles" above
other_turtles = [t_ for t_ in turtles if t_ is not t]
# This python function called any,
# checks whether there is at least one
# other turtle at a distance lower than 2.
# In this case, any(...) returns True
return any([t.distance(ot) < 2\
for ot in other_turtles])
def isInScreen(t):
# There is no need to redefine the bounds
# since they already have a global scope
# definition working in the local
# scope of this function
# [see global versus local variables]
## leftBound = - w.window_width() / 2
## rightBound = w.window_width() / 2
## topBound = w.window_height() / 2
## bottomBound = -w.window_height() / 2
turtleX = t.xcor()
turtleY = t.ycor()
stillIn = True
if turtleX > rightBound or turtleX < leftBound:
stillIn = False
if turtleY > topBound or turtleY < bottomBound:
stillIn = False
return stillIn
Define each generic turtle's brain
def getDirection():
#return random.random()*360. - 180 # returns a float between -180 and 180
return random.choice([-180,-90,0,90,180])
def moveRandom(t):
# A generic turtle moves forward
# if it is going to collide
# with no other turtle
if not isCollidingOtherTurtle(t):
if isInScreen(t):
t.left(getDirection())
t.forward(delta_move)
else:
t.backward(delta_move)
else:
t.backward(delta_move)
And let us define how to animate this world, and animate it
def anim(delta_time=60):
wn.tracer(0, 0)
for t in turtles:
moveRandom(t)
wn.update()
wn.ontimer(anim, delta_time) # delta_time is in milliseconds
anim()
turtle.mainloop()
Upvotes: 1
Reputation: 41872
Here's a rework of your code that I believe does as you desire. Most of my other changes are simplifications of your code. One major change is I tossed the while()
loop that was moving the turtles and put them on their own timers instead:
import random
from turtle import Turtle, Screen
def moveRandom(wn, t):
coin = random.randrange(0, 2)
[t.left, t.right][coin](90)
t.forward(50)
if not isInScreen(t) or areColliding(t1, t2):
t.undo() # pretend it never happened
t.left(180) # turn around
t.forward(50) # go the other way
wn.ontimer(lambda: moveRandom(wn, t), 100)
def areColliding(t1, t2):
return t1.distance(t2) < 2
def isInScreen(t):
turtleX, turtleY = t.position()
return leftBound < turtleX < rightBound and bottomBound < turtleY < topBound
t1 = Turtle('turtle', visible=False)
t2 = Turtle('circle', visible=False)
wn = Screen()
leftBound, rightBound = -wn.window_width() // 2, wn.window_width() // 2
bottomBound, topBound = -wn.window_height() // 2, wn.window_height() // 2
t1.up()
t1.goto(random.randrange(leftBound, rightBound), random.randrange(bottomBound, topBound))
t1.setheading(random.randrange(0, 360))
t1.showturtle()
t1.down()
t2.up()
t2.goto(random.randrange(leftBound, rightBound), random.randrange(bottomBound, topBound))
t2.setheading(random.randrange(0, 360))
t2.showturtle()
t2.down()
moveRandom(wn, t1)
moveRandom(wn, t2)
wn.exitonclick()
To handle the collisions, I call isInScreen(t)
and areColliding(t1, t2)
in moveRandom(wn, t)
and simply undo the move if it causes a collision, turn around move the opposite direction.
Upvotes: 1