植物大战僵尸简易版

import pygame
import random
import sys

special_number = 3028

初始化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)
YELLOW = (255, 255, 0)

游戏参数

FPS = 60
clock = pygame.time.Clock()

草坪网格设置

GRID_SIZE = 80
GRID_COLS = 9
GRID_ROWS = 5
GRID_OFFSET_X = 50
GRID_OFFSET_Y = 100

植物类

class Plant:
def init(self, row, col):
self.row = row
self.col = col
self.x = GRID_OFFSET_X + col * GRID_SIZE
self.y = GRID_OFFSET_Y + 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)
    # 绘制血条
    pygame.draw.rect(surface, RED, (self.x, self.y - 10, GRID_SIZE, 5))
    pygame.draw.rect(surface, GREEN, (self.x, self.y - 10, GRID_SIZE * (self.health/100), 5))

豌豆射手类

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

def can_shoot(self):
    if self.attack_cooldown <= 0:
        self.attack_cooldown = self.attack_speed
        return True
    return False

def draw(self, surface):
    pygame.draw.circle(surface, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
    # 绘制枪管
    pygame.draw.rect(surface, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2 - 5, 30, 10))
    # 血条
    pygame.draw.rect(surface, RED, (self.x, self.y - 10, GRID_SIZE, 5))
    pygame.draw.rect(surface, GREEN, (self.x, self.y - 10, GRID_SIZE * (self.health/100), 5))

向日葵类

class Sunflower(Plant):
def init(self, row, col):
super().init(row, col)
self.sun_produce_cooldown = 200 # 生产阳光的冷却时间

def update(self):
    if self.sun_produce_cooldown > 0:
        self.sun_produce_cooldown -= 1
        return False
    else:
        self.sun_produce_cooldown = 200
        return True

def draw(self, surface):
    pygame.draw.circle(surface, YELLOW, (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, YELLOW, 
                        (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2),
                        (end_x, end_y), 5)
    # 血条
    pygame.draw.rect(surface, RED, (self.x, self.y - 10, GRID_SIZE, 5))
    pygame.draw.rect(surface, GREEN, (self.x, self.y - 10, GRID_SIZE * (self.health/100), 5))

豌豆类

class Pea:
def init(self, x, y):
self.x = x
self.y = y
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

阳光类

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, YELLOW, (self.x, self.y), 20)

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

僵尸类 (修改了速度)

class Zombie:
def init(self, row):
self.row = row
self.x = SCREEN_WIDTH
self.y = GRID_OFFSET_Y + row * GRID_SIZE + GRID_SIZE//2
self.speed = 0.5 + random.random() * 0.2 # 基础速度从1降到0.5,并添加随机波动
self.health = 100
self.damage = 0.5

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

def draw(self, surface):
    pygame.draw.rect(surface, BROWN, (self.x - 30, self.y - 50, 60, 80))
    # 绘制血条
    pygame.draw.rect(surface, RED, (self.x - 30, self.y - 70, 60, 10))
    pygame.draw.rect(surface, GREEN, (self.x - 30, self.y - 70, 60 * (self.health/100), 10))

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

def is_at_house(self):
    return self.x <= 30

植物卡片类

class PlantCard:
def init(self, x, y, plant_type, cost):
self.x = x
self.y = y
self.width = 80
self.height = 100
self.plant_type = plant_type
self.cost = cost
self.cooldown = 0
self.cooldown_max = 100 if plant_type == "peashooter" else 150

