Greedy snake 3.0
import pygame
import random
import copy
import sys
import math
import time
初始化pygame
pygame.init()
设置屏幕大小为 650*650
screen_width, screen_height = 650, 650
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('贪吃蛇游戏')
颜色定义
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
GRAY = (128, 128, 128) # 第一条电脑蛇身体颜色
BLUE = (0, 0, 255) # 第二条电脑蛇身体颜色
YELLOW = (255, 255, 0) # 第二条电脑蛇眼睛颜色
BORDER_COLOR_1 = (255, 255, 0) # 闪烁边框颜色 1
BORDER_COLOR_2 = (0, 255, 255) # 闪烁边框颜色 2
BORDER_WIDTH = 3 # 边框宽度
BLINK_INTERVAL = 0.5 # 闪烁间隔时间(秒)
新定义红灰色和道具边框颜色
RED_GRAY = (200, 128, 128)
POWERUP_BORDER_COLOR_1 = (255, 128, 128)
POWERUP_BORDER_COLOR_2 = (128, 64, 64)
字体
font = pygame.font.SysFont('simhei', 40)
small_font = pygame.font.SysFont('simhei', 15) # 调整字体大小以适应 80x80 边框
timer_font = pygame.font.SysFont('simhei', 20) # 计时器字体
新增游戏结束提示字体,大小和按钮字体一致
game_over_font = pygame.font.SysFont('simhei', 40)
食物数量
FOOD_COUNT = 15
EYE_SIZE = 2 # 眼睛大小
EYE_OFFSET = 3 # 眼睛相对蛇头中心的偏移量
BODY_RADIUS = 5 # 蛇身体半径
HEAD_RADIUS = int(BODY_RADIUS * 1.6) # 蛇头半径
障碍物数量
OBSTACLE_COUNT = 5
OBSTACLE_RADIUS = 15 # 障碍物半径
TEETH_COUNT = 8 # 齿轮齿数
TOOTH_LENGTH = 5 # 齿长
新增碰撞阈值,当蛇头与障碍物中心距离小于该值时判定碰撞
COLLISION_THRESHOLD = OBSTACLE_RADIUS
道具相关参数
POWERUP_COUNT = 3
POWERUP_SIZE = 15
POWERUP_BLINK_INTERVAL = 0.3
SPEED_MULTIPLIER = 1.5
POWERUP_DURATION = 2 # 道具效果持续时间(秒)
游戏时间,单位:秒
GAME_DURATION = 60
加载封面图片
try:
cover_image = pygame.image.load('cover.jpg')
cover_image = pygame.transform.scale(cover_image, (screen_width, screen_height))
except FileNotFoundError:
print("未找到封面图片 'cover.jpg',请确保图片在正确路径下。")
cover_image = None
加载游戏结束图片
try:
game_over_image = pygame.image.load('game_over.jpg')
game_over_image = pygame.transform.scale(game_over_image, (screen_width, screen_height))
except FileNotFoundError:
print("未找到游戏结束图片 'game_over.jpg',请确保图片在正确路径下。")
game_over_image = None
加载模式选择界面图片
try:
mode_selection_image = pygame.image.load('mode_selection.jpg')
mode_selection_image = pygame.transform.scale(mode_selection_image, (screen_width, screen_height))
except FileNotFoundError:
print("未找到模式选择界面图片 'mode_selection.jpg',请确保图片在正确路径下。")
mode_selection_image = None
边框尺寸和位置
border_size = 80
border_x = screen_width - border_size - 10 # 距离右边 10 像素
border_y = 10 # 距离顶部 10 像素
def is_overlapping_with_border(pos, size):
"""
检查给定位置和大小的对象是否与分数统计边框重叠
:param pos: 对象的位置
:param size: 对象的大小(半径或边长等)
:return: 是否重叠
"""
x, y = pos
border_rect = pygame.Rect(border_x, border_y, border_size, border_size)
obj_rect = pygame.Rect(x - size, y - size, size * 2, size * 2)
return border_rect.colliderect(obj_rect)
def draw_button(text, x, y, width, height, inactive_color, active_color, action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
current_time = time.time()
border_color = BORDER_COLOR_1 if (current_time // BLINK_INTERVAL) % 2 == 0 else BORDER_COLOR_2
if x < mouse[0] < x + width and y < mouse[1] < y + height:
pygame.draw.rect(screen, active_color, (x, y, width, height))
pygame.draw.rect(screen, border_color, (x, y, width, height), BORDER_WIDTH)
if click[0] == 1 and action is not None:
return action
else:
pygame.draw.rect(screen, inactive_color, (x, y, width, height))
pygame.draw.rect(screen, border_color, (x, y, width, height), BORDER_WIDTH)
text_surf = font.render(text, True, BLACK)
text_rect = text_surf.get_rect()
text_rect.center = (x + width / 2, y + height / 2)
screen.blit(text_surf, text_rect)
return False
def game_intro():
intro = True
clock = pygame.time.Clock()
while intro:
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if cover_image:
screen.blit(cover_image, (0, 0))
else:
screen.fill(WHITE)
# 竖着显示“贪吃蛇游戏”
title_text = "贪吃蛇游戏"
x_pos = 30 # 文字距离左侧的距离
y_start = 50 # 文字起始的 y 坐标
title_rects = []
for i, char in enumerate(title_text):
char_surf = font.render(char, True, BLACK)
char_rect = char_surf.get_rect(topleft=(x_pos, y_start + i * (char_surf.get_height() + 10)))
screen.blit(char_surf, char_rect)
title_rects.append(char_rect)
# 计算整个标题的包围矩形
min_x = min(rect.left for rect in title_rects)
min_y = min(rect.top for rect in title_rects)
max_x = max(rect.right for rect in title_rects)
max_y = max(rect.bottom for rect in title_rects)
title_bbox = pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y)
title_bbox.inflate_ip(10, 10) # 让边框比文字区域稍大
# 获取当前时间,用于控制边框闪烁
current_time = time.time()
border_color = BORDER_COLOR_1 if (current_time // BLINK_INTERVAL) % 2 == 0 else BORDER_COLOR_2
# 绘制带闪烁边框的矩形
pygame.draw.rect(screen, border_color, title_bbox, BORDER_WIDTH)
# 按钮位置保持不变
start_game = draw_button("游戏开始",
screen_width / 2 - 100,
screen_height * 2 / 3,
200,
50,
GREEN,
(0, 200, 0),
"start")
if start_game == "start":
intro = False
pygame.display.update()
def select_mode():
selecting = True
clock = pygame.time.Clock()
while selecting:
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(WHITE)
# 绘制模式选择界面图片
if mode_selection_image:
screen.blit(mode_selection_image, (0, 0))
# 显示模式选择提示
mode_text = font.render("选择游戏模式", True, BLACK)
mode_rect = mode_text.get_rect(center=(screen_width / 2, screen_height / 4))
screen.blit(mode_text, mode_rect)
# 生存模式按钮
survival_mode = draw_button("生存模式",
screen_width / 2 - 100,
screen_height / 2 - 50,
200,
50,
GREEN,
(0, 200, 0),
"survival")
# 自由模式按钮
free_mode = draw_button("自由模式",
screen_width / 2 - 100,
screen_height / 2 + 50,
200,
50,
GREEN,
(0, 200, 0),
"free")
if survival_mode == "survival":
return "survival"
elif free_mode == "free":
return "free"
pygame.display.update()
def get_distance(p1, p2):
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
def computer_ai(snake_list, foods, obstacles, self_score, player_score, other_computer_score):
# 计算排名
scores = [self_score, player_score, other_computer_score]
rank = sorted(scores, reverse=True).index(self_score) + 1
head = snake_list[0]
closest_food = None
min_dist = float('inf')
for food in foods:
dist = get_distance(head, food["pos"])
if dist < min_dist:
min_dist = dist
closest_food = food["pos"]
if closest_food is None:
return "up"
directions = [
([head[0], head[1] - 10], "up"),
([head[0], head[1] + 10], "down"),
([head[0] - 10, head[1]], "left"),
([head[0] + 10, head[1]], "right")
]
valid_directions = []
for new_pos, direction in directions:
# 调整边界检查为 650
if 0 <= new_pos[0] < 650 and 0 <= new_pos[1] < 650:
collision = False
# 检查是否会撞到蛇身
for segment in snake_list[:-1]:
if new_pos == segment:
collision = True
break
# 检查是否会撞到障碍物
for obstacle in obstacles:
dist = get_distance(new_pos, obstacle["pos"])
if dist < COLLISION_THRESHOLD:
collision = True
break
if not collision:
valid_directions.append((new_pos, direction))
if not valid_directions:
return "up"
best_dir = None
min_dist = float('inf')
for new_pos, direction in valid_directions:
dist = get_distance(new_pos, closest_food)
if dist < min_dist:
min_dist = dist
best_dir = direction
# 根据排名调整策略,这里简单示例,排名第一时更保守
if rank == 1:
# 简单示例:避开危险区域,比如靠近障碍物时更谨慎
dangerous_directions = []
for new_pos, direction in valid_directions:
for obstacle in obstacles:
dist = get_distance(new_pos, obstacle["pos"])
if dist < COLLISION_THRESHOLD + 10: # 加大安全距离
dangerous_directions.append(direction)
break
if best_dir in dangerous_directions:
# 选择另一个安全方向
for new_pos, direction in valid_directions:
if direction not in dangerous_directions:
best_dir = direction
break
elif rank == 3:
# 排名最后时更激进,更倾向于冲向食物
pass
return best_dir
def generate_food(count):
foods = []
for _ in range(count):
while True:
# 调整随机位置范围为 650
food_pos = [random.randint(15, 635), random.randint(15, 635)]
if not is_overlapping_with_border(food_pos, 13): # 食物半径为 13
break
food = {
"pos": food_pos,
"color": RED
}
foods.append(food)
return foods
生成障碍物
def generate_obstacles(count):
obstacles = []
for _ in range(count):
while True:
# 调整随机位置范围为 650
obstacle_pos = [random.randint(15 + OBSTACLE_RADIUS, 635 - OBSTACLE_RADIUS),
random.randint(15 + OBSTACLE_RADIUS, 635 - OBSTACLE_RADIUS)]
if not is_overlapping_with_border(obstacle_pos, OBSTACLE_RADIUS + TOOTH_LENGTH): # 考虑齿长
break
obstacle = {
"pos": obstacle_pos
}
obstacles.append(obstacle)
return obstacles
生成道具
def generate_powerups(count):
powerups = []
for _ in range(count):
while True:
# 调整随机位置范围为 650
powerup_pos = [random.randint(15, 635), random.randint(15, 635)]
if not is_overlapping_with_border(powerup_pos, POWERUP_SIZE):
break
powerup = {
"pos": powerup_pos,
"visible": True
}
powerups.append(powerup)
return powerups
绘制齿轮状障碍物
def draw_gear(screen, pos):
points = []
angle_step = 2 * math.pi / TEETH_COUNT
for i in range(TEETH_COUNT):
angle = i * angle_step
# 绘制内圆上的点
inner_x = pos[0] + OBSTACLE_RADIUS * math.cos(angle)
inner_y = pos[1] + OBSTACLE_RADIUS * math.sin(angle)
points.append((inner_x, inner_y))
# 绘制齿尖的点
outer_x = pos[0] + (OBSTACLE_RADIUS + TOOTH_LENGTH) * math.cos(angle + angle_step / 2)
outer_y = pos[1] + (OBSTACLE_RADIUS + TOOTH_LENGTH) * math.sin(angle + angle_step / 2)
points.append((outer_x, outer_y))
pygame.draw.polygon(screen, BLACK, points)
def draw_snake_head(screen, head_pos, body_color, eye_color, direction):
"""
绘制带有眼睛的蛇头
:param screen: 游戏屏幕
:param head_pos: 蛇头位置
:param body_color: 蛇的身体颜色
:param eye_color: 蛇的眼睛颜色
:param direction: 蛇头移动方向
"""
# 绘制蛇头,使用蛇头半径
pygame.draw.circle(screen, body_color, head_pos, HEAD_RADIUS)
# 根据移动方向确定眼睛位置
if direction == "up":
eye1 = (head_pos[0] - EYE_OFFSET, head_pos[1] - EYE_OFFSET)
eye2 = (head_pos[0] + EYE_OFFSET, head_pos[1] - EYE_OFFSET)
elif direction == "down":
eye1 = (head_pos[0] - EYE_OFFSET, head_pos[1] + EYE_OFFSET)
eye2 = (head_pos[0] + EYE_OFFSET, head_pos[1] + EYE_OFFSET)
elif direction == "left":
eye1 = (head_pos[0] - EYE_OFFSET, head_pos[1] - EYE_OFFSET)
eye2 = (head_pos[0] - EYE_OFFSET, head_pos[1] + EYE_OFFSET)
elif direction == "right":
eye1 = (head_pos[0] + EYE_OFFSET, head_pos[1] - EYE_OFFSET)
eye2 = (head_pos[0] + EYE_OFFSET, head_pos[1] + EYE_OFFSET)
# 绘制眼睛
pygame.draw.circle(screen, eye_color, eye1, EYE_SIZE)
pygame.draw.circle(screen, eye_color, eye2, EYE_SIZE)
def game_loop(game_mode):
snake_list = [[10, 10]]
direction = "right"
next_direction = "right"
player_speed = 15
player_original_speed = 15 # 玩家蛇原始速度
player_powerup_end_time = 0 # 玩家蛇道具效果结束时间
player_score = 0 # 玩家蛇分数
computer_snake = [[300, 300]]
computer_dir = "right"
computer_speed = 15
computer_original_speed = 15 # 第一条电脑蛇原始速度
computer_powerup_end_time = 0 # 第一条电脑蛇道具效果结束时间
computer_score = 0 # 第一条电脑蛇分数
computer_snake2 = [[400, 400]]
computer_dir2 = "right"
computer_speed2 = 15
computer_original_speed2 = 15 # 第二条电脑蛇原始速度
computer_powerup_end_time2 = 0 # 第二条电脑蛇道具效果结束时间
computer_score2 = 0 # 第二条电脑蛇分数
foods = generate_food(FOOD_COUNT)
obstacles = generate_obstacles(OBSTACLE_COUNT)
powerups = generate_powerups(POWERUP_COUNT)
running = True
game_over_reason = ""
clock = pygame.time.Clock()
if game_mode == "free":
# 初始化计时器,记录游戏开始时间和结束时间
start_time = time.time()
end_time = start_time + GAME_DURATION
else:
start_time = None
end_time = None
def snake_to_food(snake):
new_foods = []
for segment in snake:
new_food = {
"pos": segment,
"color": RED
}
new_foods.append(new_food)
return new_foods
def reset_game():
nonlocal snake_list, direction, next_direction, computer_snake, computer_dir, computer_snake2, computer_dir2, foods, obstacles, powerups, start_time, end_time, player_speed, computer_speed, computer_speed2
nonlocal player_original_speed, player_powerup_end_time, computer_original_speed, computer_powerup_end_time, computer_original_speed2, computer_powerup_end_time2
snake_list = [[10, 10]]
direction = "right"
next_direction = "right"
player_speed = 15
player_original_speed = 15
player_powerup_end_time = 0
computer_snake = [[300, 300]]
computer_dir = "right"
computer_speed = 15
computer_original_speed = 15
computer_powerup_end_time = 0
computer_snake2 = [[400, 400]]
computer_dir2 = "right"
computer_speed2 = 15
computer_original_speed2 = 15
computer_powerup_end_time2 = 0
foods = generate_food(FOOD_COUNT)
obstacles = generate_obstacles(OBSTACLE_COUNT)
powerups = generate_powerups(POWERUP_COUNT)
if game_mode == "free":
# 重置计时器
start_time = time.time()
end_time = start_time + GAME_DURATION
while running:
current_time = time.time()
# 检查游戏是否结束
if game_mode == "free":
remaining_time = end_time - current_time
if remaining_time <= 0:
if player_score > computer_score and player_score > computer_score2:
game_over_reason = "玩家蛇获胜!"
elif computer_score > player_score and computer_score > computer_score2:
game_over_reason = "电脑蛇1获胜!"
elif computer_score2 > player_score and computer_score2 > computer_score:
game_over_reason = "电脑蛇2获胜!"
else:
game_over_reason = "平局!"
else:
remaining_time = None
# 检查玩家蛇道具效果是否结束
if current_time > player_powerup_end_time:
player_speed = player_original_speed
# 检查第一条电脑蛇道具效果是否结束
if current_time > computer_powerup_end_time:
computer_speed = computer_original_speed
# 检查第二条电脑蛇道具效果是否结束
if current_time > computer_powerup_end_time2:
computer_speed2 = computer_original_speed2
clock.tick(max(1, int(player_speed)))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
next_direction = "up"
elif event.key == pygame.K_DOWN:
next_direction = "down"
elif event.key == pygame.K_LEFT:
next_direction = "left"
elif event.key == pygame.K_RIGHT:
next_direction = "right"
direction = next_direction
screen.fill(WHITE)
# 计算并显示倒计时,精确到 0.01 秒
if game_mode == "free":
remaining_time = max(0, end_time - current_time)
timer_text = f"剩余时间: {remaining_time:.2f} 秒"
timer_surf = timer_font.render(timer_text, True, BLACK)
timer_rect = timer_surf.get_rect(center=(screen_width // 2, 20))
screen.blit(timer_surf, timer_rect)
# 定义分数文本和使用小字体
score_texts = [
f"玩家蛇: {player_score}",
f"电脑蛇1: {computer_score}",
f"电脑蛇2: {computer_score2}"
]
# 绘制边框
pygame.draw.rect(screen, BLACK, (border_x, border_y, border_size, border_size), 2)
# 绘制分数文本,从上到下排列
y_pos = border_y + 5 # 顶部内边距 5 像素
for text in score_texts:
score_surf = small_font.render(text, True, BLACK)
text_rect = score_surf.get_rect(topleft=(border_x + 5, y_pos)) # 左边内边距 5 像素
screen.blit(score_surf, text_rect)
y_pos += score_surf.get_height() + 3 # 文本间距 3 像素
# 绘制食物
food_rects = []
for food in foods:
rect = pygame.draw.circle(screen, food["color"], food["pos"], 13, 0)
food_rects.append({"rect": rect, "pos": food["pos"], "color": food["color"]})
# 绘制障碍物
for obstacle in obstacles:
draw_gear(screen, obstacle["pos"])
# 绘制道具
eaten_powerups = []
for i, powerup in enumerate(powerups):
# 根据时间切换边框颜色
border_color = POWERUP_BORDER_COLOR_1 if (current_time // POWERUP_BLINK_INTERVAL) % 2 == 0 else POWERUP_BORDER_COLOR_2
x, y = powerup["pos"]
triangle_points = [
(x, y - POWERUP_SIZE),
(x + POWERUP_SIZE, y + POWERUP_SIZE),
(x - POWERUP_SIZE, y + POWERUP_SIZE)
]
# 绘制道具主体
pygame.draw.polygon(screen, RED_GRAY, triangle_points)
# 绘制道具边框
pygame.draw.polygon(screen, border_color, triangle_points, 2)
# 检查玩家蛇是否吃到道具
if get_distance(snake_list[0], powerup["pos"]) < POWERUP_SIZE:
if current_time > player_powerup_end_time: # 确保道具效果已结束
player_original_speed = player_speed
player_speed *= SPEED_MULTIPLIER
player_powerup_end_time = current_time + POWERUP_DURATION
eaten_powerups.append(i)
# 检查第一条电脑蛇是否吃到道具
if get_distance(computer_snake[0], powerup["pos"]) < POWERUP_SIZE:
if current_time > computer_powerup_end_time: # 确保道具效果已结束
computer_original_speed = computer_speed
computer_speed *= SPEED_MULTIPLIER
computer_powerup_end_time = current_time + POWERUP_DURATION
eaten_powerups.append(i)
# 检查第二条电脑蛇是否吃到道具
if get_distance(computer_snake2[0], powerup["pos"]) < POWERUP_SIZE:
if current_time > computer_powerup_end_time2: # 确保道具效果已结束
computer_original_speed2 = computer_speed2
computer_speed2 *= SPEED_MULTIPLIER
computer_powerup_end_time2 = current_time + POWERUP_DURATION
eaten_powerups.append(i)
# 移除被吃掉的道具并生成新道具
for i in sorted(eaten_powerups, reverse=True):
if i < len(powerups):
powerups.pop(i)
if eaten_powerups:
powerups.extend(generate_powerups(len(eaten_powerups)))
# 电脑AI决策,传入障碍物参数和分数
computer_dir = computer_ai(computer_snake, foods, obstacles, computer_score, player_score, computer_score2)
computer_dir2 = computer_ai(computer_snake2, foods, obstacles, computer_score2, player_score, computer_score)
# 定义电脑蛇移动方向变量
computer_move_up = computer_dir == "up"
computer_move_down = computer_dir == "down"
computer_move_left = computer_dir == "left"
computer_move_right = computer_dir == "right"
computer_move_up2 = computer_dir2 == "up"
computer_move_down2 = computer_dir2 == "down"
computer_move_left2 = computer_dir2 == "left"
computer_move_right2 = computer_dir2 == "right"
# 绘制玩家蛇并获取矩形列表
player_snake_rect = []
for i, snake_point in enumerate(snake_list):
if i == 0:
draw_snake_head(screen, snake_point, GREEN, BLACK, direction)
else:
player_snake_rect_point = pygame.draw.circle(screen, GREEN, snake_point, BODY_RADIUS, 0)
player_snake_rect.append(player_snake_rect_point)
# 绘制第一条电脑蛇并获取矩形列表
computer_snake_rect = []
for i, snake_point in enumerate(computer_snake):
if i == 0:
draw_snake_head(screen, snake_point, GRAY, BLACK, computer_dir)
else:
computer_snake_rect_point = pygame.draw.circle(screen, GRAY, snake_point, BODY_RADIUS, 0)
computer_snake_rect.append(computer_snake_rect_point)
# 绘制第二条电脑蛇并获取矩形列表
computer_snake_rect2 = []
for i, snake_point in enumerate(computer_snake2):
if i == 0:
draw_snake_head(screen, snake_point, BLUE, YELLOW, computer_dir2)
else:
computer_snake_rect_point2 = pygame.draw.circle(screen, BLUE, snake_point, BODY_RADIUS, 0)
computer_snake_rect2.append(computer_snake_rect_point2)
# 检查玩家蛇吃食物
eaten_indices = []
for i, food in enumerate(food_rects):
if food["rect"].collidepoint(snake_list[0]): # 只检查蛇头
if "from_snake" not in food or food["from_snake"] != "player":
eaten_indices.append(i)
snake_list.append([food["pos"][0], food["pos"][1]])
player_score += 2 # 玩家蛇吃一个食物加 2 分
# 移除被吃掉的食物并生成新食物
for i in sorted(eaten_indices, reverse=True):
if i < len(foods):
foods.pop(i)
if eaten_indices:
foods.extend(generate_food(len(eaten_indices)))
# 检查第一条电脑蛇吃食物
eaten_indices = []
for i, food in enumerate(food_rects):
if food["rect"].collidepoint(computer_snake[0]): # 只检查电脑蛇头
if "from_snake" not in food or food["from_snake"] != "computer1":
eaten_indices.append(i)
computer_snake.append([food["pos"][0], food["pos"][1]])
computer_score += 1 # 电脑蛇吃一个食物加 1 分
# 移除被吃掉的食物并生成新食物
for i in sorted(eaten_indices, reverse=True):
if i < len(foods):
foods.pop(i)
if eaten_indices:
foods.extend(generate_food(len(eaten_indices)))
# 检查第二条电脑蛇吃食物
eaten_indices = []
for i, food in enumerate(food_rects):
if food["rect"].collidepoint(computer_snake2[0]): # 只检查电脑蛇头
if "from_snake" not in food or food["from_snake"] != "computer2":
eaten_indices.append(i)
computer_snake2.append([food["pos"][0], food["pos"][1]])
computer_score2 += 1 # 电脑蛇吃一个食物加 1 分
# 移除被吃掉的食物并生成新食物
for i in sorted(eaten_indices, reverse=True):
if i < len(foods):
foods.pop(i)
if eaten_indices:
foods.extend(generate_food(len(eaten_indices)))
# 移动玩家蛇
pos = len(snake_list) - 1
while pos > 0:
snake_list[pos] = copy.deepcopy(snake_list[pos - 1])
pos -= 1
# 根据方向移动蛇头
if direction == "up":
snake_list[0][1] -= 10
if snake_list[0][1] < 0:
snake_list[0][1] = 650
elif direction == "down":
snake_list[0][1] += 10
if snake_list[0][1] > 650:
snake_list[0][1] = 0
elif direction == "left":
snake_list[0][0] -= 10
if snake_list[0][0] < 0:
snake_list[0][0] = 650
elif direction == "right":
snake_list[0][0] += 10
if snake_list[0][0] > 650:
snake_list[0][0] = 0
# 移动第一条电脑蛇
pos = len(computer_snake) - 1
while pos > 0:
computer_snake[pos] = copy.deepcopy(computer_snake[pos - 1])
pos -= 1
if computer_move_up:
computer_snake[0][1] -= 10
if computer_snake[0][1] < 0:
computer_snake[0][1] = 650
if computer_move_down:
computer_snake[0][1] += 10
if computer_snake[0][1] > 650:
computer_snake[0][1] = 0
if computer_move_left:
computer_snake[0][0] -= 10
if computer_snake[0][0] < 0:
computer_snake[0][0] = 650
if computer_move_right:
computer_snake[0][0] += 10
if computer_snake[0][0] > 650:
computer_snake[0][0] = 0
# 移动第二条电脑蛇
pos = len(computer_snake2) - 1
while pos > 0:
computer_snake2[pos] = copy.deepcopy(computer_snake2[pos - 1])
pos -= 1
if computer_move_up2:
computer_snake2[0][1] -= 10
if computer_snake2[0][1] < 0:
computer_snake2[0][1] = 650
if computer_move_down2:
computer_snake2[0][1] += 10
if computer_snake2[0][1] > 650:
computer_snake2[0][1] = 0
if computer_move_left2:
computer_snake2[0][0] -= 10
if computer_snake2[0][0] < 0:
computer_snake2[0][0] = 650
if computer_move_right2:
computer_snake2[0][0] += 10
if computer_snake2[0][0] > 650:
computer_snake2[0][0] = 0
# 检查玩家蛇与障碍物碰撞
player_head = snake_list[0]
for obstacle in obstacles:
dist = get_distance(player_head, obstacle["pos"])
if dist < COLLISION_THRESHOLD:
new_foods = snake_to_food(snake_list)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为玩家蛇死亡掉落的食物
for food in new_foods:
food["from_snake"] = "player"
foods.extend(new_foods)
snake_list = [[random.randint(15, 635), random.randint(15, 635)]]
direction = "right"
player_speed = 15
if game_mode == "survival":
game_over_reason = "玩家蛇撞到障碍物,游戏结束!"
break
# 检查玩家蛇与其他蛇碰撞
head_rest = player_snake_rect[0] if player_snake_rect else None
if head_rest:
for segment in computer_snake_rect:
if head_rest.colliderect(segment):
new_foods = snake_to_food(snake_list)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为玩家蛇死亡掉落的食物
for food in new_foods:
food["from_snake"] = "player"
foods.extend(new_foods)
snake_list = [[random.randint(15, 635), random.randint(15, 635)]]
direction = "right"
player_speed = 15
if game_mode == "survival":
game_over_reason = "玩家蛇撞到电脑蛇1,游戏结束!"
break
for segment in computer_snake_rect2:
if head_rest.colliderect(segment):
new_foods = snake_to_food(snake_list)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为玩家蛇死亡掉落的食物
for food in new_foods:
food["from_snake"] = "player"
foods.extend(new_foods)
snake_list = [[random.randint(15, 635), random.randint(15, 635)]]
direction = "right"
player_speed = 15
if game_mode == "survival":
game_over_reason = "玩家蛇撞到电脑蛇2,游戏结束!"
break
# 检查第一条电脑蛇与障碍物碰撞
computer_head = computer_snake[0]
for obstacle in obstacles:
dist = get_distance(computer_head, obstacle["pos"])
if dist < COLLISION_THRESHOLD:
new_foods = snake_to_food(computer_snake)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 1 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer1"
foods.extend(new_foods)
computer_snake = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir = "right"
computer_speed = 15
break
# 检查第二条电脑蛇与障碍物碰撞
computer_head2 = computer_snake2[0]
for obstacle in obstacles:
dist = get_distance(computer_head2, obstacle["pos"])
if dist < COLLISION_THRESHOLD:
new_foods = snake_to_food(computer_snake2)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 2 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer2"
foods.extend(new_foods)
computer_snake2 = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir2 = "right"
computer_speed2 = 15
break
# 检查第一条电脑蛇与其他蛇碰撞
computer_head_rest = computer_snake_rect[0] if computer_snake_rect else None
if computer_head_rest:
for segment in player_snake_rect:
if computer_head_rest.colliderect(segment):
new_foods = snake_to_food(computer_snake)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 1 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer1"
foods.extend(new_foods)
computer_snake = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir = "right"
computer_speed = 15
break
for segment in computer_snake_rect2:
if computer_head_rest.colliderect(segment):
new_foods = snake_to_food(computer_snake)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 1 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer1"
foods.extend(new_foods)
computer_snake = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir = "right"
computer_speed = 15
break
# 检查第二条电脑蛇与其他蛇碰撞
computer_head_rest2 = computer_snake_rect2[0] if computer_snake_rect2 else None
if computer_head_rest2:
for segment in player_snake_rect:
if computer_head_rest2.colliderect(segment):
new_foods = snake_to_food(computer_snake2)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 2 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer2"
foods.extend(new_foods)
computer_snake2 = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir2 = "right"
computer_speed2 = 15
break
for segment in computer_snake_rect:
if computer_head_rest2.colliderect(segment):
new_foods = snake_to_food(computer_snake2)
# 移除超出屏幕范围的食物
new_foods = [food for food in new_foods if 0 <= food["pos"][0] < 650 and 0 <= food["pos"][1] < 650]
# 标记这些食物为电脑蛇 2 死亡掉落的食物
for food in new_foods:
food["from_snake"] = "computer2"
foods.extend(new_foods)
computer_snake2 = [[random.randint(15, 635), random.randint(15, 635)]]
computer_dir2 = "right"
computer_speed2 = 15
break
# 限制食物数量,避免过多
if len(foods) > 50:
foods = foods[:50]
pygame.display.update()
if game_over_reason:
screen.fill(WHITE)
if game_over_image:
# 向下移动 50 像素,可按需调整
screen.blit(game_over_image, (0, 50))
# 使用新字体渲染游戏结束原因
reason = game_over_font.render(game_over_reason, True, BLACK)
# 往上调 200 像素
reason_rect = reason.get_rect(center=(screen_width / 2, screen_height / 3 + 20 + 100 - 200))
# 获取当前时间,用于控制边框闪烁
current_time = time.time()
border_color = BORDER_COLOR_1 if (current_time // BLINK_INTERVAL) % 2 == 0 else BORDER_COLOR_2
# 绘制带闪烁边框的矩形
border_rect = reason_rect.copy()
border_rect.inflate_ip(10, 10) # 让边框比文字区域稍大
pygame.draw.rect(screen, border_color, border_rect, BORDER_WIDTH)
screen.blit(reason, reason_rect)
back_to_mode_selection_pressed = False
while True:
current_time = time.time()
border_color = BORDER_COLOR_1 if (current_time // BLINK_INTERVAL) % 2 == 0 else BORDER_COLOR_2
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# 按钮位置往上调 100 像素,按钮文字改为返回模式选择
back_to_mode_selection = draw_button("返回模式选择",
screen_width / 2 - 100,
screen_height / 2 + 30 - 100,
200,
50,
GREEN,
(0, 200, 0),
"back_to_mode_selection")
if back_to_mode_selection == "back_to_mode_selection":
back_to_mode_selection_pressed = True
if back_to_mode_selection_pressed:
break
# 重新绘制带闪烁边框的矩形
pygame.draw.rect(screen, border_color, border_rect, BORDER_WIDTH)
screen.blit(reason, reason_rect)
# 按钮位置往上调 100 像素,按钮文字改为返回模式选择
draw_button("返回模式选择",
screen_width / 2 - 100,
screen_height / 2 + 30 - 100,
200,
50,
GREEN,
(0, 200, 0),
"back_to_mode_selection")
pygame.display.update()
break # 退出 game_loop 循环,回到模式选择界面
游戏主循环
while True:
game_intro()
selected_mode = select_mode()
game_loop(selected_mode)
pygame.quit()

浙公网安备 33010602011771号