Reputation: 105
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()
Upvotes: 1
Views: 2942
Reputation: 41872
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.
Upvotes: 2
Reputation: 33
You could do the same as game engines, put shapes over the objects and apply algorithms for collision detection, there are some algorithms that very simple, for example sphere vs sphere, this is how it works.
Put a circle over the objects that you want detect colision, this can be done making a class CircleCollider for example and make it property of your turtle. This collider have an ID, radius and a position, the same as the turtle
Make another class to manage the colliders and collisions, saving the collisions in an array or a list
Every iteration (i suppose you have your game code in a loop), apply the sphere vs sphere algorithm to detect a colision. You have to do this between all the objects. (do not forget update the collider position as well)
Sphere vs sphere algorithm (between 2 spheres): just calculate the distance between the two colliders, it must be minor than the radius, you can do this with the formula d=sqrt((x1-x2)^2 + (y1-y2) ^2), if not, there is a collision.
I known this solution can be a little long, but it worth it, also you must consider if the circle is the perfect shape for your character, you can also use boxes and capsules, but the algorithms are a little more complex. Finally if you only have 2 types of objects (character and obstacles) instead using an id you can use tags (character or obstacle) instead a different ID for every object.
Upvotes: 0