| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- from typing import List
- import pygame
- from random import randint
- class Pos:
- def __init__(self, x, y):
- self.x, self.y = int(x), int(y)
- @classmethod
- def random(cls):
- return cls(randint(0, Game.MAP.x - 1), randint(0, Game.MAP.y - 1))
- def copy(self):
- return Pos(self.x, self.y)
- def __eq__(self, other):
- return self.x == other.x and self.y == other.y
- class Colours:
- BACKGROUND = (0, 0, 0)
- FOREGROUND = (255, 0, 0)
- SNAKE = (0, 255, 0)
- FOOD = (0, 0, 255)
- class Game:
- MAP = Pos(20, 20)
- CUBE = 20
- FPS = 60
- SPEED = 120
- DEBUG = False
- def __init__(self):
- start_pos = Pos(self.MAP.x / 2, self.MAP.y / 2)
- self.snake = Snake(start_pos)
- self.dead = False
- self.running = True
- self.score = 0
- self.screen = pygame.display.set_mode((self.MAP.y * self.CUBE, self.MAP.x * self.CUBE))
- self.clock = pygame.time.Clock()
- self.timer = 0.0
- self.font = pygame.font.SysFont('Arial', 20, True, False)
- def proc_events(self, e):
- if e.type == pygame.QUIT:
- self.running = False
- if e.type != pygame.KEYDOWN:
- return
- if e.key == pygame.K_SPACE and self.dead:
- start_pos = Pos(self.MAP.x / 2, self.MAP.y / 2)
- self.snake = Snake(start_pos)
- self.dead = False
- if e.key == pygame.K_UP:
- if self.snake.dir != 1:
- self.snake.dir_next = 0
- elif e.key == pygame.K_DOWN:
- if self.snake.dir != 0:
- self.snake.dir_next = 1
- elif e.key == pygame.K_LEFT:
- if self.snake.dir != 3:
- self.snake.dir_next = 2
- elif e.key == pygame.K_RIGHT:
- if self.snake.dir != 2:
- self.snake.dir_next = 3
- elif e.key == pygame.K_d:
- self.DEBUG = not self.DEBUG
- elif e.key == pygame.K_ESCAPE:
- self.running = False
- def loop(self):
- for event in pygame.event.get():
- self.proc_events(event)
- if self.dead:
- text = self.font.render(f"SCORE: {self.score}", True, Colours.FOREGROUND)
- self.screen.blit(text, (self.MAP.x * self.CUBE / 2, self.MAP.y * self.CUBE / 2))
- pygame.display.flip()
- self.clock.tick(30)
- return
- if 0 > self.snake.head.x or self.snake.head.x >= self.MAP.x or \
- 0 > self.snake.head.y or self.snake.head.y >= self.MAP.y:
- self.dead = True
- self.screen.fill(Colours.BACKGROUND)
- pygame.draw.rect(
- self.screen, Colours.FOOD,
- (self.snake.food.y * self.CUBE, self.snake.food.x * self.CUBE, self.CUBE - 1, self.CUBE - 1), 0)
- for c in self.snake.body:
- pygame.draw.rect(
- self.screen, Colours.SNAKE,
- (c.y * self.CUBE, c.x * self.CUBE, self.CUBE - 1, self.CUBE - 1), 0)
- self.timer += self.clock.get_time()
- if self.timer >= self.SPEED:
- self.timer = 0.0
- if self.snake.dir_next == 0:
- self.snake.head.x -= 1
- elif self.snake.dir_next == 1:
- self.snake.head.x += 1
- elif self.snake.dir_next == 2:
- self.snake.head.y -= 1
- else:
- self.snake.head.y += 1
- self.snake.dir = self.snake.dir_next
- if self.snake.collide(self.snake.head):
- self.dead = True
- if self.snake.head == self.snake.food:
- self.snake.add_food()
- self.snake.size += 1
- self.score += 1
- self.snake.move()
- if self.DEBUG:
- text1 = self.font.render(
- f"X: {self.snake.head.x:02d} Y: {self.snake.head.y:02d} "
- f"S: {self.snake.size} FPS: {self.clock.get_fps():.1f}",
- True, Colours.FOREGROUND)
- text2 = self.font.render(
- f"F X: {self.snake.food.x:02d} Y: {self.snake.food.y:02d} S: {self.score}",
- True, Colours.FOREGROUND)
- self.screen.blit(text1, (10, 10))
- self.screen.blit(text2, (10, 32))
- pygame.display.flip()
- self.clock.tick(60)
- class Snake:
- def __init__(self, start: Pos, size=3, dir=0):
- self.size: int = size
- self.head: Pos = start
- self.body: List[Pos] = [start.copy()]
- self.dir: int = dir # Direction 0=N, 1=S, 2=W, 3=E
- self.dir_next: int = dir # Next direction
- self.food: Pos = None
- self.add_food()
- def add_food(self):
- self.food = Pos.random()
- while self.collide(self.food):
- self.food = Pos.random()
- def collide(self, pos: Pos) -> bool:
- for l in self.body:
- if pos == l:
- return True
- return False
- def move(self):
- self.body.append(self.head.copy())
- if len(self.body) > self.size:
- self.body.pop(0)
- if __name__ == '__main__':
- pygame.init()
- pygame.display.set_caption("Snake")
- game = Game()
- game.DEBUG = True
- while game.running:
- game.loop()
- pygame.quit()
|