植物大战僵尸游戏开发

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

# 初始化pygame
pygame.init()

# 游戏常量
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 600
GRID_SIZE = 80
GRID_ROWS = 5
GRID_COLS = 9
LAWN_LEFT = 100
LAWN_TOP = 100
FPS = 60

# 颜色定义
GREEN = (50, 180, 50)
DARK_GREEN = (30, 120, 30)
BROWN = (150, 100, 50)
LIGHT_BROWN = (200, 150, 100)
YELLOW = (255, 255, 0)
RED = (255, 50, 50)
BLUE = (50, 150, 255)
PURPLE = (180, 50, 180)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SKY_BLUE = (135, 206, 235)
GRID_BG = (100, 200, 100, 150)

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("植物大战僵尸简化版")
clock = pygame.time.Clock()

# 字体
font = pygame.font.SysFont(None, 28)
big_font = pygame.font.SysFont(None, 48)

class Sun:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.target_y = y + 100
        self.speed = 1
        self.collected = False
        self.timer = 300  # 太阳存在时间
        
    def update(self):
        if self.y < self.target_y:
            self.y += self.speed
            
        self.timer -= 1
        if self.timer <= 0:
            return True
        return False
            
    def draw(self, surface):
        pygame.draw.circle(surface, YELLOW, (self.x, self.y), 20)
        pygame.draw.circle(surface, (255, 200, 0), (self.x, self.y), 15)
        
    def is_clicked(self, pos):
        distance = math.sqrt((pos[0] - self.x) ** 2 + (pos[1] - self.y) ** 2)
        return distance <= 20

