-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGame.py
More file actions
167 lines (119 loc) · 5.46 KB
/
Game.py
File metadata and controls
167 lines (119 loc) · 5.46 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import random
import pygame
import time
from Snake import Snake
import GUI
pygame.init()
width = 1080
height = 720
run = True
# Window
window = pygame.display.set_mode([width, height])
pygame.display.set_caption("Snake")
# The clock is needed for time keeping
clock = pygame.time.Clock()
# Get key input (QUIT, KEY DOWN, LEFT MOUSE CLICK, etc)
# Ideally the quit event and other window events will not be checked in the same place as
# player controls but because the alternative method for key checking is not as reliable
# I have chosen to keep this method and add one extra condition (player.lives > 0)
# Eventually all entities would be contained in a data structure which will be passed instead of player object.
def get_key_entered(player):
global run
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
elif (event.type == pygame.KEYDOWN) and (player.lives > 0):
player.change_move_direction(event.key)
# Generates a random position for a given object.
# @params:
# *app_width - width of the object to spawn.
# *app_height - height of the object to spawn.
# *game_view - dimensions and coordinates of the rectangle on which the game is rendered.
def gen_random_spawn_location(object_width, object_height, spawn_area_scale):
# The random X and Y are generated by taking into account the spawn area.
rand_x = random.randint(spawn_area_scale[0], spawn_area_scale[2] - object_height)
rand_y = random.randint(spawn_area_scale[1], spawn_area_scale[3] - object_width)
return rand_x, rand_y
def main():
start_timer = 0
invincibility_time = 2
view_width = 1000
view_height = 600
# Calculate game view rectangle starting position
start_x = (width - view_width) / 2
start_y = (height - view_height) / 2
spawn_area_scale = (start_x, start_y, view_width, view_height)
# COLOURS
lives_display_col = (0, 0, 0)
score = 0
live_taken = False
# Construct a snake
snake = Snake(1023, 350, 3, 3, 15, (0, 0, 0))
# Apple scale
app_width = 10
app_height = 10
# Randomise apple position
rand_x, rand_y = gen_random_spawn_location(app_width, app_height, spawn_area_scale)
# Game loop
while run:
curr_time = time.time()
# Draw background, needs to happen every frame
window.fill((255, 255, 255))
spawn_area = pygame.draw.rect(window, (98, 244, 66), spawn_area_scale)
# (Simply Visual) Spawn Area Border
pygame.draw.rect(window, (3, 132, 36), spawn_area_scale, 4)
# Draw apple
apple = pygame.draw.rect(window, (255, 0, 0), (rand_x, rand_y, app_width, app_height))
# Player controls and other events
get_key_entered(snake)
if snake.lives > 0:
if not live_taken:
snake.draw_snake(window)
snake.update_position()
# If the apple was eaten
if snake.eat(apple):
# Spawn a new apple
rand_x, rand_y = gen_random_spawn_location(app_width, app_height, spawn_area_scale)
# Update score
score += 5
print("Snake length: ", snake.segments.length)
snake_x = snake.segments.head.rect.x
snake_y = snake.segments.head.rect.y
# The top left and top right corners of the snake head.
# Those exact points create the exact boundary needed and at the same time save computation.
s_tl = (snake_x, snake_y)
s_tr = (snake_x+snake.segment_size, snake_y+snake.segment_size)
not_collide_top_left = not spawn_area.collidepoint(s_tl)
not_collide_top_right = not spawn_area.collidepoint(s_tr)
if not_collide_top_left and not_collide_top_right and not live_taken:
start_timer = curr_time
snake.lives -= 1
live_taken = True
# RESPAWN
temp_lives = snake.lives
del snake
snake = Snake(1023, 350, 3, 3, 15, (0, 0, 0))
snake.lives = temp_lives
# Set all segments in the snake to start at the head position
for counter in range(0, snake.segments.length):
snake.segments.get_at_pos(counter).rect.x = 1023
snake.segments.get_at_pos(counter).rect.y = 350
# Can loose a life again
if round(curr_time - start_timer, 0) == invincibility_time:
live_taken = False
# Strange snake scale behaviour of snake when snake respawn runs here. (To inspect that just in case.)
else: # GAME OVER
# pygame.display.update() # this update causes flicker of the rectangle and text below
pygame.draw.rect(window, (155, 50, 50), (start_x-2, start_y-2, view_width+4, view_height+4))
GUI.display_text(window, "GAME OVER! ", 100, (0, 0, 0), [310, 300])
# GUI
GUI.display_text(window, "Score: " + str(score), 50, (0, 0, 0), [40, 10])
GUI.display_text(window, "Lives: " + str(snake.lives), 50, (0, 0, 0), [910, 10])
# Limit frames to 60
clock.tick(60)
# Displays the buffered data
pygame.display.update()
if __name__ == "__main__":
main()