|
1 | 1 | import pygame
|
2 | 2 | import random
|
3 |
| -from enum import Enum |
4 |
| -from collections import namedtuple |
| 3 | +from snake import Snake, Direction, Point |
| 4 | +from display import Display |
| 5 | +from constants import GameSettings |
5 | 6 |
|
6 |
| -pygame.init() |
7 |
| -font = pygame.font.Font(None, 25) |
8 |
| - |
9 |
| - |
10 |
| -class Direction(Enum): |
11 |
| - RIGHT = 1 |
12 |
| - LEFT = 2 |
13 |
| - UP = 3 |
14 |
| - DOWN = 4 |
15 |
| - |
16 |
| - |
17 |
| -Point = namedtuple("Point", "x, y") |
18 |
| - |
19 |
| -# rgb colors |
20 |
| -WHITE = (255, 255, 255) |
21 |
| -RED = (200, 0, 0) |
22 |
| -BLUE1 = (0, 0, 255) |
23 |
| -BLUE2 = (0, 100, 255) |
24 |
| -BLACK = (0, 0, 0) |
25 |
| - |
26 |
| -BLOCK_SIZE = 20 |
27 |
| -SPEED = 5 |
28 |
| - |
29 |
| - |
30 |
| -class SnakeGame: |
31 |
| - def __init__(self, w=640, h=480): |
32 |
| - self.w = w |
33 |
| - self.h = h |
34 |
| - # init display |
35 |
| - self.display = pygame.display.set_mode((self.w, self.h)) |
36 |
| - pygame.display.set_caption("Snake") |
37 |
| - self.clock = pygame.time.Clock() |
38 |
| - |
39 |
| - # init game state |
40 |
| - self.direction = Direction.RIGHT |
41 |
| - |
42 |
| - self.head = Point(self.w / 2, self.h / 2) |
43 |
| - self.snake = [ |
44 |
| - self.head, |
45 |
| - Point(self.head.x - BLOCK_SIZE, self.head.y), |
46 |
| - Point(self.head.x - (2 * BLOCK_SIZE), self.head.y), |
47 |
| - ] |
48 | 7 |
|
| 8 | +class Game: |
| 9 | + def __init__(self): |
| 10 | + self.display = Display() |
| 11 | + self.snake = Snake() |
49 | 12 | self.score = 0
|
50 | 13 | self.food = None
|
51 |
| - self._place_food() |
| 14 | + self.place_food() |
| 15 | + |
| 16 | + def game_loop(self): |
| 17 | + while True: |
| 18 | + self.play_step() |
| 19 | + game_over, score = self.play_step() |
| 20 | + if game_over: |
| 21 | + break |
| 22 | + print("Final Score:", self.score) |
| 23 | + pygame.quit() |
| 24 | + |
| 25 | + def is_collision(self): |
| 26 | + # Snake hits boundary |
| 27 | + if ( |
| 28 | + self.snake.head.x > self.display.width - self.snake.block_size |
| 29 | + or self.snake.head.x < 0 |
| 30 | + or self.snake.head.y > self.display.height - self.snake.block_size |
| 31 | + or self.snake.head.y < 0 |
| 32 | + ): |
| 33 | + return True |
| 34 | + # Snake hits itself |
| 35 | + if self.snake.self_collision(): |
| 36 | + return True |
| 37 | + return False |
52 | 38 |
|
53 |
| - def _place_food(self): |
54 |
| - x = random.randint(0, (self.w - BLOCK_SIZE) // BLOCK_SIZE) * BLOCK_SIZE |
55 |
| - y = random.randint(0, (self.h - BLOCK_SIZE) // BLOCK_SIZE) * BLOCK_SIZE |
56 |
| - self.food = Point(x, y) |
57 |
| - if self.food in self.snake: |
58 |
| - self._place_food() |
| 39 | + def game_over(self): |
| 40 | + return self.is_collision() |
59 | 41 |
|
60 |
| - def play_step(self): |
61 |
| - # 1. collect user input |
| 42 | + def get_user_input(self): |
62 | 43 | for event in pygame.event.get():
|
63 | 44 | if event.type == pygame.QUIT:
|
64 | 45 | pygame.quit()
|
65 | 46 | quit()
|
66 | 47 | if event.type == pygame.KEYDOWN:
|
67 | 48 | if event.key == pygame.K_LEFT:
|
68 |
| - self.direction = Direction.LEFT |
| 49 | + self.snake.direction = Direction.LEFT |
69 | 50 | elif event.key == pygame.K_RIGHT:
|
70 |
| - self.direction = Direction.RIGHT |
| 51 | + self.snake.direction = Direction.RIGHT |
71 | 52 | elif event.key == pygame.K_UP:
|
72 |
| - self.direction = Direction.UP |
| 53 | + self.snake.direction = Direction.UP |
73 | 54 | elif event.key == pygame.K_DOWN:
|
74 |
| - self.direction = Direction.DOWN |
75 |
| - |
76 |
| - # 2. move |
77 |
| - self._move(self.direction) # update the head |
78 |
| - self.snake.insert(0, self.head) |
| 55 | + self.snake.direction = Direction.DOWN |
79 | 56 |
|
80 |
| - # 3. check if game over |
81 |
| - game_over = False |
82 |
| - if self._is_collision(): |
83 |
| - game_over = True |
84 |
| - return game_over, self.score |
85 |
| - |
86 |
| - # 4. place new food or just move |
87 |
| - if self.head == self.food: |
| 57 | + def play_step(self): |
| 58 | + self.get_user_input() |
| 59 | + self.snake.move(self.snake.direction) |
| 60 | + if self.snake.head == self.food: |
88 | 61 | self.score += 1
|
89 |
| - self._place_food() |
| 62 | + self.place_food() |
90 | 63 | else:
|
91 |
| - self.snake.pop() |
92 |
| - |
93 |
| - # 5. update ui and clock |
94 |
| - self._update_ui() |
95 |
| - self.clock.tick(SPEED) |
96 |
| - # 6. return game over and score |
| 64 | + self.snake.blocks.pop() |
| 65 | + # Update UI and Clock |
| 66 | + self.display.update_ui(self.snake, self.food, self.score) |
| 67 | + self.display.clock_tick(GameSettings.SPEED) |
| 68 | + game_over = self.is_collision() |
97 | 69 | return game_over, self.score
|
98 | 70 |
|
99 |
| - def _is_collision(self): |
100 |
| - # hits boundary |
101 |
| - if ( |
102 |
| - self.head.x > self.w - BLOCK_SIZE |
103 |
| - or self.head.x < 0 |
104 |
| - or self.head.y > self.h - BLOCK_SIZE |
105 |
| - or self.head.y < 0 |
106 |
| - ): |
107 |
| - return True |
108 |
| - # hits itself |
109 |
| - if self.head in self.snake[1:]: |
110 |
| - return True |
111 |
| - |
112 |
| - return False |
113 |
| - |
114 |
| - def _update_ui(self): |
115 |
| - self.display.fill(BLACK) |
116 |
| - |
117 |
| - for pt in self.snake: |
118 |
| - pygame.draw.rect( |
119 |
| - self.display, BLUE1, pygame.Rect(pt.x, pt.y, BLOCK_SIZE, BLOCK_SIZE) |
120 |
| - ) |
121 |
| - pygame.draw.rect( |
122 |
| - self.display, BLUE2, pygame.Rect(pt.x + 4, pt.y + 4, 12, 12) |
123 |
| - ) |
124 |
| - |
125 |
| - pygame.draw.rect( |
126 |
| - self.display, |
127 |
| - RED, |
128 |
| - pygame.Rect(self.food.x, self.food.y, BLOCK_SIZE, BLOCK_SIZE), |
129 |
| - ) |
130 |
| - |
131 |
| - text = font.render("Score: " + str(self.score), True, WHITE) |
132 |
| - self.display.blit(text, [0, 0]) |
133 |
| - pygame.display.flip() |
134 |
| - |
135 |
| - def _move(self, direction): |
136 |
| - x = self.head.x |
137 |
| - y = self.head.y |
138 |
| - if direction == Direction.RIGHT: |
139 |
| - x += BLOCK_SIZE |
140 |
| - elif direction == Direction.LEFT: |
141 |
| - x -= BLOCK_SIZE |
142 |
| - elif direction == Direction.DOWN: |
143 |
| - y += BLOCK_SIZE |
144 |
| - elif direction == Direction.UP: |
145 |
| - y -= BLOCK_SIZE |
146 |
| - |
147 |
| - self.head = Point(x, y) |
148 |
| - |
149 |
| - |
150 |
| -if __name__ == "__main__": |
151 |
| - game = SnakeGame() |
152 |
| - |
153 |
| - # game loop |
154 |
| - while True: |
155 |
| - game_over, score = game.play_step() |
156 |
| - |
157 |
| - if game_over == True: |
158 |
| - break |
159 |
| - |
160 |
| - print("Final Score", score) |
| 71 | + def place_food(self): |
| 72 | + x = random.randint(0, ( |
| 73 | + self.display.width - GameSettings.BLOCK_SIZE) // GameSettings.BLOCK_SIZE) * GameSettings.BLOCK_SIZE |
| 74 | + y = random.randint(0, ( |
| 75 | + self.display.height - GameSettings.BLOCK_SIZE) // GameSettings.BLOCK_SIZE) * GameSettings.BLOCK_SIZE |
| 76 | + self.food = Point(x, y) |
| 77 | + if self.food in self.snake.blocks: |
| 78 | + self.place_food() |
161 | 79 |
|
162 |
| - pygame.quit() |
| 80 | + def get_score(self): |
| 81 | + return self.score |
0 commit comments