def draw(self, surface, sun_count, selected=False):
    # 绘制卡片背景
    color = (100, 100, 100) if sun_count < self.cost else (200, 200, 200)
    if selected:
        color = (255, 255, 0) if sun_count >= self.cost else (150, 150, 0)
    
    pygame.draw.rect(surface, color, (self.x, self.y, self.width, self.height))
    pygame.draw.rect(surface, (50, 50, 50), (self.x, self.y, self.width, self.height), 2)
    
    # 绘制植物图标
    if self.plant_type == "peashooter":
        pygame.draw.circle(surface, GREEN, (self.x + self.width//2, self.y + 40), 20)
        pygame.draw.rect(surface, GREEN, (self.x + self.width//2, self.y + 40 - 5, 20, 10))
    elif self.plant_type == "sunflower":
        pygame.draw.circle(surface, YELLOW, (self.x + self.width//2, self.y + 40), 20)
        for i in range(8):
            angle = i * 45
            end_x = self.x + self.width//2 + 25 * pygame.math.Vector2(1, 0).rotate(angle).x
            end_y = self.y + 40 + 25 * pygame.math.Vector2(1, 0).rotate(angle).y
            pygame.draw.line(surface, YELLOW, 
                            (self.x + self.width//2, self.y + 40),
                            (end_x, end_y), 3)
    
    # 绘制冷却效果
    if self.cooldown > 0:
        height = (self.cooldown / self.cooldown_max) * self.height
        s = pygame.Surface((self.width, height), pygame.SRCALPHA)
        s.fill((0, 0, 0, 180))
        surface.blit(s, (self.x, self.y))
    
    # 绘制阳光消耗
    font = pygame.font.SysFont(None, 24)
    cost_text = font.render(str(self.cost), True, YELLOW)
    surface.blit(cost_text, (self.x + 10, self.y + self.height - 25))

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

def is_clicked(self, pos):
    x, y = pos
    return (self.x <= x <= self.x + self.width and 
            self.y <= y <= self.y + self.height)

def is_ready(self, sun_count):
    return self.cooldown <= 0 and sun_count >= self.cost

游戏类

class Game:
def init(self):
self.plants = []
self.zombies = []
self.peas = []
self.suns = []
self.sun = 75 # 初始阳光值
self.zombie_spawn_cooldown = 0
self.font = pygame.font.SysFont(None, 36)
self.selected_plant = None
self.game_over = False

    # 创建植物卡片
    self.plant_cards = [
        PlantCard(10, 10, "peashooter", 100),
        PlantCard(100, 10, "sunflower", 50)
    ]

def add_plant(self, row, col, plant_type):
    # 检查该位置是否已有植物
    for plant in self.plants:
        if plant.row == row and plant.col == col:
            return False
    
    if plant_type == "peashooter":
        self.plants.append(Peashooter(row, col))
        return True
    elif plant_type == "sunflower":
        self.plants.append(Sunflower(row, col))
        return True
    return False

def add_zombie(self):
    row = random.randint(0, GRID_ROWS - 1)
    self.zombies.append(Zombie(row))

def add_sun(self, x=None, y=None):
    if x is None and y is None:
        # 随机位置生成阳光
        x = random.randint(50, SCREEN_WIDTH - 50)
        y = 0
    self.suns.append(Sun(x, y))

def update(self):
    if self.game_over:
        return
    
    # 更新植物卡片
    for card in self.plant_cards:
        card.update()
    
    # 更新植物
    for plant in self.plants:
        if isinstance(plant, Peashooter):
            plant.update()
            if plant.can_shoot():
                self.peas.append(Pea(plant.x + GRID_SIZE, plant.y + GRID_SIZE//2))
        elif isinstance(plant, Sunflower):
            if plant.update():  # 如果返回True,表示可以生产阳光
                self.add_sun(plant.x + GRID_SIZE//2, plant.y + GRID_SIZE//2)
    
    # 更新豌豆
    for pea in self.peas[:]:
        pea.update()
        if pea.is_off_screen():
            self.peas.remove(pea)
            continue
        
        # 检测豌豆是否击中僵尸
        for zombie in self.zombies:
            if (zombie.row == (pea.y - GRID_OFFSET_Y) // GRID_SIZE and 
                zombie.x - 30 <= pea.x <= zombie.x + 30):
                zombie.health -= pea.damage
                if pea in self.peas:
                    self.peas.remove(pea)
                break
    
    # 更新阳光
    for sun in self.suns[:]:
        sun.update()
        if sun.is_dead():
            self.suns.remove(sun)
    
    # 更新僵尸
    for zombie in self.zombies[:]:
        zombie.update()
        
        # 检测僵尸是否到达房子
        if zombie.is_at_house():
            self.game_over = True
            return
        
        # 检测僵尸是否死亡
        if zombie.is_dead():
            self.zombies.remove(zombie)
            self.sun += 25  # 杀死僵尸获得阳光
            continue
        
        # 检测僵尸是否碰到植物
        for plant in self.plants[:]:
            if (zombie.row == plant.row and 
                plant.x <= zombie.x - 30 <= plant.x + GRID_SIZE):
                plant.health -= zombie.damage
                if plant.health <= 0:
                    self.plants.remove(plant)
    
    # 随机生成僵尸 (增加了生成间隔)
    if self.zombie_spawn_cooldown <= 0:
        self.add_zombie()
        self.zombie_spawn_cooldown = random.randint(200, 400)  # 增加了生成间隔
    else:
        self.zombie_spawn_cooldown -= 1
    
    # 随机生成阳光
    if random.random() < 0.005:  # 0.5%的几率每帧增加阳光
        self.add_sun()

def draw(self, surface):
    # 绘制背景
    surface.fill(BLACK)
    
    # 绘制草坪网格
    for row in range(GRID_ROWS):
        for col in range(GRID_COLS):
            rect = pygame.Rect(
                GRID_OFFSET_X + col * GRID_SIZE,
                GRID_OFFSET_Y + row * GRID_SIZE,
                GRID_SIZE,
                GRID_SIZE
            )
            pygame.draw.rect(surface, (0, 100, 0) if (row + col) % 2 == 0 else (0, 120, 0), rect)
            pygame.draw.rect(surface, (50, 50, 50), rect, 1)
    
    # 绘制植物
    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)
    
    # 绘制阳光值
    sun_text = self.font.render(f"阳光: {self.sun}", True, WHITE)
    surface.blit(sun_text, (20, SCREEN_HEIGHT - 50))
    
    # 绘制植物卡片
    for card in self.plant_cards:
        selected = (self.selected_plant == card.plant_type)
        card.draw(surface, self.sun, selected)
    
    # 如果游戏结束,显示游戏结束文字
    if self.game_over:
        game_over_text = self.font.render("游戏结束! 按R键重新开始", True, RED)
        surface.blit(game_over_text, (SCREEN_WIDTH//2 - 180, SCREEN_HEIGHT//2))

def handle_click(self, pos):
    if self.game_over:
        return
    
    x, y = pos
    
    # 检查是否点击了阳光
    for sun in self.suns[:]:
        if ((sun.x - x)**2 + (sun.y - y)**2) <= 400:  # 20px半径内
            self.sun += 25
            sun.collected = True
            return
    
    # 检查是否点击了植物卡片
    for card in self.plant_cards:
        if card.is_clicked(pos) and card.is_ready(self.sun):
            self.selected_plant = card.plant_type
            card.cooldown = card.cooldown_max
            self.sun -= card.cost
            return
    
    # 检查是否点击了草坪网格
    if (GRID_OFFSET_X <= x <= GRID_OFFSET_X + GRID_COLS * GRID_SIZE and 
        GRID_OFFSET_Y <= y <= GRID_OFFSET_Y + GRID_ROWS * GRID_SIZE):
        col = (x - GRID_OFFSET_X) // GRID_SIZE
        row = (y - GRID_OFFSET_Y) // GRID_SIZE
        
        if self.selected_plant:
            if self.add_plant(row, col, self.selected_plant):
                self.selected_plant = None

def reset(self):
    self.__init__()

主游戏循环

def main():
game = Game()
running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            game.handle_click(event.pos)
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r and game.game_over:
                game.reset()
    
    game.update()
    game.draw(screen)
    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()
sys.exit()

if name == "main":
main()

posted @ 2025-06-17 16:20  鳞*  阅读(17)  评论(0)    收藏  举报