植物大战僵尸

import pygame
import random
import sys

# 初始化游戏
pygame.init()
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("简易植物大战僵尸")
clock = pygame.time.Clock()
FPS = 30

# 颜色定义
GREEN = (0, 200, 0)
LIGHT_GREEN = (0, 255, 0)
BROWN = (139, 69, 19)
YELLOW = (255, 255, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)

# 游戏参数
GRID_SIZE = 80
ROW_NUM, COL_NUM = 5, 9
SUN_VALUE = 25
PLANT_COST = {"sunflower": 50, "peashooter": 100}
ZOMBIE_HP = 100
PEA_DAMAGE = 20

# 字体
font = pygame.font.SysFont('simhei', 24)  # 确保中文显示

# 绘制网格
def draw_grid():
    for row in range(ROW_NUM):
        for col in range(COL_NUM):
            x, y = col * GRID_SIZE, row * GRID_SIZE
            if (row + col) % 2 == 0:
                pygame.draw.rect(screen, GREEN, (x, y, GRID_SIZE, GRID_SIZE))
            else:
                pygame.draw.rect(screen, LIGHT_GREEN, (x, y, GRID_SIZE, GRID_SIZE))
            pygame.draw.rect(screen, (50, 50, 50), (x, y, GRID_SIZE, GRID_SIZE), 1)  # 网格线

