-
Notifications
You must be signed in to change notification settings - Fork 0
/
Snake.py
119 lines (95 loc) · 4.93 KB
/
Snake.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from SnakeSegment import SnakeSegment
import pygame
import math
from collision_checker import *
# Snake is a SnakeSegment itself and also contains other SnakeSegments
class Snake(SnakeSegment):
def __init__(self, x, y, speed, boundary_x, boundary_y):
super().__init__(x, y, speed, boundary_x, boundary_y, head = True)
self.head_size = 20
# contains the segments which make up the body
self.body = []
self.reward = 0
# the image of the head is stored here
# I need to scale the image to correct size
self.head = pygame.transform.scale(pygame.image.load("./assets/head.png"), (self.head_size, self.head_size))
def self_collision_check(self):
# THERE IS A BUG HERE PLS FIX THIS
bodies = self.body
seg_count = 0
for segment in bodies:
# we check for collision only if theres more than 2 head
if seg_count > 2:
if snake_collision(self, segment):
return True
seg_count += 1
# False is returend if and ONLY if we get out of the loop and have iterated over every single segment and found no collision
# this prevents the check from just checking one segment finding no collision and returning
return False
def get_body(self):
return self.body
def distance_from_food(self, food):
x_distance = self.distance_from_food_x(food)
y_distance = self.distance_from_food_y(food)
return math.sqrt(x_distance**2 + y_distance**2) - food.get_size()
def distance_from_food_x(self, food):
return self.coordinates[0] - food.get_coor()[0]
def distance_from_food_y(self, food):
return self.coordinates[1] - food.get_coor()[1]
def get_head_coor(self):
return self.coordinates
def get_tail_coor(self):
return self.body[-1].coordinates
def get_mid_coor(self):
midpoint = self.body / 2
midpoint = int(midpoint)
return self.body[midpoint].coordinates
def grow(self):
# NOTE the x and y value of the SnakeSegment doesn't matter atm as it gets updated when it gets drawn
self.body.append(SnakeSegment(0, 0, self.speed, self.boundary_x, self.boundary_y, False))
self.reward += 1
# MAIN GAME LOGIC TO UPDATE THE BODIES
# this function will be invoked and the head's previous x and y coordinates
# before it is about to be redrawn again in the current game loop will be passed in
def update_body(self, screen, prev_x, prev_y, previous_direction, go_through):
# each segment in the body will return its previous x and y coordinates before it gets updated
for segment in self.body:
segment.change_direction(previous_direction)
# each segment basically gets updated by the previous x and y coordinates of its previous segment (if we are dealing
# with the 0th index in the segment array then the 0th index will get the previous value of the head segment), the x and y coordinate
# is the previous segments x and y coordinates before it gets redrawn, kind of tricky to understand
# so when in the next frame all the segment will be at the position of their previous segment's position, this creates the snake
# body delay effect
prev_x, prev_y, previous_direction = segment.draw(screen, prev_x, prev_y, go_through)
# draws the segment
def draw(self, screen, go_through_boundary = False):
# by default boundary_check is always true, depending on the if we are checking if collision
# occurs in the boundary we assign this variable
boundary_collision = False
# previous x and y coordinates to be passed on to the segments
prev_x = self.coordinates[0]
prev_y = self.coordinates[1]
previous_direction = self.previous_direction
# in pygame the y coordinates start at the maximum value or in other words it is flipped
if self.current_direction == "up":
# up direction
self.coordinates[1] -= self.speed
elif self.current_direction == "down":
# down direction
self.coordinates[1] += self.speed
elif self.current_direction == "right":
# down direction
self.coordinates[0] += self.speed
elif self.current_direction == "left":
# down direction
self.coordinates[0] -= self.speed
# if go through_boundary is specified then the snake goes through the boundary
if go_through_boundary:
self.boundary_check_through()
else:
boundary_collision = self.boundary_collision()
screen.blit(self.head, (self.coordinates[0], self.coordinates[1]))
self.update_body(screen, prev_x, prev_y, previous_direction, go_through_boundary)
if self.self_collision_check() or boundary_collision:
return True
return False