植物大战僵尸简化版

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("植物大战僵尸简化版 - 2023")

颜色定义

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
LAWN_LEFT = 100
LAWN_TOP = 100

植物类

class Plant:
def init(self, row, col):
self.row = row
self.col = col
self.x = LAWN_LEFT + col * GRID_SIZE
self.y = LAWN_TOP + row * GRID_SIZE
self.health = 100
self.attack_cooldown = 0

def update(self):
    if self.attack_cooldown > 0:
        self.attack_cooldown -= 1

def draw(self, surface):
    pygame.draw.circle(surface, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
    # 显示生命值
    font = pygame.font.SysFont(None, 24)
    health_text = font.render(str(self.health), True, BLACK)
    surface.blit(health_text, (self.x + GRID_SIZE//2 - 10, self.y + GRID_SIZE//2 - 10))

豌豆射手类

class Peashooter(Plant):
def init(self, row, col):
super().init(row, col)
self.attack_speed = 60 # 攻击速度(帧)

def update(self, zombies, peas):
    super().update()
    
    # 检查同一行是否有僵尸
    zombies_in_row = [z for z in zombies if z.row == self.row and z.x > self.x]
    
    if zombies_in_row and self.attack_cooldown <= 0:
        peas.append(Pea(self.row, self.col))
        self.attack_cooldown = self.attack_speed

def draw(self, surface):
    pygame.draw.circle(surface, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
    # 绘制豌豆射手特征
    pygame.draw.rect(surface, (0, 100, 0), (self.x + GRID_SIZE//2 - 5, self.y + 10, 10, 20))
    # 显示生命值
    font = pygame.font.SysFont(None, 24)
    health_text = font.render(str(self.health), True, BLACK)
    surface.blit(health_text, (self.x + GRID_SIZE//2 - 10, self.y + GRID_SIZE//2 - 10))

向日葵类

class Sunflower(Plant):
def init(self, row, col):
super().init(row, col)
self.sun_production_time = 300 # 生产阳光的间隔(帧)
self.timer = 0

def update(self, suns):
    self.timer += 1
    if self.timer >= self.sun_production_time:
        suns.append(Sun(self.x + GRID_SIZE//2, self.y + GRID_SIZE//2))
        self.timer = 0

def draw(self, surface):
    pygame.draw.circle(surface, (255, 255, 0), (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
    # 绘制向日葵特征
    for i in range(8):
        angle = i * 45
        end_x = self.x + GRID_SIZE//2 + 40 * pygame.math.Vector2(1, 0).rotate(angle).x
        end_y = self.y + GRID_SIZE//2 + 40 * pygame.math.Vector2(1, 0).rotate(angle).y
        pygame.draw.line(surface, (255, 165, 0), 
                        (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 
                        (end_x, end_y), 5)
    # 显示生命值
    font = pygame.font.SysFont(None, 24)
    health_text = font.render(str(self.health), True, BLACK)
    surface.blit(health_text, (self.x + GRID_SIZE//2 - 10, self.y + GRID_SIZE//2 - 10))

豌豆类

class Pea:
def init(self, row, col):
self.row = row
self.col = col
self.x = LAWN_LEFT + (col + 1) * GRID_SIZE
self.y = LAWN_TOP + row * GRID_SIZE + GRID_SIZE//2
self.speed = 5
self.damage = 20

def update(self):
    self.x += self.speed

def draw(self, surface):
    pygame.draw.circle(surface, GREEN, (self.x, self.y), 10)

def is_off_screen(self):
    return self.x > SCREEN_WIDTH

def collides_with(self, zombie):
    return (self.row == zombie.row and 
            abs(self.x - zombie.x) < 30 and 
            abs(self.y - zombie.y) < 50)

阳光类

class Sun:
def init(self, x, y):
self.x = x
self.y = y
self.target_y = y + random.randint(50, 150)
self.speed = 1
self.lifetime = 300 # 帧数
self.collected = False

def update(self):
    if self.y < self.target_y:
        self.y += self.speed
    self.lifetime -= 1

def draw(self, surface):
    pygame.draw.circle(surface, (255, 255, 0), (self.x, self.y), 20)

def is_expired(self):
    return self.lifetime <= 0 or self.collected

def is_clicked(self, pos):
    distance = ((pos[0] - self.x) ** 2 + (pos[1] - self.y) ** 2) ** 0.5
    return distance <= 20

僵尸类

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.attack_cooldown = 0
self.attack_damage = 1
self.attack_speed = 30 # 帧

def update(self, plants):
    # 检查前方是否有植物
    plant_in_front = None
    for plant in plants:
        if plant.row == self.row and abs(plant.x - self.x) < GRID_SIZE:
            plant_in_front = plant
            break
    
    if plant_in_front:
        if self.attack_cooldown <= 0:
            plant_in_front.health -= self.attack_damage
            self.attack_cooldown = self.attack_speed
        else:
            self.attack_cooldown -= 1
    else:
        self.x -= self.speed

def draw(self, surface):
    # 绘制僵尸身体
    pygame.draw.rect(surface, (100, 100, 100), (self.x - 20, self.y - 40, 40, 80))
    # 绘制僵尸头
    pygame.draw.circle(surface, (150, 150, 150), (self.x, self.y - 50), 20)
    # 显示生命值
    font = pygame.font.SysFont(None, 24)
    health_text = font.render(str(self.health), True, WHITE)
    surface.blit(health_text, (self.x - 15, self.y - 60))

def is_off_screen(self):
    return self.x < -50

def is_dead(self):
    return self.health <= 0

游戏主类

class Game:
def init(self):
self.plants = []
self.zombies = []
self.peas = []
self.suns = []
self.sun_count = 100
self.zombie_timer = 0
self.zombie_spawn_time = 300 # 帧
self.selected_plant = None
self.game_over = False
self.font = pygame.font.SysFont(None, 36)

    # 植物选择区域
    self.plant_options = [
        {"type": "peashooter", "cost": 100, "rect": pygame.Rect(10, 100, 70, 70)},
        {"type": "sunflower", "cost": 50, "rect": pygame.Rect(10, 180, 70, 70)}
    ]

def handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            return False
        
        if event.type == pygame.MOUSEBUTTONDOWN:
            pos = pygame.mouse.get_pos()
            
            # 检查是否点击了阳光
            for sun in self.suns:
                if sun.is_clicked(pos):
                    sun.collected = True
                    self.sun_count += 25
            
            # 检查是否点击了植物选择区域
            for option in self.plant_options:
                if option["rect"].collidepoint(pos) and self.sun_count >= option["cost"]:
                    self.selected_plant = option["type"]
            
            # 检查是否在草坪上放置植物
            if self.selected_plant:
                col = (pos[0] - LAWN_LEFT) // GRID_SIZE
                row = (pos[1] - LAWN_TOP) // GRID_SIZE
                
                if 0 <= row < GRID_ROWS and 0 <= col < GRID_COLS:
                    cell_empty = True
                    for plant in self.plants:
                        if plant.row == row and plant.col == col:
                            cell_empty = False
                            break
                    
                    if cell_empty:
                        if self.selected_plant == "peashooter" and self.sun_count >= 100:
                            self.plants.append(Peashooter(row, col))
                            self.sun_count -= 100
                            self.selected_plant = None
                        elif self.selected_plant == "sunflower" and self.sun_count >= 50:
                            self.plants.append(Sunflower(row, col))
                            self.sun_count -= 50
                            self.selected_plant = None
    
    return True

def update(self):
    if self.game_over:
        return
    
    # 更新植物
    for plant in self.plants[:]:
        if isinstance(plant, Peashooter):
            plant.update(self.zombies, self.peas)
        elif isinstance(plant, Sunflower):
            plant.update(self.suns)
        
        if plant.health <= 0:
            self.plants.remove(plant)
    
    # 更新豌豆
    for pea in self.peas[:]:
        pea.update()
        
        # 检查豌豆是否击中僵尸
        for zombie in self.zombies:
            if pea.collides_with(zombie):
                zombie.health -= pea.damage
                if pea in self.peas:
                    self.peas.remove(pea)
                break
        
        if pea.is_off_screen() and pea in self.peas:
            self.peas.remove(pea)
    
    # 更新僵尸
    for zombie in self.zombies[:]:
        zombie.update(self.plants)
        
        if zombie.is_off_screen():
            self.game_over = True
        
        if zombie.is_dead():
            self.zombies.remove(zombie)
    
    # 更新阳光
    for sun in self.suns[:]:
        sun.update()
        if sun.is_expired():
            self.suns.remove(sun)
    
    # 生成僵尸
    self.zombie_timer += 1
    if self.zombie_timer >= self.zombie_spawn_time:
        row = random.randint(0, GRID_ROWS - 1)
        self.zombies.append(Zombie(row))
        self.zombie_timer = 0
        # 随着游戏进行,僵尸生成速度加快
        self.zombie_spawn_time = max(100, self.zombie_spawn_time - 5)

def draw(self, surface):
    surface.fill((200, 200, 200))
    
    # 绘制草坪网格
    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, (144, 238, 144), rect)
            pygame.draw.rect(surface, BLACK, rect, 1)
    
    # 绘制植物选择区域
    pygame.draw.rect(surface, (200, 200, 200), (0, 0, 90, SCREEN_HEIGHT))
    for option in self.plant_options:
        color = (0, 255, 0) if self.sun_count >= option["cost"] else (100, 100, 100)
        pygame.draw.rect(surface, color, option["rect"])
        pygame.draw.rect(surface, BLACK, option["rect"], 2)
        
        # 绘制植物图标
        if option["type"] == "peashooter":
            pygame.draw.circle(surface, GREEN, 
                               (option["rect"].x + option["rect"].width//2, 
                                option["rect"].y + option["rect"].height//2), 20)
            pygame.draw.rect(surface, (0, 100, 0), 
                           (option["rect"].x + option["rect"].width//2 - 5, 
                            option["rect"].y + 15, 10, 20))
        elif option["type"] == "sunflower":
            pygame.draw.circle(surface, (255, 255, 0), 
                             (option["rect"].x + option["rect"].width//2, 
                              option["rect"].y + option["rect"].height//2), 20)
        
        # 显示花费
        cost_text = self.font.render(str(option["cost"]), True, BLACK)
        surface.blit(cost_text, (option["rect"].x + 5, option["rect"].y + 5))
    
    # 绘制阳光计数
    sun_text = self.font.render(f"阳光: {self.sun_count}", True, BLACK)
    surface.blit(sun_text, (10, 10))
    
    # 绘制选中的植物
    if self.selected_plant:
        pos = pygame.mouse.get_pos()
        if self.selected_plant == "peashooter":
            pygame.draw.circle(surface, GREEN, pos, 30)
        elif self.selected_plant == "sunflower":
            pygame.draw.circle(surface, (255, 255, 0), pos, 30)
    
    # 绘制植物
    for plant in self.plants:
        plant.draw(surface)
    
    # 绘制豌豆
    for pea in self.peas:
        pea.draw(surface)
    
    # 绘制阳光
    for sun in self.suns:
        sun.draw(surface)
    
    # 绘制僵尸
    for zombie in self.zombies:
        zombie.draw(surface)
    
    # 游戏结束显示
    if self.game_over:
        game_over_text = self.font.render("游戏结束! 僵尸吃掉了你的脑子!", True, RED)
        surface.blit(game_over_text, (SCREEN_WIDTH//2 - 200, SCREEN_HEIGHT//2))
    
    # 绘制特殊标志
    signature = self.font.render("2023", True, BLACK)
    surface.blit(signature, (SCREEN_WIDTH - 50, SCREEN_HEIGHT - 30))
    
    pygame.display.flip()

def run(self):
    running = True
    while running:
        clock.tick(FPS)
        
        running = self.handle_events()
        self.update()
        self.draw(screen)
    
    pygame.quit()
    sys.exit()

运行游戏

if name == "main":
game = Game()
game.run()

posted @ 2025-06-21 14:03  Neflibata。  阅读(35)  评论(0)    收藏  举报