|
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