刚刚过去的端午,参加了学校的一个活动,用python做了一个小游戏,当然这个小游戏还可以继续改进,可以加个bgm什么的......
可以小玩一下
import pygame
import random
import math
import sys
import time
pygame.init()
pygame.mixer.init()
# 屏幕设置
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("端午节:艾草驱邪")
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 200, 0)
LIGHT_GREEN = (144, 238, 144, 100)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
PURPLE = (128, 0, 128)
GRAY = (150, 150, 150)
font_small = pygame.font.SysFont('SimHei', 20)
font_medium = pygame.font.SysFont('SimHei', 30)
font_large = pygame.font.SysFont('SimHei', 50)
FPS = 60
clock = pygame.time.Clock()
MENU = 0
PLAYING = 1
GAME_OVER = 2
INSTRUCTIONS = 3
game_state = MENU
NORMAL_MODE = 0
SURVIVAL_MODE = 1
TIME_ATTACK_MODE = 2
current_mode = NORMAL_MODE
score = 0
max_moxa = 30
start_time = 0
time_limit = 60
survival_time = 0
class Moxa:
def __init__(self, x, y, moxa_type="normal"):
self.x = x
self.y = y
self.type = moxa_type
self.radius = 10
self.effect_radius = 80 if moxa_type == "normal" else (120 if moxa_type == "strong" else 60) # 不同类型艾草效果范围
self.color = GREEN if moxa_type == "normal" else BLUE if moxa_type == "strong" else YELLOW # 不同类型艾草颜色
self.active = True
def draw(self, surface):
if self.active:
effect_surface = pygame.Surface((self.effect_radius*2, self.effect_radius*2), pygame.SRCALPHA)
pygame.draw.circle(effect_surface, (*self.color[:3], 50), (self.effect_radius, self.effect_radius), self.effect_radius)
surface.blit(effect_surface, (self.x - self.effect_radius, self.y - self.effect_radius))
pygame.draw.circle(surface, self.color, (self.x, self.y), self.radius)
class Evil:
def __init__(self, x, y, evil_type="normal"):
self.x = x
self.y = y
self.type = evil_type
self.radius = 8 if evil_type == "normal" else (12 if evil_type == "strong" else 6) # 不同类型邪气大小
self.color = RED if evil_type == "normal" else PURPLE if evil_type == "strong" else (200, 100, 0) # 不同类型邪气颜色
self.speed = 1.5 if evil_type == "normal" else 2.5 if evil_type == "strong" else 1.0 # 不同类型邪气速度
self.direction = random.uniform(0, 2 * math.pi)
self.change_dir_counter = 0
self.change_dir_interval = random.randint(30, 90)
self.being_repelled = False
self.repulsion_strength = 0
self.alpha = 255
def move(self, moxas):
if self.being_repelled and self.repulsion_strength > 0:
self.x += math.cos(self.direction) * self.repulsion_strength
self.y += math.sin(self.direction) * self.repulsion_strength
self.repulsion_strength *= 0.95
self.radius *= 0.98
self.alpha -= 5
if self.repulsion_strength < 0.1 or self.alpha <= 0:
return False
return True
self.change_dir_counter += 1
if self.change_dir_counter >= self.change_dir_interval:
self.direction = random.uniform(0, 2 * math.pi)
self.change_dir_counter = 0
self.change_dir_interval = random.randint(30, 90)
self.x += math.cos(self.direction) * self.speed
self.y += math.sin(self.direction) * self.speed
if self.x < self.radius:
self.x = self.radius
self.direction = math.pi - self.direction
elif self.x > WIDTH - self.radius:
self.x = WIDTH - self.radius
self.direction = math.pi - self.direction
if self.y < self.radius:
self.y = self.radius
self.direction = -self.direction
elif self.y > HEIGHT - self.radius:
self.y = HEIGHT - self.radius
self.direction = -self.direction
for moxa in moxas:
if moxa.active:
distance = math.sqrt((self.x - moxa.x)**2 + (self.y - moxa.y)**2)
if distance < moxa.effect_radius + self.radius:
self.being_repelled = True
self.direction = math.atan2(self.y - moxa.y, self.x - moxa.x)
repel_force = 3 if moxa.type == "normal" else (5 if moxa.type == "strong" else 2)
self.repulsion_strength = repel_force
return True
return True
def draw(self, surface):
color_with_alpha = (*self.color, self.alpha)
evil_surface = pygame.Surface((self.radius*2, self.radius*2), pygame.SRCALPHA)
pygame.draw.circle(evil_surface, color_with_alpha, (self.radius, self.radius), self.radius)
surface.blit(evil_surface, (self.x - self.radius, self.y - self.radius))
moxas = []
evils = []
evil_spawn_timer = 0
evil_spawn_interval = 60
selected_moxa_type = "normal"
show_type_selection = False
type_selection_timer = 0
for _ in range(5):
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
evil_type = random.choice(["normal", "normal", "strong", "weak"]) # 初始邪气以普通为主
evils.append(Evil(x, y, evil_type))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
if game_state == PLAYING:
game_state = MENU
elif game_state == INSTRUCTIONS:
game_state = MENU
elif game_state == GAME_OVER:
game_state = MENU
else:
running = False
if event.key == pygame.K_r and game_state == GAME_OVER:
game_state = PLAYING
score = 0
moxas = []
evils = []
for _ in range(5):
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
evils.append(Evil(x, y, "normal"))
start_time = time.time()
if current_mode == TIME_ATTACK_MODE:
start_time = time.time()
elif current_mode == SURVIVAL_MODE:
survival_time = 0
if event.key == pygame.K_1:
selected_moxa_type = "normal"
show_type_selection = True
type_selection_timer = 60
if event.key == pygame.K_2:
selected_moxa_type = "strong"
show_type_selection = True
type_selection_timer = 60
if event.key == pygame.K_3:
selected_moxa_type = "weak"
show_type_selection = True
type_selection_timer = 60
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if game_state == MENU:
mouse_x, mouse_y = pygame.mouse.get_pos()
button_width, button_height = 200, 50
button_y = HEIGHT // 2 - 75
if WIDTH // 2 - button_width // 2 <= mouse_x <= WIDTH // 2 + button_width // 2 and button_y <= mouse_y <= button_y + button_height:
current_mode = NORMAL_MODE
max_moxa = 30
game_state = PLAYING
score = 0
moxas = []
evils = []
for _ in range(5):
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
evils.append(Evil(x, y, "normal"))
start_time = time.time()
button_y += 75
if WIDTH // 2 - button_width // 2 <= mouse_x <= WIDTH // 2 + button_width // 2 and button_y <= mouse_y <= button_y + button_height:
current_mode = SURVIVAL_MODE
max_moxa = 999
game_state = PLAYING
score = 0
moxas = []
evils = []
for _ in range(5):
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
evils.append(Evil(x, y, "normal"))
survival_time = time.time()
button_y += 75
if WIDTH // 2 - button_width // 2 <= mouse_x <= WIDTH // 2 + button_width // 2 and button_y <= mouse_y <= button_y + button_height:
current_mode = TIME_ATTACK_MODE
max_moxa = 999
game_state = PLAYING
score = 0
moxas = []
evils = []
for _ in range(5):
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
evils.append(Evil(x, y, "normal"))
start_time = time.time()
button_y += 75
if WIDTH // 2 - button_width // 2 <= mouse_x <= WIDTH // 2 + button_width // 2 and button_y <= mouse_y <= button_y + button_height:
game_state = INSTRUCTIONS
elif game_state == INSTRUCTIONS:
game_state = MENU
elif game_state == PLAYING:
if current_mode == NORMAL_MODE and len(moxas) >= max_moxa:
continue
# 放置艾草
mouse_x, mouse_y = pygame.mouse.get_pos()
moxas.append(Moxa(mouse_x, mouse_y, selected_moxa_type))
show_type_selection = True
type_selection_timer = 60
if game_state == PLAYING:
evil_spawn_timer += 1
if evil_spawn_timer >= evil_spawn_interval:
evil_spawn_timer = 0
if current_mode == SURVIVAL_MODE:
spawn_interval_factor = max(0.5, 1 - survival_time / 300)
evil_spawn_interval = int(60 * spawn_interval_factor)
if survival_time > 120:
evil_type_weights = {"normal": 3, "strong": 5, "weak": 2}
else:
evil_type_weights = {"normal": 5, "strong": 3, "weak": 2}
elif current_mode == TIME_ATTACK_MODE:
spawn_interval_factor = max(0.7, 1 - (time.time() - start_time) / time_limit)
evil_spawn_interval = int(60 * spawn_interval_factor)
if (time.time() - start_time) > time_limit * 0.6:
evil_type_weights = {"normal": 4, "strong": 4, "weak": 2}
else:
evil_type_weights = {"normal": 6, "strong": 2, "weak": 2}
else: # NORMAL_MODE
evil_type_weights = {"normal": 7, "strong": 2, "weak": 1}
evil_type_choices = []
for evil_type, weight in evil_type_weights.items():
evil_type_choices.extend([evil_type] * weight)
new_evil_type = random.choice(evil_type_choices)
side = random.randint(0, 3)
if side == 0:
x = random.randint(0, WIDTH)
y = 0
elif side == 1:
x = WIDTH
y = random.randint(0, HEIGHT)
elif side == 2:
x = random.randint(0, WIDTH)
y = HEIGHT
else:
x = 0
y = random.randint(0, HEIGHT)
evils.append(Evil(x, y, new_evil_type))
evils_to_remove = []
for evil in evils:
if not evil.move(moxas):
evils_to_remove.append(evil)
score += 1
for evil in evils_to_remove:
evils.remove(evil)
if current_mode == SURVIVAL_MODE:
survival_time = time.time() - survival_time_start if 'survival_time_start' in locals() else 0
if 'survival_time_start' not in locals():
survival_time_start = time.time()
if current_mode == TIME_ATTACK_MODE:
elapsed_time = time.time() - start_time
if elapsed_time >= time_limit:
game_state = GAME_OVER
if current_mode == NORMAL_MODE and len(moxas) >= max_moxa:
game_state = GAME_OVER
if show_type_selection:
type_selection_timer -= 1
if type_selection_timer <= 0:
show_type_selection = False
screen.fill(BLACK)
if game_state == MENU:
title_text = font_large.render("端午节:艾草驱邪模拟器", True, WHITE)
screen.blit(title_text, (WIDTH // 2 - title_text.get_width() // 2, HEIGHT // 4))
button_width, button_height = 200, 50
button_x = WIDTH // 2 - button_width // 2
button_y = HEIGHT // 2 - 75
# 正常模式按钮
pygame.draw.rect(screen, GREEN, (button_x, button_y, button_width, button_height))
normal_text = font_medium.render("正常模式", True, WHITE)
screen.blit(normal_text, (button_x + button_width // 2 - normal_text.get_width() // 2, button_y + button_height // 2 - normal_text.get_height() // 2))
# 生存模式按钮
button_y += 75
pygame.draw.rect(screen, BLUE, (button_x, button_y, button_width, button_height))
survival_text = font_medium.render("生存模式", True, WHITE)
screen.blit(survival_text, (button_x + button_width // 2 - survival_text.get_width() // 2, button_y + button_height // 2 - survival_text.get_height() // 2))
# 限时模式按钮
button_y += 75
pygame.draw.rect(screen, YELLOW, (button_x, button_y, button_width, button_height))
time_text = font_medium.render("限时模式", True, BLACK)
screen.blit(time_text, (button_x + button_width // 2 - time_text.get_width() // 2, button_y + button_height // 2 - time_text.get_height() // 2))
# 说明按钮
button_y += 75
pygame.draw.rect(screen, GRAY, (button_x, button_y, button_width, button_height))
instructions_text = font_medium.render("游戏说明", True, WHITE)
screen.blit(instructions_text, (button_x + button_width // 2 - instructions_text.get_width() // 2, button_y + button_height // 2 - instructions_text.get_height() // 2))
elif game_state == INSTRUCTIONS:
# 绘制游戏说明
title_text = font_large.render("游戏说明", True, WHITE)
screen.blit(title_text, (WIDTH // 2 - title_text.get_width() // 2, 50))
instructions = [
"- 点击屏幕放置艾草,驱散邪气。",
"- 按数字键 1、2、3 选择不同类型的艾草:",
" 1: 普通艾草 (绿色,中等效果)",
" 2: 强效艾草 (蓝色,范围大,驱散力强)",
" 3: 弱效艾草 (黄色,范围小,驱散力弱)",
"",
"- 邪气 (红色/紫色/橙色小点) 会随机移动。",
"- 当邪气进入艾草的清香范围时,会被驱散。",
"",
"- **正常模式**: 限制艾草数量,驱散所有邪气后继续生成,直到放置满艾草数量。",
"- **生存模式**: 无限艾草,邪气会随时间变强,坚持时间越长分数越高。",
"- **限时模式**: 无限艾草,在限定时间内驱散尽可能多的邪气。",
"",
"按 ESC 返回主菜单。"
]
y_offset = 120
for line in instructions:
text = font_small.render(line, True, WHITE)
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, y_offset))
y_offset += 30
elif game_state == PLAYING:
for moxa in moxas:
moxa.draw(screen)
for evil in evils:
evil.draw(screen)
score_text = font_medium.render(f"得分: {score}", True, WHITE)
screen.blit(score_text, (10, 10))
if current_mode == NORMAL_MODE:
moxa_count_text = font_small.render(f"艾草: {len(moxas)}/{max_moxa}", True, WHITE)
screen.blit(moxa_count_text, (10, 50))
if show_type_selection:
type_names = {"normal": "普通艾草", "strong": "强效艾草", "weak": "弱效艾草"}
type_text = font_small.render(f"已选择: {type_names[selected_moxa_type]}", True, WHITE)
screen.blit(type_text, (WIDTH - type_text.get_width() - 10, 10))
mode_names = {NORMAL_MODE: "正常模式", SURVIVAL_MODE: "生存模式", TIME_ATTACK_MODE: "限时模式"}
mode_text = font_small.render(f"模式: {mode_names[current_mode]}", True, WHITE)
screen.blit(mode_text, (10, HEIGHT - 30))
if current_mode == TIME_ATTACK_MODE:
elapsed_time = time.time() - start_time
remaining_time = max(0, time_limit - elapsed_time)
time_text = font_small.render(f"剩余时间: {int(remaining_time)}秒", True, WHITE)
screen.blit(time_text, (WIDTH - time_text.get_width() - 10, HEIGHT - 30))
elif current_mode == SURVIVAL_MODE:
survival_time_text = font_small.render(f"生存时间: {int(survival_time)}秒", True, WHITE)
screen.blit(survival_time_text, (WIDTH - survival_time_text.get_width() - 10, HEIGHT - 30))
elif game_state == GAME_OVER:
game_over_text = font_large.render("游戏结束", True, WHITE)
screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 3))
score_text = font_medium.render(f"最终得分: {score}", True, WHITE)
screen.blit(score_text, (WIDTH // 2 - score_text.get_width() // 2, HEIGHT // 2))
if current_mode == SURVIVAL_MODE:
survival_time_text = font_medium.render(f"生存时间: {int(survival_time)}秒", True, WHITE)
screen.blit(survival_time_text, (WIDTH // 2 - survival_time_text.get_width() // 2, HEIGHT // 2 + 50))
restart_text = font_small.render("按 R 键重新开始,按 ESC 返回主菜单", True, WHITE)
screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT * 2 // 3))
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
sys.exit()