Detecting collision in Python turtle game

I am trying to make a Python game where the red turtle chases the blue turtle. When the red turtle catches the blue turtle, I want it to say 'COLLISION' on the screen but it is not working. When it collides, nothing happens and it gives me an error 'Turtle' object is not callable'.

from turtle import Turtle, Screen

playGround = Screen()

playGround.screensize(250, 250)
playGround.title("Turtle Keys")

run = Turtle("turtle")
run.speed("fastest")
run.color("blue")
run.penup()
run.setposition(250, 250)

follow = Turtle("turtle")
follow.speed("fastest")
follow.color("red")
follow.penup()
follow.setposition(-250, -250)

def k1():
    run.forward(45)

def k2():
    run.left(45)

def k3():
    run.right(45)

def k4():
    run.backward(45)

def quitThis():
    playGround.bye()

def follow_runner():
    follow.setheading(follow.towards(run))
    follow.forward(8)
    playGround.ontimer(follow_runner, 10)

playGround.onkey(k1, "Up")  # the up arrow key
playGround.onkey(k2, "Left")  # the left arrow key
playGround.onkey(k3, "Right")  # you get it!
playGround.onkey(k4, "Down")

playGround.listen()

follow_runner()

def is_collided_with(self, run):
    return self.rect.colliderect(run.rect)

runner = run(10, 10, 'my_run')
follower = follow(20, 10)
if follow.is_collided_with(run):
    print 'collision!'

 playGround.mainloop()

Solution 1:

This code seems to be more wishful thinking than actual programming:

def is_collided_with(self, run):
    return self.rect.colliderect(run.rect)

runner = run(10, 10, 'my_run')
follower = follow(20, 10)
if follow.is_collided_with(run):
    print 'collision!'

Turtles don't have a .rect() method. You can't simply add a is_collided_with() method to an existing class with this def statement. There are no run() and follow() functions. This collision test would only be executed once when you need it after every motion. Let's try to salvage what we can and make this work:

from turtle import Turtle, Screen

playGround = Screen()

playGround.screensize(250, 250)
playGround.title("Turtle Keys")

run = Turtle("turtle")
run.color("blue")
run.penup()
run.setposition(250, 250)

follow = Turtle("turtle")
follow.color("red")
follow.penup()
follow.setposition(-250, -250)

def k1():
    run.forward(45)

def k2():
    run.left(45)

def k3():
    run.right(45)

def k4():
    run.backward(45)

def quitThis():
    playGround.bye()

def is_collided_with(a, b):
    return abs(a.xcor() - b.xcor()) < 10 and abs(a.ycor() - b.ycor()) < 10

def follow_runner():
    follow.setheading(follow.towards(run))
    follow.forward(min(follow.distance(run), 8))

    if is_collided_with(follow, run):
        print('Collision!')
        quitThis()
    else:
        playGround.ontimer(follow_runner, 10)

playGround.onkey(k1, "Up")  # the up arrow key
playGround.onkey(k2, "Left")  # the left arrow key
playGround.onkey(k3, "Right")  # you get it!
playGround.onkey(k4, "Down")

playGround.listen()

follow_runner()

playGround.mainloop()

I use 10 as a collision radius based on the size of a turtle cursor, you can adjust as you see fit. This code simply ends the game, with a message, when a collision occurs, you might want to do something more sophisticated. You could consider making the collision logic its own function to use after each keystroke in case the runner accidentally rams the follower!

Solution 2:

We have a function for distance in Turtle, so let's say turtle1 is at x1, y1, and turtle2 is at x2, y2, then the distance will be calculated as the mathematical xy distance between those two points.

Now, let's say that turtle1 has a "radius" of r1, and turtle2 a radius of r2, we could check for a collision by chencking if the distance is less than the sum of these two radii.

So I think it would suffice to check if (r1+r2)<=turtle1.distance(turtle2.pos())

These radii could be set as this: turtle1.r=10, turtle2.r=5, or as global variables, r1=10, r2=5. Remember the global keyword in the def's if the last option is applicable.

For checking collisions with a given turtle, turtle1, and a list of turtles, say turtles=[jim,ben,kate,jane], and all turtles have a field for radius, r, You could iterate over this list, to check if turtle1 collided with any of them:

collsion=False
for turtle in turtles:
    if (turtle.r+turtle1.r)<=turtle1.distance(turtle.pos()):
        collision=True
        # turtle.reset() # removes the turtle
        # points+=1, or whatever

Now to make a function of this last one:

def group_collide(t1,group):
    global points
    turtle1=t1
    collide=False
    for turtle in group:
        if (turtle.r+turtle1.r)<=turtle1.distance(turtle(pos)):
            collide=True
            turtle.reset()
            points+=1
   # if needed:
   return collide

This will detect if turtle1 collided with any in the group, remove the turtle that turtle1 collided with, and add 1 to global points, and then, if needed, return True if collision occured, False otherwise.

This way the follower could try to overtake a group of turtles. Hope this can help somewhat.