pythonpython-3.xcollision-detectionturtle-graphicspython-turtle

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

  • 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!