# 阳光类
class Sun:
    def __init__(self):
        self.x = random.randint(50, width - 50)
        self.y = -50
        self.radius = 15
        self.speed = 1
        self.value = SUN_VALUE
        self.collected = False

    def update(self):
        self.y += self.speed
        if self.y > height:
            return True
        return False

    def draw(self):
        pygame.draw.circle(screen, YELLOW, (self.x, self.y), self.radius)
        pygame.draw.circle(screen, (255, 200, 0), (self.x, self.y), self.radius // 2)

# 植物类
class Plant:
    def __init__(self, type_, row, col, sun_count):
        self.type = type_
        self.row = row
        self.col = col
        self.x = col * GRID_SIZE + GRID_SIZE // 2
        self.y = row * GRID_SIZE + GRID_SIZE // 2
        self.hp = 100
        self.cost = PLANT_COST[type_]
        self.last_attack = pygame.time.get_ticks()
        self.attack_interval = 2000 if type_ == "peashooter" else 5000  # 攻击间隔(毫秒)

    def update(self, peas):
        current_time = pygame.time.get_ticks()
        if self.type == "sunflower" and current_time - self.last_attack > self.attack_interval:
            self.last_attack = current_time
            return Sun()
        elif self.type == "peashooter" and current_time - self.last_attack > self.attack_interval:
            self.last_attack = current_time
            pea_x = self.x + GRID_SIZE // 2
            pea_y = self.y
            peas.append([pea_x, pea_y, self.row])
        return None

    def draw(self):
        if self.type == "sunflower":
            pygame.draw.circle(screen, YELLOW, (self.x, self.y), 25)
            pygame.draw.circle(screen, (255, 150, 0), (self.x, self.y), 15)
        else:  # peashooter
            pygame.draw.rect(screen, (0, 100, 0), (self.x - 15, self.y - 25, 30, 50))
            pygame.draw.rect(screen, (0, 200, 0), (self.x - 10, self.y - 20, 20, 10))  # 叶子
            pygame.draw.rect(screen, (0, 200, 0), (self.x + 5, self.y - 20, 20, 10))
            pygame.draw.circle(screen, (0, 150, 0), (self.x, self.y - 30), 15)  # 头部

# 豌豆类
class Pea:
    def __init__(self, x, y, row):
        self.x = x
        self.y = y
        self.row = row
        self.speed = 3
        self.remove = False

    def update(self, zombies):
        self.x += self.speed
        if self.x > width:
            self.remove = True
        for zombie in zombies:
            if zombie.row == self.row and zombie.x < self.x < zombie.x + 30 and zombie.y < self.y < zombie.y + 40:
                zombie.hp -= PEA_DAMAGE
                self.remove = True
                break

    def draw(self):
        pygame.draw.circle(screen, (0, 255, 0), (self.x, self.y), 8)

# 僵尸类
class Zombie:
    def __init__(self, row):
        self.row = row
        self.x = width
        self.y = row * GRID_SIZE + GRID_SIZE // 2
        self.hp = ZOMBIE_HP
        self.speed = 0.5
        self.remove = False
        self.eaten = False

    def update(self, plants):
        self.x -= self.speed
        if self.x < 0:
            self.remove = True
            self.eaten = True
        # 检查是否碰到植物
        for plant in plants:
            if plant.row == self.row and self.x - 30 < plant.x < self.x:
                plant.hp -= 1
                if plant.hp <= 0:
                    plants.remove(plant)
        return self.eaten

    def draw(self):
        pygame.draw.rect(screen, (100, 0, 0), (self.x - 15, self.y - 20, 30, 40))  # 僵尸身体
        pygame.draw.circle(screen, (150, 0, 0), (self.x, self.y - 30), 15)  # 僵尸头
        pygame.draw.rect(screen, (200, 0, 0), (self.x - 5, self.y - 15, 5, 10))  # 眼睛
        pygame.draw.rect(screen, (200, 0, 0), (self.x + 5, self.y - 15, 5, 10))

# 游戏主循环
def main():
    suns = [Sun() for _ in range(2)]  # 初始阳光
    plants = []
    peas = []
    zombies = []
    sun_count = 50
    selected_plant = None
    game_over = False
    win = False

    while True:
        screen.fill(BROWN)  # 背景
        draw_grid()  # 绘制草坪网格
        
        # 事件处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
                if event.button == 1:  # 左键点击
                    x, y = event.pos
                    # 收集阳光
                    for sun in suns:
                        if (sun.x - sun.radius) < x < (sun.x + sun.radius) and \
                           (sun.y - sun.radius) < y < (sun.y + sun.radius):
                            sun_count += sun.value
                            suns.remove(sun)
                            suns.append(Sun())  # 生成新阳光
                            break
                    # 种植植物
                    if selected_plant and sun_count >= PLANT_COST[selected_plant]:
                        row, col = y // GRID_SIZE, x // GRID_SIZE
                        if 0 <= row < ROW_NUM and 0 <= col < COL_NUM:
                            # 检查是否已有植物
                            if not any(plant.row == row and plant.col == col for plant in plants):
                                plants.append(Plant(selected_plant, row, col, sun_count))
                                sun_count -= PLANT_COST[selected_plant]
            if event.type == pygame.KEYDOWN and not game_over:
                if event.key == pygame.K_1 and sun_count >= PLANT_COST["peashooter"]:
                    selected_plant = "peashooter"
                if event.key == pygame.K_2 and sun_count >= PLANT_COST["sunflower"]:
                    selected_plant = "sunflower"
                if event.key == pygame.K_r:  # 重新开始
                    main()
        
        # 显示选中的植物
        if selected_plant == "peashooter":
            pygame.draw.rect(screen, YELLOW, (10, 10, 60, 60), 2)
            plant = Plant("peashooter", 0, 0, 0)
            plant.draw()
        elif selected_plant == "sunflower":
            pygame.draw.rect(screen, YELLOW, (10, 10, 60, 60), 2)
            plant = Plant("sunflower", 0, 0, 0)
            plant.draw()
        
        # 绘制植物选择框
        plant1 = Plant("peashooter", 0, 0, 0)
        plant1.draw()
        plant1.x, plant1.y = 10, 10
        cost1 = font.render(f"100", True, WHITE)
        screen.blit(cost1, (10, 70))
        
        plant2 = Plant("sunflower", 0, 0, 0)
        plant2.draw()
        plant2.x, plant2.y = 80, 10
        cost2 = font.render(f"50", True, WHITE)
        screen.blit(cost2, (80, 70))
        
        # 生成阳光
        if random.random() < 0.005 and len(suns) < 5:
            suns.append(Sun())
        
        # 生成僵尸
        if random.random() < 0.002 and len(zombies) < 3:
            zombies.append(Zombie(random.randint(0, ROW_NUM-1)))
        
        # 更新和绘制阳光
        for sun in suns[:]:
            if sun.update():
                suns.remove(sun)
            sun.draw()
        
        # 更新和绘制植物
        new_suns = []
        for plant in plants[:]:
            new_sun = plant.update(peas)
            if new_sun:
                new_suns.append(new_sun)
            plant.draw()
            if plant.hp <= 0:
                plants.remove(plant)
        suns.extend(new_suns)
        
        # 更新和绘制豌豆
        for pea in peas[:]:
            pea.update(zombies)
            if pea.remove:
                peas.remove(pea)
            pea.draw()
        
        # 更新和绘制僵尸
        game_over = False
        for zombie in zombies[:]:
            if zombie.update(plants):
                game_over = True
            zombie.draw()
            if zombie.hp <= 0:
                zombies.remove(zombie)
        if game_over:
            overlay = pygame.Surface((width, height), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 180))
            screen.blit(overlay, (0, 0))
            text = font.render("游戏结束! 按R键重新开始", True, WHITE)
            screen.blit(text, (width//2 - 150, height//2))
        
        # 检查胜利条件
        if not zombies and len(plants) > 0:
            win = True
            overlay = pygame.Surface((width, height), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 180))
            screen.blit(overlay, (0, 0))
            text = font.render("游戏胜利! 按R键重新开始", True, WHITE)
            screen.blit(text, (width//2 - 150, height//2))
        
        # 显示阳光数量
        sun_text = font.render(f"阳光: {sun_count}", True, WHITE)
        screen.blit(sun_text, (width - 120, 10))
        
        pygame.display.flip()
        clock.tick(FPS)

if __name__ == "__main__":
    main()

posted @ 2025-06-21 22:25  叶柯鑫  阅读(55)  评论(0)    收藏  举报