植物大战僵尸

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

# 初始化pygame
pygame.init()

# 屏幕设置
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("植物大战僵尸简易版")

# 颜色定义
GREEN = (0, 255, 0)
BROWN = (139, 69, 19)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# 游戏参数
FPS = 60
clock = pygame.time.Clock()

# 草坪网格
GRID_SIZE = 80
GRID_ROWS = 5
GRID_COLS = 9
GRID_OFFSET_X = 50
GRID_OFFSET_Y = 100

# 植物类
class Plant:
    def __init__(self, row, col):
        self.row = row
        self.col = col
        self.health = 100
        self.x = GRID_OFFSET_X + col * GRID_SIZE
        self.y = GRID_OFFSET_Y + row * GRID_SIZE
        self.cooldown = 0
    
    def draw(self):
        pygame.draw.circle(screen, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
    
    def update(self):
        if self.cooldown > 0:
            self.cooldown -= 1
    
    def can_shoot(self):
        return self.cooldown == 0

# 豌豆射手类
class Peashooter(Plant):
    def __init__(self, row, col):
        super().__init__(row, col)
        self.cooldown_max = 60
    
    def shoot(self, projectiles):
        if self.can_shoot():
            projectiles.append(Projectile(self.row, self.col))
            self.cooldown = self.cooldown_max
    
    def draw(self):
        pygame.draw.circle(screen, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
        # 绘制豌豆射手头部
        pygame.draw.circle(screen, (0, 200, 0), (self.x + GRID_SIZE//2 + 15, self.y + GRID_SIZE//2 - 10), 15)

# 向日葵类
class Sunflower(Plant):
    def __init__(self, row, col):
        super().__init__(row, col)
        self.cooldown_max = 300  # 生产阳光的冷却时间
    
    def produce_sun(self, suns):
        if self.can_shoot():  # 复用can_shoot方法判断是否可以生产阳光
            suns.append(Sun(self.row, self.col))
            self.cooldown = self.cooldown_max
    
    def draw(self):
        pygame.draw.circle(screen, (255, 255, 0), (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
        # 绘制向日葵花瓣
        for i in range(8):
            angle = i * 45
            pygame.draw.ellipse(screen, (255, 200, 0), 
                               (self.x + GRID_SIZE//2 - 20 + 10 * pygame.math.Vector2(1, 0).rotate(angle).x,
                               self.y + GRID_SIZE//2 - 20 + 10 * pygame.math.Vector2(1, 0).rotate(angle).y,
                               40, 20))

# 阳光类
class Sun:
    def __init__(self, row, col):
        self.row = row
        self.col = col
        self.x = GRID_OFFSET_X + col * GRID_SIZE + random.randint(-20, 20)
        self.y = GRID_OFFSET_Y + row * GRID_SIZE + random.randint(-20, 20)
        self.target_y = self.y + random.randint(50, 150)
        self.speed = 1
        self.collected = False
        self.value = 25
        self.lifetime = 300  # 阳光存在时间
    
    def update(self):
        if self.y < self.target_y and not self.collected:
            self.y += self.speed
        self.lifetime -= 1
    
    def draw(self):
        if not self.collected and self.lifetime > 0:
            pygame.draw.circle(screen, (255, 255, 0), (self.x, self.y), 20)
            # 绘制阳光光芒
            for i in range(8):
                angle = i * 45
                start_pos = (self.x + 20 * pygame.math.Vector2(1, 0).rotate(angle).x,
                            self.y + 20 * pygame.math.Vector2(1, 0).rotate(angle).y)
                end_pos = (self.x + 30 * pygame.math.Vector2(1, 0).rotate(angle).x,
                          self.y + 30 * pygame.math.Vector2(1, 0).rotate(angle).y)
                pygame.draw.line(screen, (255, 200, 0), start_pos, end_pos, 3)

# 子弹类
class Projectile:
    def __init__(self, row, col):
        self.row = row
        self.col = col
        self.x = GRID_OFFSET_X + col * GRID_SIZE + GRID_SIZE
        self.y = GRID_OFFSET_Y + row * GRID_SIZE + GRID_SIZE//2
        self.speed = 5
        self.damage = 20
    
    def update(self):
        self.x += self.speed
    
    def draw(self):
        pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 10)
    
    def is_off_screen(self):
        return self.x > SCREEN_WIDTH

# 僵尸类
class Zombie:
    def __init__(self, row):
        self.row = row
        self.col = GRID_COLS
        self.x = SCREEN_WIDTH
        self.y = GRID_OFFSET_Y + row * GRID_SIZE
        self.speed = 0.5
        self.health = 100
        self.damage = 0.5
    
    def update(self):
        self.x -= self.speed
        self.col = int((self.x - GRID_OFFSET_X) / GRID_SIZE)
    
    def draw(self):
        # 绘制僵尸身体
        pygame.draw.rect(screen, (100, 100, 100), (self.x, self.y + 10, 40, 60))
        # 绘制僵尸头部
        pygame.draw.circle(screen, (150, 150, 150), (int(self.x + 20), int(self.y)), 20)
        # 绘制血条
        pygame.draw.rect(screen, RED, (self.x, self.y - 10, 40, 5))
        pygame.draw.rect(screen, GREEN, (self.x, self.y - 10, 40 * (self.health / 100), 5))  # 这里修复了括号
    
    def is_dead(self):
        return self.health <= 0
    
    def is_at_house(self):
        return self.x <= GRID_OFFSET_X

# 游戏主类
class Game:
    def __init__(self):
        self.plants = []
        self.zombies = []
        self.projectiles = []
        self.suns = []
        self.sun_count = 100
        self.selected_plant = None
        self.game_over = False
        self.wave_timer = 0
        self.wave_count = 0
        self.font = pygame.font.SysFont(None, 36)
    
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            
            if event.type == pygame.MOUSEBUTTONDOWN and not self.game_over:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                
                # 检查是否点击了阳光
                for sun in self.suns:
                    if (not sun.collected and sun.lifetime > 0 and 
                        (mouse_x - sun.x)**2 + (mouse_y - sun.y)**2 <= 400):  # 20^2
                        sun.collected = True
                        self.sun_count += sun.value
                
                # 检查是否点击了植物选择区域
                if 10 <= mouse_x <= 50 and 10 <= mouse_y <= 50:
                    self.selected_plant = "peashooter"
                elif 60 <= mouse_x <= 100 and 10 <= mouse_y <= 50:
                    self.selected_plant = "sunflower"
                
                # 检查是否在草坪上种植植物
                if (GRID_OFFSET_X <= mouse_x <= GRID_OFFSET_X + GRID_COLS * GRID_SIZE and
                    GRID_OFFSET_Y <= mouse_y <= GRID_OFFSET_Y + GRID_ROWS * GRID_SIZE):
                    
                    col = (mouse_x - GRID_OFFSET_X) // GRID_SIZE
                    row = (mouse_y - GRID_OFFSET_Y) // GRID_SIZE
                    
                    # 检查该位置是否已有植物
                    cell_empty = True
                    for plant in self.plants:
                        if plant.row == row and plant.col == col:
                            cell_empty = False
                            break
                    
                    if cell_empty and self.selected_plant:
                        if self.selected_plant == "peashooter" and self.sun_count >= 100:
                            self.plants.append(Peashooter(row, col))
                            self.sun_count -= 100
                        elif self.selected_plant == "sunflower" and self.sun_count >= 50:
                            self.plants.append(Sunflower(row, col))
                            self.sun_count -= 50
    
    def update(self):
        if self.game_over:
            return
        
        # 更新植物
        for plant in self.plants:
            plant.update()
            if isinstance(plant, Peashooter):
                # 检查该行是否有僵尸
                has_zombie = False
                for zombie in self.zombies:
                    if zombie.row == plant.row and zombie.col > plant.col:
                        has_zombie = True
                        break
                if has_zombie:
                    plant.shoot(self.projectiles)
            elif isinstance(plant, Sunflower):
                plant.produce_sun(self.suns)
        
        # 更新子弹
        for projectile in self.projectiles[:]:
            projectile.update()
            if projectile.is_off_screen():
                self.projectiles.remove(projectile)
                continue
            
            # 检查子弹是否击中僵尸
            for zombie in self.zombies:
                if (zombie.row == projectile.row and 
                    zombie.x <= projectile.x <= zombie.x + 40 and
                    zombie.y <= projectile.y <= zombie.y + 70):
                    zombie.health -= projectile.damage
                    if projectile in self.projectiles:
                        self.projectiles.remove(projectile)
                    break
        
        # 更新僵尸
        for zombie in self.zombies[:]:
            zombie.update()
            
            # 检查僵尸是否到达房子
            if zombie.is_at_house():
                self.game_over = True
            
            # 检查僵尸是否死亡
            if zombie.is_dead():
                self.zombies.remove(zombie)
                continue
            
            # 检查僵尸是否在吃植物
            for plant in self.plants[:]:
                if (zombie.row == plant.row and 
                    zombie.col == plant.col + 1):
                    plant.health -= zombie.damage
                    if plant.health <= 0:
                        self.plants.remove(plant)
        
        # 更新阳光
        for sun in self.suns[:]:
            sun.update()
            if sun.lifetime <= 0 or sun.collected:
                if sun in self.suns:
                    self.suns.remove(sun)
        
        # 生成僵尸波次
        self.wave_timer += 1
        if self.wave_timer >= 600:  # 每10秒一波
            self.wave_timer = 0
            self.wave_count += 1
            # 每波生成1-3个僵尸
            for _ in range(random.randint(1, min(3, self.wave_count))):
                self.zombies.append(Zombie(random.randint(0, GRID_ROWS - 1)))
    
    def draw(self):
        screen.fill(BLACK)
        
        # 绘制草坪网格
        for row in range(GRID_ROWS):
            for col in range(GRID_COLS):
                pygame.draw.rect(screen, (0, 100, 0) if (row + col) % 2 == 0 else (0, 80, 0),
                                 (GRID_OFFSET_X + col * GRID_SIZE, 
                                  GRID_OFFSET_Y + row * GRID_SIZE, 
                                  GRID_SIZE, GRID_SIZE), 0)
                pygame.draw.rect(screen, (0, 50, 0),
                                 (GRID_OFFSET_X + col * GRID_SIZE, 
                                  GRID_OFFSET_Y + row * GRID_SIZE, 
                                  GRID_SIZE, GRID_SIZE), 1)
        
        # 绘制植物选择区域
        pygame.draw.rect(screen, GREEN, (10, 10, 40, 40))
        pygame.draw.rect(screen, (255, 255, 0), (60, 10, 40, 40))
        
        # 绘制植物价格
        peashooter_text = self.font.render("100", True, WHITE)
        sunflower_text = self.font.render("50", True, WHITE)
        screen.blit(peashooter_text, (10, 50))
        screen.blit(sunflower_text, (60, 50))
        
        # 绘制当前阳光数量
        sun_text = self.font.render(f"阳光: {self.sun_count}", True, (255, 255, 0))
        screen.blit(sun_text, (SCREEN_WIDTH - 150, 10))
        
        # 绘制植物
        for plant in self.plants:
            plant.draw()
        
        # 绘制僵尸
        for zombie in self.zombies:
            zombie.draw()
        
        # 绘制子弹
        for projectile in self.projectiles:
            projectile.draw()
        
        # 绘制阳光
        for sun in self.suns:
            sun.draw()
        
        # 绘制选中的植物
        if self.selected_plant:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            if self.selected_plant == "peashooter":
                pygame.draw.circle(screen, GREEN, (mouse_x, mouse_y), 30)
            elif self.selected_plant == "sunflower":
                pygame.draw.circle(screen, (255, 255, 0), (mouse_x, mouse_y), 30)
        
        # 游戏结束画面
        if self.game_over:
            game_over_text = self.font.render("游戏结束! 按R键重新开始", True, RED)
            screen.blit(game_over_text, (SCREEN_WIDTH//2 - 150, SCREEN_HEIGHT//2))
        
        pygame.display.flip()

# 主游戏循环
def main():
    game = Game()
    
    while True:
        game.handle_events()
        game.update()
        game.draw()
        clock.tick(FPS)
        
        # 检查重新开始
        keys = pygame.key.get_pressed()
        if game.game_over and keys[pygame.K_r]:
            game = Game()

if __name__ == "__main__":
    main()
posted @ 2025-06-23 14:40  Lay“  阅读(15)  评论(0)    收藏  举报