用Python制作简易植物大战僵尸

点击查看代码
import pygame
import random
import sys

#学号后两位:07

# 初始化pygame
pygame.init()

# 游戏窗口设置
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("简易植物大战僵尸")

# 颜色定义
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)

# 游戏参数
FPS = 60
LANES = 5
LANE_HEIGHT = SCREEN_HEIGHT // LANES
SUN_COOLDOWN = 3000  # 阳光生成冷却时间(毫秒)
ZOMBIE_SPAWN_RATE = 5000  # 僵尸生成间隔(毫秒)

# 加载图片(使用简单的矩形代替真实图片)
class Images:
    sunflower = pygame.Surface((50, 50))
    sunflower.fill(YELLOW)
    
    peashooter = pygame.Surface((50, 50))
    peashooter.fill(GREEN)
    
    zombie = pygame.Surface((60, 80))
    zombie.fill(RED)
    
    sun = pygame.Surface((30, 30))
    sun.fill(YELLOW)
    
    pea = pygame.Surface((10, 10))
    pea.fill(YELLOW)

# 植物基类
class Plant(pygame.sprite.Sprite):
    def __init__(self, x, y, cost, health=100):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.cost = cost
        self.health = health
        self.cooldown = 0
        self.last_attack = 0

    def update(self, current_time):
        if self.health <= 0:
            self.kill()

# 向日葵类
class Sunflower(Plant):
    def __init__(self, x, y):
        super().__init__(x, y, 50)
        self.image = Images.sunflower.copy()
        self.sun_production_time = 5000  # 产生阳光的间隔(毫秒)
        self.last_sun_time = pygame.time.get_ticks()

    def update(self, current_time):
        super().update(current_time)
        if current_time - self.last_sun_time > self.sun_production_time:
            return True
        return False

# 豌豆射手类
class Peashooter(Plant):
    def __init__(self, x, y):
        super().__init__(x, y, 100)
        self.image = Images.peashooter.copy()
        self.attack_cooldown = 1500  # 攻击间隔(毫秒)
        self.last_attack = pygame.time.get_ticks()

    def can_shoot(self, current_time):
        return current_time - self.last_attack > self.attack_cooldown

# 豌豆类
class Pea(pygame.sprite.Sprite):
    def __init__(self, x, y, lane):
        super().__init__()
        self.image = Images.pea.copy()
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y + LANE_HEIGHT // 2 - 5  # 居中放置豌豆
        self.lane = lane
        self.speed = 10

    def update(self):
        self.rect.x += self.speed
        if self.rect.x > SCREEN_WIDTH:
            self.kill()

# 僵尸类
class Zombie(pygame.sprite.Sprite):
    def __init__(self, lane):
        super().__init__()
        self.image = Images.zombie.copy()
        self.rect = self.image.get_rect()
        self.rect.x = SCREEN_WIDTH
        self.rect.y = lane * LANE_HEIGHT + 10
        self.lane = lane
        self.health = 200
        self.speed = 1
        self.attack_damage = 10
        self.attack_cooldown = 1000
        self.last_attack = 0

    def update(self, current_time, plants):
        if self.health <= 0:
            self.kill()
            return

        # 检查是否有植物可以攻击
        for plant in plants:
            if (plant.rect.y // LANE_HEIGHT == self.lane and
                self.rect.x <= plant.rect.x + 50 and
                self.rect.x + 60 >= plant.rect.x):
                if current_time - self.last_attack > self.attack_cooldown:
                    plant.health -= self.attack_damage
                    self.last_attack = current_time
                return

        # 没有植物可以攻击,继续移动
        self.rect.x -= self.speed

