I tried to make a snake game in python using the turtle module. Overall, the game is working fine but the condition to show a game over when snake hits its own body is not working.
Following is the function I made to check collision of both types (with boundary and with itself):
def check_collision(self):
#to check collision with boundary
if 298 > self.head.xcor() > -298 and 298 > self.head.ycor() > -298:
#to check collision with its body (s=list containing all parts of snake's body)
for i in range(self.c): #c = len(s) - 2
if self.head.distance(self.s[i]) > 28:
f = 1
else:
f = 0
else:
f = 0
#returning true or false to continue or terminate the game(false=terminate, true=continue)
if f == 0:
return False
else:
return True
This is working when the snake hits the boundary but not working when the snake hits its own body.
I'm expecting for the game to show game over when snake hits its own body, but the game continues.
This isn't exactly a complete, reproducible example, but you probably want something like:
class Snake:
collision_distance = 28
screen_size = 298
# ...
def in_bounds(self):
screen_size = self.screen_size
return (
-screen_size < self.head.xcor() < screen_size and
-screen_size < self.head.ycor() < screen_size
)
def overlapping_tail(self):
dist = self.collision_distance
return any(self.head.distance(x) < dist for x in self.s[:-2])
def alive(self):
return self.in_bounds() and not self.overlapping_tail()
# usage:
if not snake.alive():
end_game()
any()
is shorthand here for:
for x in self.s[:-2]:
if self.head.distance(x) < dist:
return True
return False
Notes/suggestions:
f = 0
once you detect a collision, then risk flipping it back to 1 once another segment doesn't collide. If you must keep the single-return pattern, use break
to exit the loop as soon as you detect a colliding segment.int
s as bool
s. This hasn't even been necessary in C for the past 30-odd years, so it's truly archaic and confusing programming style.#to check collision with boundary
, break it out into a function check_collision_with_boundary
and remove the comment.print()
to debug your code and observe the control flow and variables.self.c
. If it represents len(self.s) - 2
, make it len(self.s) - 2
everywhere because len()
is plenty fast and contains the most up-to-date information. With self.c
, you have to remember to update it, and more state means a more complex program, which means more bugs.self.s
and self.c
should use clearer variable names, like self.tail
and self.tail_count
or something like that. f
should be valid
(or removed complete in favor of immediate returns).if x: return True; else: return False
. Simply return x
! (or return bool(x)
if it's not a bool, and you want to return a bool based on its truthiness)142 > some_number > 42
, prefer 42 < some_number < 142
. Having the larger numbers first seems counter to how I usually see this written.