-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
282 lines (240 loc) · 10.9 KB
/
main.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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
import pygame
import random
from enum import Enum
from collections import namedtuple
pygame.init()
class Direction(Enum):
RIGHT = 1
LEFT = 2
UP = 3
DOWN = 4
Point = namedtuple('Point', 'x, y')
BLOCK_SIZE = 20
font = pygame.font.SysFont('arial', 25)
PLAY_TIME = 30
# rgb colors
WHITE = (255,255,255)
RED = (200,0,0)
BLUE = (0,0,255)
BLUE1 = (0,100,255)
BLACK = (0,0,0)
class SnakeGame:
def __init__(self, w=640, h=480):
self.w = w
self.h = h
# Init Display
self.display = pygame.display.set_mode((self.w, self.h))
pygame.display.set_caption('Snake')
# Init second display
self.second_display = pygame.Surface((self.w, self.h)) # the size of your rect
self.second_display.set_alpha(20) # alpha level
self.second_display.fill((0, 0, 0)) # this fills the entire surface
self.clock = pygame.time.Clock()
# Init game state
self.direction = Direction.RIGHT
self.head = Point(self.w/2, self.h/2)
self.snake = [self.head,
Point(self.head.x-BLOCK_SIZE, self.head.y),
Point(self.head.x-(2*BLOCK_SIZE), self.head.y)]
self.score = 0
self.level = 1
self.food = None
self._place_food()
self.start_time = pygame.time.get_ticks() # reset the start time
def _init_time(self):
# Calculate how much time is left by subtracting the current time
# from the start time, and then this value from the maximum allowed time (30 seconds).
# As these times are stored in milliseconds, we then
# divide by 1000 to convert to seconds, and convert the result to an integer
# value so that only whole seconds are shown.
self.time_left = pygame.time.get_ticks() - self.start_time # find out how much time has passed since the start of the game
self.time_left = self.time_left / 1000 # Convert this time from milliseconds to seconds
self.time_left = PLAY_TIME - self.time_left # Find out how much time is remaining by subtracting total time from time thats passed
self.time_left = int(self.time_left) # Convert this value to an integer
self.draw_timer(0, 25, self.time_left) # Once we have calculated how much time is left, draw the timer
def _place_food(self):
x = random.randint(0, (self.w-BLOCK_SIZE )//BLOCK_SIZE)*BLOCK_SIZE
y = random.randint(0, (self.h - BLOCK_SIZE) // BLOCK_SIZE) * BLOCK_SIZE
self.food = Point(x, y)
if self.food in self.snake:
self._place_food()
"""def _place_big_food(self):
x = random.randint(0, (self.w - BLOCK_SIZE) // BLOCK_SIZE) * BLOCK_SIZE
y = random.randint(0, (self.h - BLOCK_SIZE) // BLOCK_SIZE) * BLOCK_SIZE
self.food = Point(x, y)
if self.food in self.snake:
self._place_big_food()"""
def play_step(self):
# Collect user input
game_over = False
self._init_time()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a and self.direction != Direction.RIGHT:
self.direction = Direction.LEFT
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d and self.direction != Direction.LEFT:
self.direction = Direction.RIGHT
elif event.key == pygame.K_UP or event.key == pygame.K_w and self.direction != Direction.DOWN:
self.direction = Direction.UP
elif event.key == pygame.K_DOWN or event.key == pygame.K_s and self.direction != Direction.UP:
self.direction = Direction.DOWN
# 2. move
self._move(self.direction)
self.snake.insert(0, self.head) # update the head
# 3. check if game over
if self._is_collision("modern"):
game_over = True
#self.draw_game_over("g", "g")
return game_over, self.score
# 4. replace new food or just move
if self.head == self.food:
self.score += 1
self.start_time += 2000
self._place_food()
else:
self.snake.pop()
# 5. update ui
self._update_ui()
# 6. change Level and speed
if self.score <= 5:
self.level = 1
self.clock.tick(10)
elif self.score > 5:
self.level = 2
self.clock.tick(12)
elif self.score > 13:
self.level = 3
self.clock.tick(15)
elif self.score > 20:
self.level = 4
self.clock.tick(18)
elif self.score > 40:
self.level = 5
self.clock.tick(23)
elif self.score > 80:
self.level = 6
self.clock.tick(30)
elif self.score > 150:
self.level = 2
self.clock.tick(36)
# 7. return game over and score if time is over
if self.time_left <= 0:
# If the time is up, set the boolean game_ended to True
# so we can display the correct game over screen
game_over = True
self.draw_game_over("g", "g")
return game_over, self.score
def _is_collision(self, mode):
mode = mode
# hits boundary
if mode == 'classic':
if self.head.x > self.w - BLOCK_SIZE or self.head.x < 0 or self.head.y > self.h - BLOCK_SIZE or self.head.y < 0:
return True
elif mode == 'modern':
# hits right boundary
if self.head.x >= self.w and self.direction == Direction.RIGHT:
self.head = Point(self.head.x-self.w-BLOCK_SIZE, self.head.y)
# hits left boundary
if self.head.x < 0 and self.direction == Direction.LEFT:
self.head = Point(self.head.x+self.w+BLOCK_SIZE, self.head.y)
# hits top boundary
if self.head.y < 0 and self.direction == Direction.UP:
self.head = Point(self.head.x, self.head.y+self.h+BLOCK_SIZE)
# hits bottom boundary
if self.head.y > self.h - BLOCK_SIZE and self.direction == Direction.DOWN:
self.head = Point(self.head.x, self.head.y-self.h-BLOCK_SIZE)
# hits itself
if self.head in self.snake[1:]:
return True
return False
def _update_ui(self):
self.display.fill(BLACK)
self.draw_timer(0, 25, self.time_left)
for pt in self.snake:
pygame.draw.rect(self.display, BLUE1, pygame.Rect(pt.x, pt.y, BLOCK_SIZE, BLOCK_SIZE))
pygame.draw.rect(self.display, BLUE, pygame.Rect(pt.x+4, pt.y+4, 12, 12))
#### Draw borders / another way: https://stackoverflow.com/questions/61765229/snake-game-in-pygame-borders
line_number_w = self.w / BLOCK_SIZE
line_number_h = self.h / BLOCK_SIZE
w_lines = {
'0': [(0, 0), (0, 480)],
'1': [(5, 0), (20, 480)],
}
h_lines = {
'0': [(0, 0), (0, 480)],
'1': [(5, 0), (20, 480)],
}
for i in range(int(line_number_w)):
w_lines[f'{i}'] = [(i*20, 20*i), (0, 480)]
for i in range(int(line_number_h)):
h_lines[f'{i}'] = [(640, 0), (i*20, i*20)]
for i in range(int(line_number_w)):
for element in w_lines[str(i)]:
value_1 = str(element)
a, b = value_1.split(' ')
a, b = zip(*w_lines[str(i)])
pygame.draw.line(self.second_display, WHITE, a, b, width=1)
for i in range(int(line_number_h)):
for element in h_lines[str(i)]:
value_1 = str(element)
a, b = value_1.split(' ')
a, b = zip(*h_lines[str(i)])
pygame.draw.line(self.second_display, WHITE, a, b, width=1)
####
pygame.draw.rect(self.display, RED, pygame.Rect(self.food.x, self.food.y, BLOCK_SIZE, BLOCK_SIZE))
# Draw Score and Speed text
text_score = font.render('Score: ' + str(self.score), True, WHITE)
text_lvl = font.render('Level: ' + str(self.level), True, WHITE)
self.display.blit(text_score, [0, 0])
self.display.blit(text_lvl, [90, 0])
self.display.blit(self.second_display, (0, 0)) # (0,0) are the top-left coordinates
pygame.display.flip()
def _move(self, direction):
x = self.head.x
y = self.head.y
if direction == Direction.RIGHT:
x += BLOCK_SIZE
elif direction == Direction.LEFT:
x -= BLOCK_SIZE
elif direction == Direction.DOWN:
y += BLOCK_SIZE
elif direction == Direction.UP:
y -= BLOCK_SIZE
self.head = Point(x, y)
def draw_timer(self, x, y, time_left):
font2 = pygame.font.Font(None, 36) # Choose the font for the text
text = font2.render("Time Left = " + str(time_left), 1, WHITE) # Create the text
self.display.blit(text, (x, y)) # Draw the text on the screen
def draw_game_over(self, message_1, message_2):
pygame.draw.rect(self.display, WHITE, (150, 200, 400, 100), 0) # Draw a white box for the text to sit in
#font = pygame.font.Font(None, 36) # Choose the font for the text
text = font.render(message_1, 1, BLACK) # Create the text for "GAME OVER"
self.display.blit(text, (170, 220)) # Draw the text on the screen
text = font.render(message_2, 1, BLACK) # Create the text for "You hit the other player"
self.display.blit(text, (170, 260)) # Draw the text on the screen
#font = pygame.font.Font(None, 28) # Make the font a bit smaller for this bit
text = font.render("Press P to play again. Press E to exit the game.", 1,
WHITE) # Create text for instructions on what to do now
self.display.blit(text, (100, 350)) # Draw the text on the screen
if __name__ =='__main__':
game = SnakeGame()
# Game Loop
while True:
game_over, score = game.play_step()
if game_over == True:
break
print('Final score: ' + str(score))
#break if game over
pygame.quit()
"""## TO do list:
1. Dodac BigFood
2. Zrobic Menu glowne i opcje wyboru trundosci(czas, predkosc)
3. Zrobic menu game over
4. Dodac opcje multiplayer czyli dwoch graczy nie moze sie ze soba zderzyc, albo
gracz ma mini plansze drugiego gracza w mini mapie i widzi jego punkty, ten gracz ktory
zdobedzie wiecej wygrywa, a roznica w punktach daje wiecej kasy wirtualnej za ktora
mozna kupic ulepszenia, skorki.
5. DOdac AI"""