You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tcs/snake_game.py

206 lines
7.1 KiB

import pygame
import random
# 初始化 Pygame
pygame.init()
# 游戏窗口设置
WINDOW_X = 720
WINDOW_Y = 480
game_window = pygame.display.set_mode((WINDOW_X, WINDOW_Y))
pygame.display.set_caption('贪吃蛇游戏')
# 颜色定义
BLACK = pygame.Color(0, 0, 0)
WHITE = pygame.Color(255, 255, 255)
RED = pygame.Color(255, 0, 0)
GREEN = pygame.Color(0, 255, 0)
# 游戏控制
FPS = pygame.time.Clock()
FONT_SMALL = pygame.font.SysFont('simhei', 20)
FONT_MEDIUM = pygame.font.SysFont('simhei', 30)
FONT_LARGE = pygame.font.SysFont('simhei', 50)
class SnakeGame:
def __init__(self):
self.reset_game()
def reset_game(self):
"""重置游戏状态"""
self.snake_position = [100, 50]
self.snake_body = [[100, 50], [90, 50], [80, 50], [70, 50]]
self.food_position = [
random.randrange(1, (WINDOW_X // 10)) * 10,
random.randrange(1, (WINDOW_Y // 10)) * 10
]
self.food_spawn = True
self.direction = 'RIGHT'
self.change_to = self.direction
self.score = 0
self.speed = 10
self.game_over_flag = False
self.key_press_time = None
def show_score(self, position=1):
"""显示当前分数"""
score_surface = FONT_SMALL.render(f'分数 : {self.score}', True, WHITE)
score_rect = score_surface.get_rect()
if position == 1:
score_rect.midtop = (WINDOW_X / 10, 15)
else:
score_rect.midtop = (WINDOW_X / 2, WINDOW_Y / 1.25)
game_window.blit(score_surface, score_rect)
def game_over(self):
"""显示游戏结束界面"""
game_over_surface = FONT_LARGE.render(f'你的分数 : {self.score}', True, RED)
game_over_rect = game_over_surface.get_rect()
game_over_rect.midtop = (WINDOW_X / 2, WINDOW_Y / 4)
game_window.blit(game_over_surface, game_over_rect)
restart_surface = FONT_MEDIUM.render('按C键重新开始游戏', True, WHITE)
restart_rect = restart_surface.get_rect()
restart_rect.midtop = (WINDOW_X / 2, WINDOW_Y / 2)
game_window.blit(restart_surface, restart_rect)
pygame.display.flip()
def handle_events(self):
"""处理用户输入事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.change_to = 'UP'
self.key_press_time = pygame.time.get_ticks() / 1000
if event.key == pygame.K_DOWN:
self.change_to = 'DOWN'
self.key_press_time = pygame.time.get_ticks() / 1000
if event.key == pygame.K_LEFT:
self.change_to = 'LEFT'
self.key_press_time = pygame.time.get_ticks() / 1000
if event.key == pygame.K_RIGHT:
self.change_to = 'RIGHT'
self.key_press_time = pygame.time.get_ticks() / 1000
if event.key == pygame.K_c and self.game_over_flag:
self.reset_game()
if event.type == pygame.KEYUP:
self.key_press_time = None
return True
def update_speed(self):
"""根据按键时间调整蛇的速度"""
if self.key_press_time:
elapsed_time = pygame.time.get_ticks() / 1000 - self.key_press_time
if elapsed_time < 0.5:
self.speed = 15
elif elapsed_time < 1:
self.speed = 20
else:
self.speed = 25
else:
self.speed = 10
def validate_direction(self):
"""确保蛇不能直接反向移动"""
if self.change_to == 'UP' and self.direction != 'DOWN':
self.direction = self.change_to
if self.change_to == 'DOWN' and self.direction != 'UP':
self.direction = self.change_to
if self.change_to == 'LEFT' and self.direction != 'RIGHT':
self.direction = self.change_to
if self.change_to == 'RIGHT' and self.direction != 'LEFT':
self.direction = self.change_to
def move_snake(self):
"""移动蛇并处理碰撞检测"""
# 根据方向移动蛇头
if self.direction == 'UP':
self.snake_position[1] -= 10
if self.direction == 'DOWN':
self.snake_position[1] += 10
if self.direction == 'LEFT':
self.snake_position[0] -= 10
if self.direction == 'RIGHT':
self.snake_position[0] += 10
# 蛇吃食物
self.snake_body.insert(0, list(self.snake_position))
if self.snake_position == self.food_position:
self.score += 10
self.food_spawn = False
else:
self.snake_body.pop()
# 生成新食物
if not self.food_spawn:
self.food_position = [
random.randrange(1, (WINDOW_X // 10)) * 10,
random.randrange(1, (WINDOW_Y // 10)) * 10
]
# 确保新食物不会出现在蛇身上
while self.food_position in self.snake_body:
self.food_position = [
random.randrange(1, (WINDOW_X // 10)) * 10,
random.randrange(1, (WINDOW_Y // 10)) * 10
]
self.food_spawn = True
# 边界碰撞检测
if (self.snake_position[0] < 0 or self.snake_position[0] > WINDOW_X - 10 or
self.snake_position[1] < 0 or self.snake_position[1] > WINDOW_Y - 10):
self.game_over_flag = True
# 自身碰撞检测
for block in self.snake_body[1:]:
if self.snake_position == block:
self.game_over_flag = True
def draw(self):
"""绘制游戏元素"""
game_window.fill(BLACK)
# 绘制蛇身和食物
for pos in self.snake_body:
pygame.draw.rect(game_window, GREEN, pygame.Rect(pos[0], pos[1], 10, 10))
pygame.draw.rect(game_window, WHITE, pygame.Rect(self.food_position[0], self.food_position[1], 10, 10))
# 显示分数
self.show_score(1)
pygame.display.update()
def run(self):
"""游戏主循环"""
running = True
while running:
if self.game_over_flag:
self.game_over()
# 游戏结束后等待用户按键,不自动重置
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_c:
self.reset_game()
else:
running = self.handle_events()
if not running:
break
self.update_speed()
self.validate_direction()
self.move_snake()
self.draw()
FPS.tick(self.speed)
pygame.quit()
if __name__ == "__main__":
game = SnakeGame()
game.run()