# 阳光类
class Sun(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = Images.sun.copy()
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.value = 25
        self.target_y = y + random.randint(30, 100)
        self.speed = 1
        self.collected = False
        self.collect_time = 0

    def update(self, current_time):
        if not self.collected:
            if self.rect.y < self.target_y:
                self.rect.y += self.speed
        else:
            # 阳光被收集后飞向阳光槽
            dx = 50 - self.rect.x
            dy = 50 - self.rect.y
            distance = max(1, (dx**2 + dy**2)**0.5)  # 避免除以零
            self.rect.x += dx / distance * 8
            self.rect.y += dy / distance * 8
            
            if abs(self.rect.x - 50) < 5 and abs(self.rect.y - 50) < 5:
                self.kill()

# 游戏类
class Game:
    def __init__(self):
        self.sun = 150
        self.plants = pygame.sprite.Group()
        self.zombies = pygame.sprite.Group()
        self.peas = pygame.sprite.Group()
        self.suns = pygame.sprite.Group()
        self.selected_plant = None
        self.clock = pygame.time.Clock()
        self.last_sun_time = pygame.time.get_ticks()
        self.last_zombie_time = pygame.time.get_ticks()
        self.font = pygame.font.SysFont("Arial", 24)
        self.running = True

    def generate_sun(self, current_time):
        if current_time - self.last_sun_time > SUN_COOLDOWN:
            x = random.randint(100, SCREEN_WIDTH - 100)
            y = random.randint(0, SCREEN_HEIGHT - 100)
            self.suns.add(Sun(x, y))
            self.last_sun_time = current_time

    def spawn_zombie(self, current_time):
        global ZOMBIE_SPAWN_RATE  # 将global声明移到函数开始处
        if current_time - self.last_zombie_time > ZOMBIE_SPAWN_RATE:
            lane = random.randint(0, LANES - 1)
            self.zombies.add(Zombie(lane))
            self.last_zombie_time = current_time
            # 随着时间增加,僵尸生成速度加快
            ZOMBIE_SPAWN_RATE = max(1000, ZOMBIE_SPAWN_RATE - 10)

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                # 检查是否点击了阳光
                sun_collected = False
                for sun in self.suns:
                    if sun.rect.collidepoint(x, y) and not sun.collected:
                        sun.collected = True
                        self.sun += sun.value
                        sun_collected = True
                        break
                # 检查是否点击了植物选择栏
                if not sun_collected and y < 70:
                    if 100 <= x < 150 and self.sun >= 50:
                        self.selected_plant = "sunflower"
                    elif 200 <= x < 250 and self.sun >= 100:
                        self.selected_plant = "peashooter"
                    else:
                        self.selected_plant = None
                # 检查是否种植植物
                elif self.selected_plant and y >= 70:
                    lane = y // LANE_HEIGHT
                    plant_x = (x // 50) * 50
                    plant_y = lane * LANE_HEIGHT + 10
                    
                    # 检查该位置是否已有植物
                    plant_exists = False
                    for plant in self.plants:
                        if (abs(plant.rect.x - plant_x) < 50 and
                            abs(plant.rect.y - plant_y) < 50):
                            plant_exists = True
                            break
                    
                    if not plant_exists:
                        if self.selected_plant == "sunflower" and self.sun >= 50:
                            self.plants.add(Sunflower(plant_x, plant_y))
                            self.sun -= 50
                        elif self.selected_plant == "peashooter" and self.sun >= 100:
                            self.plants.add(Peashooter(plant_x, plant_y))
                            self.sun -= 100

    def update(self):
        current_time = pygame.time.get_ticks()
        self.generate_sun(current_time)
        self.spawn_zombie(current_time)

        # 更新向日葵产生阳光
        for plant in self.plants:
            if isinstance(plant, Sunflower):
                if plant.update(current_time):
                    self.suns.add(Sun(plant.rect.x, plant.rect.y))
                    plant.last_sun_time = current_time
            elif isinstance(plant, Peashooter):
                plant.update(current_time)
                if plant.can_shoot(current_time):
                    # 检查该车道是否有僵尸
                    for zombie in self.zombies:
                        if zombie.lane == plant.rect.y // LANE_HEIGHT and zombie.rect.x < SCREEN_WIDTH:
                            self.peas.add(Pea(plant.rect.x + 50, plant.rect.y, plant.rect.y // LANE_HEIGHT))
                            plant.last_attack = current_time
                            break

        # 更新僵尸攻击植物
        for zombie in self.zombies:
            zombie.update(current_time, self.plants)

        # 更新豌豆和僵尸的碰撞
        for pea in self.peas:
            pea.update()
            for zombie in self.zombies:
                if (pea.lane == zombie.lane and
                    pea.rect.x > zombie.rect.x and
                    pea.rect.x < zombie.rect.x + zombie.rect.width):
                    zombie.health -= 50
                    pea.kill()
                    break

        # 更新所有精灵
        self.suns.update(current_time)
        self.plants.update(current_time)
        self.zombies.update(current_time, self.plants)

        # 检查游戏是否结束
        for zombie in self.zombies:
            if zombie.rect.x < 50:
                self.running = False

    def draw(self):
        screen.fill(WHITE)
        
        # 绘制网格线
        for i in range(LANES + 1):
            pygame.draw.line(screen, BLACK, (0, i * LANE_HEIGHT), (SCREEN_WIDTH, i * LANE_HEIGHT), 1)
        for i in range(SCREEN_WIDTH // 50 + 1):
            pygame.draw.line(screen, BLACK, (i * 50, 70), (i * 50, SCREEN_HEIGHT), 1)
        
        # 绘制阳光数量
        sun_text = self.font.render(f"阳光: {self.sun}", True, BLACK)
        screen.blit(sun_text, (10, 10))
        
        # 绘制阳光槽
        pygame.draw.rect(screen, YELLOW, (50, 50, 30, 30))
        
        # 绘制植物选择栏
        pygame.draw.rect(screen, GREEN, (100, 10, 50, 50))
        screen.blit(Images.sunflower, (100, 10))
        sunflower_text = self.font.render("50", True, BLACK)
        screen.blit(sunflower_text, (100, 65))
        
        pygame.draw.rect(screen, GREEN, (200, 10, 50, 50))
        screen.blit(Images.peashooter, (200, 10))
        peashooter_text = self.font.render("100", True, BLACK)
        screen.blit(peashooter_text, (200, 65))
        
        # 绘制选中的植物
        if self.selected_plant:
            x, y = pygame.mouse.get_pos()
            if self.selected_plant == "sunflower":
                screen.blit(Images.sunflower, (x - 25, y - 25))
            elif self.selected_plant == "peashooter":
                screen.blit(Images.peashooter, (x - 25, y - 25))
        
        # 绘制所有精灵
        self.suns.draw(screen)
        self.plants.draw(screen)
        self.zombies.draw(screen)
        self.peas.draw(screen)
        
        # 显示游戏状态
        if not self.running:
            game_over_text = self.font.render("游戏结束!", True, RED)
            screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 - 12))
        
        pygame.display.flip()

    def run(self):
        while self.running:
            self.handle_events()
            self.update()
            self.draw()
            self.clock.tick(FPS)
        
        # 游戏结束画面
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN:
                    pygame.quit()
                    sys.exit()
            
            game_over_text = self.font.render("游戏结束! 按任意键退出", True, RED)
            screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 12))
            pygame.display.flip()
            self.clock.tick(FPS)

# 主程序
if __name__ == "__main__":
    game = Game()
    game.run()    
posted @ 2025-06-22 18:56  兜雨  阅读(75)  评论(0)    收藏  举报