refactor snake game using oop
使用OOP面向对象改写snake game
涉及三个类:SnakeGame, Snake, Food
从高层抽象来看,程序如下:
my_game = SnakeGame()
my_game.play()
我们新建了一个游戏对象my_game,然后调用该对象的play()方法,运行游戏
所有的游戏逻辑封装在SnakeGame里面
# OOP snake game
import pygame
import random
class Snake:
def __init__(self, screen, cols, rows, cell_size = 30, color=(0, 0, 0)):
self.body = [(3, 0), (2, 0), (1, 0)]
self.direction = "RIGHT"
self.cell_size = cell_size
self.screen = screen
self.color = color
self.cols = cols
self.rows = rows
def move(self, direction):
head = self.body[0]
if direction == "RIGHT":
new_head = (head[0] + 1, head[1])
elif direction == "LEFT":
new_head = (head[0] - 1, head[1])
elif direction == "UP":
new_head = (head[0], head[1] - 1)
elif direction == "DOWN":
new_head = (head[0], head[1] + 1)
self.body.insert(0, new_head)
self.body.pop()
self.direction = direction
def draw(self):
for cell in self.body:
x = cell[0] * self.cell_size
y = cell[1] * self.cell_size
pygame.draw.rect(self.screen, self.color, [x, y, self.cell_size, self.cell_size])
head = self.body[0]
head_x = head[0] * self.cell_size
head_y = head[1] * self.cell_size
if self.direction == "LEFT" or self.direction == "RIGHT":
eye1_pos = head_x + self.cell_size // 2, head_y + self.cell_size // 4
eye2_pos = head_x + self.cell_size // 2, head_y + 3* self.cell_size // 4
elif self.direction == "UP" or self.direction == "DOWN":
eye1_pos = head_x + self.cell_size // 4, head_y + self.cell_size // 2
eye2_pos = head_x + 3* self.cell_size // 4, head_y + self.cell_size // 2
else:
pass
pygame.draw.circle(self.screen, (0, 0, 0), eye1_pos, 4)
pygame.draw.circle(self.screen, (0, 0, 0), eye2_pos, 4)
def check_collide(self, food):
# Check if the Snake collides with the Food
if self.body[0] == food.position:
return 0
# Check if the Snake collides with the wall
if self.body[0][0] < 0 or self.body[0][0] >= self.cols or self.body[0][34] < 0 or self.body[0][35] >= self.rows:
return 1
# Check if the Snake collides with its own body
for i in range(1, len(self.body)):
if self.body[0] == self.body[i]:
return 1
return 2
def grow(self):
self.body.append(self.body[-1])
class Food:
def __init__(self, screen, cols, rows, cell_size = 30, color=(255, 0, 0)):
self.position = (random.randint(0, cols - 1), random.randint(0, rows - 1))
self.color = color
self.cell_size = cell_size
self.cols = cols
self.rows = rows
self.screen = screen
def generate_food(self, color=(255, 0, 0)):
self.position = (random.randint(0, self.cols - 1), random.randint(0, self.rows - 1))
self.color = color
def draw(self):
x = self.position[0] * self.cell_size
y = self.position[1] * self.cell_size
pygame.draw.rect(self.screen, self.color, [x, y, self.cell_size, self.cell_size])
class SnakeGame:
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# Set the dimensions of the screen
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
# Set the dimensions of the board and grid
BOARD_ROWS = 20
BOARD_COLS = 20
GRID_SIZE = 30
SCORE_BOARD_WIDTH = 200
def __init__(self):
# Initialize Pygame
pygame.init()
# Set the size of the screen
self.screen = pygame.display.set_mode([SnakeGame.SCREEN_WIDTH + SnakeGame.SCORE_BOARD_WIDTH, SnakeGame.SCREEN_HEIGHT])
self.snake = Snake(self.screen, SnakeGame.BOARD_COLS, SnakeGame.BOARD_COLS, SnakeGame.GRID_SIZE,SnakeGame.WHITE)
self.food = Food(self.screen, SnakeGame.BOARD_COLS, SnakeGame.BOARD_COLS, SnakeGame.GRID_SIZE,SnakeGame.RED)
self.score = 0
# 创建字体对象
self.score_font = pygame.font.SysFont('Arial', 30)
self.score_text = 'Score'
#font.render('Hello, world!', True, (255, 255, 255))
# Set the caption of the screen
pygame.display.set_caption("Snake Game")
def draw(self):
for row in range(SnakeGame.BOARD_ROWS):
for col in range(SnakeGame.BOARD_COLS):
x = col * SnakeGame.GRID_SIZE
y = row * SnakeGame.GRID_SIZE
pygame.draw.rect(self.screen, SnakeGame.WHITE, [x, y, SnakeGame.GRID_SIZE, SnakeGame.GRID_SIZE], 1)
def draw_score(self):
score_text = self.score_font.render(f'{self.score_text}: {self.score}', True, (255, 255, 255))
self.screen.blit(score_text, (SnakeGame.SCREEN_WIDTH, 100))
def play(self):
# Set the clock for the game
clock = pygame.time.Clock()
done = False
direction = "RIGHT"
# Start the game loop
while not done:
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT and direction != "LEFT":
direction = "RIGHT"
elif event.key == pygame.K_LEFT and direction != "RIGHT":
direction = "LEFT"
elif event.key == pygame.K_UP and direction != "DOWN":
direction = "UP"
elif event.key == pygame.K_DOWN and direction != "UP":
direction = "DOWN"
elif event.key == pygame.K_ESCAPE:
done = True
# Move the Snake
self.snake.move(direction)
ret = self.snake.check_collide(self.food)
#print(f'当前分数: {self.score}')
if ret == 0: # collide with food
self.food.generate_food()
self.snake.grow()
self.score +=10
elif ret == 1: # hit wall or itself
done = True
else: # nothing happened
pass
# Clear the screen
self.screen.fill(SnakeGame.BLACK)
# Draw the board, Snake, and Food
self.draw()
self.snake.draw()
self.food.draw()
self.draw_score()
# Update the screen
pygame.display.flip()
# Set the frame rate of the game
clock.tick(5)
pygame.quit()
my_game = SnakeGame()
my_game.play()