Search code examples
pythoncollision-detectionturtle-graphicspython-turtle

How to detect collision between two objects in turtle python?


So I am making a clone for chrome's dino game in python turtle . I have done the randomisation for the cactus (which is very hackish , and yes if something is better than my aaproach , please help !)and the jumping is working.But as the heading says , I am unable to detect collisions properly. I have tried this much :

import turtle
import time
import random
print("dino game in turtle")

wn = turtle.Screen()
wn.bgcolor("white")
wn.setup(width=650, height=400)
wn.tracer(0)
delay = 0.1
#scoring system
score = 0
w = 1
h = 1
#dino
dino = turtle.Turtle()
dino.shape("square")
dino.shapesize(w, h)
dino.color("black")
dino.penup()
dino.goto(-200, -50)

#ground
g = turtle.Turtle()
g.penup()
g.goto(0, -60)
g.pendown()
g.lt(180)
g.fd(500)
g.rt(180)
g.fd(1000)
g.hideturtle()

#cactus
#y = random.randint(2, 4)
cactus = turtle.Turtle()
cactus.penup()
cactus.shape("square")
cactus.color("green")
cactus.shapesize(3, 0.5)
cactus.goto(-50, -30)

cactus2 = turtle.Turtle()
cactus2.penup()
cactus2.shape("square")
cactus2.color("green")
cactus2.shapesize(3, 0.5)
cactus2.goto(600, -30)

cactus3 = turtle.Turtle()
cactus3.penup()
cactus3.shape("square")
cactus3.color("green")
cactus3.shapesize(3, 0.5)
cactus3.goto(600, -30)

#score_pen
pen = turtle.Turtle()
pen.speed(0)
pen.shape("square")
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("Score: 0  High Score: 0", align="center", font=("Courier", 24, "normal"))





max_height = 150



def steady():
    y = dino.ycor() 
    if y == -50:
        return True
        
    else:
        return False
def jump():
    y = dino.ycor()
    if y != -50:
        return True
    else:
        return False
def jumping():
    y = dino.ycor()
    y += 200
    dino.sety(y)

def cactus_move():
    x = cactus.xcor()
    x -= 20
    cactus.setx(x)

def cactus_move2():
    x = cactus2.xcor()
    x -= 20
    cactus2.setx(x)

def cactus_move3():
    x = cactus3.xcor()
    x -= 20
    cactus3.setx(x)
x = dino.xcor()
y = dino.ycor()

def check_rect_collision(dino, x, y, w, h): 
    
    if p.x >= x and p.x <= x+w and p.y >= y and p.y <= y+h:
        # collision between p and rectangle
        return True
    return False







wn.listen()
wn.onkeypress(jumping, "space")

while True:
    score += 1
    check_rect_collision()
    #print(score)
    #pen.clear()
    #pen.clear()
    #pen.write("Score: {} ".format(score), align="center", font=("Courier", 24, "normal")) 
    x = random.randint(200, 300)
    xm = random.randint(300, 500)
    xms = random.randint(500, 550)
    
    cactus_move()
    cactus_move2()
    cactus_move3()
    y = dino.ycor()

    if steady() == True and dino.distance(cactus) < 25:
        print("Hello")
        break
    if steady() == True and dino.distance(cactus2) < 25:
        print("Hello")
        break
    if steady() == True and dino.distance(cactus3) < 25:
        print("Hello")
        break
    if jump() == True and dino.ycor() <= cactus.ycor():
        print("Ycor")
        break 
    if jump() == True and dino.ycor() <= cactus2.ycor():
        print("Ycor")
        break 
    if jump() == True and dino.ycor() <= cactus3.ycor():
        print("Ycor")
        break 

    if steady() == False:
        y -= 25
        dino.sety(y)
        
    if y >= max_height:
        y -= 200
        dino.sety(y) 

    if cactus.xcor() < -400:
        cactus.goto(x, -30)

    if cactus2.xcor() < -400:
        cactus2.goto(xm, -30)

    if cactus3.xcor() < -400:
        cactus3.goto(xms, -30)

    
    
        

    time.sleep(delay)
    wn.update()