class Plant:
    def __init__(self, row, col, plant_type):
        self.row = row
        self.col = col
        self.x = LAWN_LEFT + col * GRID_SIZE + GRID_SIZE // 2
        self.y = LAWN_TOP + row * GRID_SIZE + GRID_SIZE // 2
        self.health = 100
        self.plant_type = plant_type  # "sunflower" or "peashooter"
        self.shoot_timer = 0
        self.sun_timer = 0
        
    def update(self):
        if self.plant_type == "peashooter":
            self.shoot_timer += 1
            if self.shoot_timer >= 60:  # 每60帧发射一次
                self.shoot_timer = 0
                return True
        elif self.plant_type == "sunflower":
            self.sun_timer += 1
            if self.sun_timer >= 180:  # 每180帧产生一个太阳
                self.sun_timer = 0
                return True
        return False
        
    def draw(self, surface):
        if self.plant_type == "sunflower":
            # 绘制向日葵
            pygame.draw.circle(surface, (255, 200, 0), (self.x, self.y), 20)  # 花盘
            for i in range(8):
                angle = i * (2 * math.pi / 8)
                petal_x = self.x + 30 * math.cos(angle)
                petal_y = self.y + 30 * math.sin(angle)
                pygame.draw.circle(surface, YELLOW, (petal_x, petal_y), 15)
            pygame.draw.circle(surface, (200, 150, 0), (self.x, self.y), 10)
            
            # 绘制茎和叶
            pygame.draw.line(surface, GREEN, (self.x, self.y), (self.x, self.y + 30), 5)
            pygame.draw.ellipse(surface, GREEN, (self.x - 15, self.y + 10, 30, 15))
            
        elif self.plant_type == "peashooter":
            # 绘制豌豆射手
            pygame.draw.circle(surface, GREEN, (self.x, self.y), 20)  # 头部
            pygame.draw.circle(surface, DARK_GREEN, (self.x + 15, self.y), 8)  # 嘴巴
            pygame.draw.rect(surface, GREEN, (self.x - 15, self.y, 30, 40))  # 身体
            pygame.draw.rect(surface, DARK_GREEN, (self.x - 10, self.y + 40, 20, 20))  # 底部
            
        # 绘制血条
        bar_width = 40
        bar_height = 5
        pygame.draw.rect(surface, RED, (self.x - bar_width//2, self.y - 40, bar_width, bar_height))
        pygame.draw.rect(surface, (50, 200, 50), (self.x - bar_width//2, self.y - 40, bar_width * self.health // 100, bar_height))

class Pea:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.speed = 5
        self.damage = 25
        
    def update(self):
        self.x += self.speed
        return self.x > SCREEN_WIDTH
        
    def draw(self, surface):
        pygame.draw.circle(surface, GREEN, (self.x, self.y), 8)
        pygame.draw.circle(surface, DARK_GREEN, (self.x, self.y), 5)

class Zombie:
    def __init__(self, row):
        self.row = row
        self.x = SCREEN_WIDTH
        self.y = LAWN_TOP + row * GRID_SIZE + GRID_SIZE // 2
        self.speed = 0.5
        self.health = 100
        self.damage = 0.5
        self.attack_timer = 0
        self.attacking = False
        
    def update(self, plants):
        if not self.attacking:
            self.x -= self.speed
            
         # 检查是否与植物碰撞
        for plant in plants:
            if plant.row == self.row and abs(self.x - plant.x) < 40:
                self.attacking = True
                self.attack_timer += 1
                if self.attack_timer >= 30:  # 每30帧攻击一次
                    plant.health -= self.damage * 30
                    self.attack_timer = 0
                break
        else:
            self.attacking = False
            
        return self.x < 0 or self.health <= 0
        
    def draw(self, surface):
        # 绘制僵尸身体
        pygame.draw.rect(surface, (100, 100, 150), (self.x - 25, self.y - 40, 50, 60))
        pygame.draw.circle(surface, (150, 150, 200), (self.x, self.y - 45), 20)
        
        # 绘制僵尸眼睛
        pygame.draw.circle(surface, BLACK, (self.x - 5, self.y - 50), 5)
        pygame.draw.circle(surface, BLACK, (self.x + 10, self.y - 50), 5)
        
        # 绘制僵尸嘴巴
        pygame.draw.rect(surface, (200, 100, 100), (self.x - 15, self.y - 30, 30, 10))
        
        # 绘制血条
        bar_width = 50
        bar_height = 5
        pygame.draw.rect(surface, RED, (self.x - bar_width//2, self.y - 70, bar_width, bar_height))
        pygame.draw.rect(surface, (50, 200, 50), (self.x - bar_width//2, self.y - 70, bar_width * self.health // 100, bar_height))

class Game:
    def __init__(self):
        self.plants = []
        self.zombies = []
        self.peas = []
        self.suns = []
        self.sun_count = 100
        self.selected_plant = None
        self.zombie_spawn_timer = 0
        self.game_over = False
        self.wave = 1
        
    def spawn_zombie(self):
        row = random.randint(0, GRID_ROWS - 1)
        self.zombies.append(Zombie(row))
        
    def spawn_sun(self):
        x = random.randint(LAWN_LEFT, LAWN_LEFT + GRID_SIZE * GRID_COLS)
        self.suns.append(Sun(x, LAWN_TOP))
        
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
                
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                
                # 收集太阳
                for sun in self.suns[:]:
                    if sun.is_clicked(mouse_pos):
                        self.sun_count += 25
                        self.suns.remove(sun)
                        break
                
                # 选择植物
                if 20 <= mouse_pos[0] <= 70:
                    if 20 <= mouse_pos[1] <= 70 and self.sun_count >= 50:
                        self.selected_plant = "sunflower"
                    elif 90 <= mouse_pos[1] <= 140 and self.sun_count >= 100:
                        self.selected_plant = "peashooter"
                
                # 放置植物
                if self.selected_plant:
                    grid_x = (mouse_pos[0] - LAWN_LEFT) // GRID_SIZE
                    grid_y = (mouse_pos[1] - LAWN_TOP) // GRID_SIZE
                    
                    if 0 <= grid_x < GRID_COLS and 0 <= grid_y < GRID_ROWS:
                        # 检查该位置是否已有植物
                        position_empty = True
                        for plant in self.plants:
                            if plant.col == grid_x and plant.row == grid_y:
                                position_empty = False
                                break
                        
                        if position_empty:
                            if self.selected_plant == "sunflower":
                                self.plants.append(Plant(grid_y, grid_x, "sunflower"))
                                self.sun_count -= 50
                            elif self.selected_plant == "peashooter":
                                self.plants.append(Plant(grid_y, grid_x, "peashooter"))
                                self.sun_count -= 100
                            self.selected_plant = None
        
    def update(self):
        if self.game_over:
            return
        # 更新太阳
        for sun in self.suns[:]:
            if sun.update():
                self.suns.remove(sun)
                
        # 随机生成太阳
        if random.randint(0, 100) < 1 and len(self.suns) < 5:
            self.spawn_sun()
            
        # 更新植物
        for plant in self.plants[:]:
            if plant.health <= 0:
                self.plants.remove(plant)
                continue
                
            if plant.update():
                if plant.plant_type == "sunflower":
                    self.suns.append(Sun(plant.x, plant.y - 50))
                elif plant.plant_type == "peashooter":
                    self.peas.append(Pea(plant.x + 20, plant.y))
        
        # 更新豌豆
        for pea in self.peas[:]:
            if pea.update():
                self.peas.remove(pea)
                continue
                
            # 检查豌豆是否击中僵尸
            for zombie in self.zombies[:]:
                if zombie.row == (pea.y - LAWN_TOP) // GRID_SIZE and abs(pea.x - zombie.x) < 30:
                    zombie.health -= pea.damage
                    if zombie.health <= 0:
                        self.zombies.remove(zombie)
                    if pea in self.peas:
                        self.peas.remove(pea)
                    break
        
        # 更新僵尸
        for zombie in self.zombies[:]:
            if zombie.update(self.plants):
                if zombie.x < 0:  # 僵尸到达左边界
                    self.game_over = True
                elif zombie in self.zombies:  # 僵尸死亡
                    self.zombies.remove(zombie)
        
        # 生成僵尸
        self.zombie_spawn_timer += 1
        spawn_rate = max(100 - self.wave * 10, 30)
        if self.zombie_spawn_timer >= spawn_rate and len(self.zombies) < 5 + self.wave:
            self.spawn_zombie()
            self.zombie_spawn_timer = 0
            
        # 检查是否进入下一波
        if len(self.zombies) == 0 and self.zombie_spawn_timer > 300:
            self.wave += 1
            self.zombie_spawn_timer = 0
    
    def draw(self, surface):
        # 绘制背景
        surface.fill(SKY_BLUE)
        
        # 绘制标题
        title = big_font.render("植物大战僵尸 - 简化版", True, GREEN)
        surface.blit(title, (SCREEN_WIDTH // 2 - title.get_width() // 2, 20))
        
        # 绘制草坪
        pygame.draw.rect(surface, GREEN, (LAWN_LEFT - 10, LAWN_TOP - 10, 
                                         GRID_SIZE * GRID_COLS + 20, 
                                         GRID_SIZE * GRID_ROWS + 20))
        
        # 绘制网格
        for row in range(GRID_ROWS):
            for col in range(GRID_COLS):
                rect = pygame.Rect(LAWN_LEFT + col * GRID_SIZE, 
                                  LAWN_TOP + row * GRID_SIZE, 
                                  GRID_SIZE, GRID_SIZE)
                pygame.draw.rect(surface, GRID_BG, rect)
                pygame.draw.rect(surface, DARK_GREEN, rect, 1)
        # 绘制植物选择区域
        pygame.draw.rect(surface, LIGHT_BROWN, (10, 10, 300, 160))
        pygame.draw.rect(surface, BROWN, (10, 10, 300, 160), 3)
        
        # 绘制向日葵选择按钮
        pygame.draw.rect(surface, YELLOW if self.selected_plant == "sunflower" else (200, 200, 100), 
                        (20, 20, 50, 50))
        pygame.draw.rect(surface, BROWN, (20, 20, 50, 50), 2)
        pygame.draw.circle(surface, YELLOW, (45, 45), 20)
        sun_text = font.render("50", True, BLACK)
        surface.blit(sun_text, (75, 35))
        
        # 绘制豌豆射手选择按钮
        pygame.draw.rect(surface, GREEN if self.selected_plant == "peashooter" else (100, 200, 100), 
                        (20, 90, 50, 50))
        pygame.draw.rect(surface, BROWN, (20, 90, 50, 50), 2)
        pygame.draw.circle(surface, GREEN, (45, 115), 15)
        pea_text = font.render("100", True, BLACK)
        surface.blit(pea_text, (75, 105))
        
        # 绘制阳光计数
        pygame.draw.circle(surface, YELLOW, (200, 40), 25)
        sun_count_text = font.render(f": {self.sun_count}", True, BLACK)
        surface.blit(sun_count_text, (220, 30))
        
        # 绘制波数
        wave_text = font.render(f"波数: {self.wave}", True, BLACK)
        surface.blit(wave_text, (200, 80))
        
        # 绘制太阳
        for sun in self.suns:
            sun.draw(surface)
        
        # 绘制植物
        for plant in self.plants:
            plant.draw(surface)
            
        # 绘制豌豆
        for pea in self.peas:
            pea.draw(surface)
            
        # 绘制僵尸
        for zombie in self.zombies:
            zombie.draw(surface)
            
        # 游戏结束
        if self.game_over:
            overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
            overlay.set_alpha(150)
            overlay.fill(BLACK)
            surface.blit(overlay, (0, 0))
            
            game_over_text = big_font.render("游戏结束!", True, RED)
            surface.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, 
                                         SCREEN_HEIGHT // 2 - 50))
            
            restart_text = font.render("按R键重新开始", True, WHITE)
            surface.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, 
                                       SCREEN_HEIGHT // 2 + 20))
            
            keys = pygame.key.get_pressed()
            if keys[pygame.K_r]:
                self.__init__()

# 创建游戏实例
game = Game()

# 游戏主循环
while True:
    game.handle_events()
    game.update()
    game.draw(screen)
    
    pygame.display.flip()
    clock.tick(FPS)

posted @ 2025-06-22 21:30  佘婷婷  阅读(35)  评论(0)    收藏  举报