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.
206 lines
7.1 KiB
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() |