wn.mainloop()

Solution

  • Normally, I'd say use the turtle.distance() function. But since your two turtles are different shapes, you need a custom collision function that takes into account the shape of both. I've reworked your code below incorporating such as well as fixing it to use turtle timer events instead of while True and sleep() and other changes:

    from turtle import Screen, Turtle
    from random import randint
    
    WIDTH, HEIGHT = 650, 400
    MAX_HEIGHT = 180
    BASELINE = -60
    
    NUMBER_CACTI = 3
    
    FONT = ('Courier', 24, 'normal')
    
    CURSOR_SIZE = 20
    CACTUS_WIDTH, CACTUS_HEIGHT = 10, 60
    
    def steady():
        return dino.ycor() == BASELINE + CURSOR_SIZE/2
    
    def jump():
        y = dino.ycor()
    
        if steady():
            dino.sety(y + 7 * CURSOR_SIZE)
        elif y < MAX_HEIGHT:
            dino.sety(y + 2 * CURSOR_SIZE)
    
    def cactus_move(cactus):
        cactus.setx(cactus.xcor() - CACTUS_WIDTH)
    
    def check_rect_collision(a, b):
        return abs(a.xcor() - b.xcor()) < CURSOR_SIZE/2 + CACTUS_WIDTH/2 and abs(a.ycor() - b.ycor()) < CURSOR_SIZE/2 + CACTUS_HEIGHT/2
    
    def place_cactus(cactus):
        cactus.setx(randint(WIDTH//2, WIDTH))
    
        while True:
            for other in cacti:
                if other is cactus:
                    continue
    
                if other.distance(cactus) < 5 * CACTUS_WIDTH:
                    cactus.setx(randint(0, WIDTH//2))
                    break  # for
            else:  # no break
                break  # while
    
    # scoring system
    score = 0
    
    def run():
        global score
    
        score += 1
    
        pen.clear()
        pen.write("Score: {} ".format(score), align='center', font=FONT)
    
        for cactus in cacti:
            cactus_move(cactus)
    
            if check_rect_collision(dino, cactus):
                screen.onkeypress(None, 'space')  # Game Over
                screen.tracer(True)
                return
    
            if cactus.xcor() < -WIDTH/2:
                place_cactus(cactus)
    
        if not steady():
            dino.sety(dino.ycor() - CURSOR_SIZE)
    
        screen.update()
        screen.ontimer(run, 50)  # repeat in 50 milliseconds
    
    screen = Screen()
    screen.title("Dino game in turtle")
    screen.bgcolor('white')
    screen.setup(width=WIDTH, height=HEIGHT)
    screen.tracer(False)
    
    # ground
    ground = Turtle()
    ground.hideturtle()
    
    ground.penup()
    ground.sety(BASELINE)
    ground.pendown()
    
    ground.forward(WIDTH/2)
    ground.backward(WIDTH)
    
    # dino
    
    dino = Turtle()
    dino.shape('square')
    dino.penup()
    dino.goto(-WIDTH/3, BASELINE + CURSOR_SIZE/2)
    
    # cacti
    
    cacti = []
    
    for _ in range(NUMBER_CACTI):
    
        cactus = Turtle()
        cactus.shape('square')
        cactus.shapesize(CACTUS_HEIGHT / CURSOR_SIZE, CACTUS_WIDTH / CURSOR_SIZE)
        cactus.color('green')
    
        cactus.penup()
        cactus.sety(BASELINE + CACTUS_HEIGHT/2)
        place_cactus(cactus)
    
        cacti.append(cactus)
    
    # score pen
    pen = Turtle()
    pen.hideturtle()
    pen.penup()
    pen.sety(175)
    
    pen.write("Score: 0  High Score: 0", align='center', font=FONT)
    
    screen.onkeypress(jump, 'space')
    screen.listen()
    
    run()
    
    screen.mainloop()
    

    I believe it is bascially playable now but you might want to tweak some of the constants to taste.