端午编程小游戏--艾草驱邪

发布于:2025-06-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

刚刚过去的端午,参加了学校的一个活动,用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()


网站公告

今日签到

点亮在社区的每一天
去签到