植物大战僵尸

import pygame
import random
import sys
import os

初始化pygame

pygame.init()

学号后四位特殊标志:3006

print("植物大战僵尸游戏 - 特殊标志:3006")

游戏常量

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_ROWS = 5
GRID_COLS = 9
CELL_WIDTH = SCREEN_WIDTH // GRID_COLS
CELL_HEIGHT = SCREEN_HEIGHT // GRID_ROWS
SUN_VALUE = 25
PLANT_SPAWN_DELAY = 10000 # 10秒
ZOMBIE_SPAWN_DELAY = 8000 # 8秒
BULLET_SPEED = 5
ZOMBIE_SPEED = 1
DAY = True

颜色定义

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BROWN = (139, 69, 19)
YELLOW = (255, 255, 0)
RED = (255, 0, 0)

创建游戏窗口

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("植物大战僵尸")

加载图片资源(这里使用简单的颜色块代替实际图片)

def load_image(name, size=(CELL_WIDTH, CELL_HEIGHT)):
try:
image = pygame.Surface(size)
if name == "sun":
image.fill(YELLOW)
pygame.draw.circle(image, (255, 255, 0), (size[0]//2, size[1]//2), size[0]//2)
pygame.draw.circle(image, (255, 255, 255), (size[0]//2, size[1]//2), size[0]//4)
elif name == "sunflower":
image.fill(GREEN)
pygame.draw.circle(image, YELLOW, (size[0]//2, size[1]//2), size[0]//3)
elif name == "peashooter":
image.fill(GREEN)
pygame.draw.rect(image, (0, 100, 0), (size[0]//2, size[1]//2, size[0]//3, size[0]//6))
elif name == "wallnut":
image.fill(BROWN)
pygame.draw.ellipse(image, (100, 50, 0), (size[0]//4, size[1]//4, size[0]//2, size[0]//2))
elif name == "zombie":
image.fill((128, 0, 0))
pygame.draw.rect(image, (100, 0, 0), (size[0]//4, size[1]//3, size[0]//2, size[0]//2))
pygame.draw.circle(image, (150, 0, 0), (size[0]//2, size[1]//4), size[0]//4)
elif name == "bullet":
image.fill((100, 200, 100))
pygame.draw.circle(image, (50, 150, 50), (size[0]//2, size[1]//2), size[0]//4)
return image
except pygame.error as e:
print(f"无法加载图片: {e}")
return pygame.Surface(size)

阳光类

class Sun:
def init(self, x, y):
self.image = load_image("sun")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.value = SUN_VALUE
self.collected = False
self.falling = True
self.speed = 1

def update(self):
    if self.falling:
        self.rect.y += self.speed
        if self.rect.y >= SCREEN_HEIGHT:
            self.collected = True
            
def draw(self, surface):
    if not self.collected:
        surface.blit(self.image, self.rect)

植物基类

class Plant:
def init(self, x, y, cost, health):
self.x = x
self.y = y
self.cost = cost
self.health = health
self.rect = pygame.Rect(x, y, CELL_WIDTH, CELL_HEIGHT)
self.planted = False

def update(self, zombies, bullets):
    pass
    
def draw(self, surface):
    pass
    
def take_damage(self, damage):
    self.health -= damage
    if self.health <= 0:
        return True
    return False

向日葵类

class Sunflower(Plant):
def init(self, x, y):
super().init(x, y, 50, 100)
self.image = load_image("sunflower")
self.sun_timer = 0
self.sun_interval = 20000 # 20秒生产一次阳光

def update(self, zombies, bullets):
    self.sun_timer += 1
    if self.sun_timer >= self.sun_interval:
        sun = Sun(self.x + CELL_WIDTH//2 - SUN_VALUE//2, self.y - CELL_HEIGHT)
        sun.falling = True
        suns.append(sun)
        self.sun_timer = 0
        
def draw(self, surface):
    if self.planted:
        surface.blit(self.image, self.rect)

豌豆射手类

class Peashooter(Plant):
def init(self, x, y):
super().init(x, y, 100, 100)
self.image = load_image("peashooter")
self.shoot_timer = 0
self.shoot_interval = 2000 # 2秒发射一次
self.bullet_damage = 20

def update(self, zombies, bullets):
    self.shoot_timer += 1
    if self.shoot_timer >= self.shoot_interval:
        # 检查同一行是否有僵尸
        for zombie in zombies:
            if zombie.row == self.y // CELL_HEIGHT and zombie.rect.x < self.rect.x + CELL_WIDTH:
                bullet = Bullet(self.rect.right, self.rect.centery - 10, self.bullet_damage)
                bullets.append(bullet)
                self.shoot_timer = 0
                break
                
def draw(self, surface):
    if self.planted:
        surface.blit(self.image, self.rect)

坚果墙类

class WallNut(Plant):
def init(self, x, y):
super().init(x, y, 50, 400)
self.image = load_image("wallnut")

def draw(self, surface):
    if self.planted:
        surface.blit(self.image, self.rect)

子弹类

class Bullet:
def init(self, x, y, damage):
self.image = load_image("bullet")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.damage = damage
self.speed = BULLET_SPEED

def update(self, zombies):
    self.rect.x += self.speed
    if self.rect.x > SCREEN_WIDTH:
        return True  # 子弹超出屏幕,移除
    
    # 检查与僵尸的碰撞
    for zombie in zombies:
        if self.rect.colliderect(zombie.rect):
            zombie.take_damage(self.damage)
            return True
    return False
    
def draw(self, surface):
    surface.blit(self.image, self.rect)

僵尸基类

class Zombie:
def init(self, x, y, health, damage):
self.image = load_image("zombie")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.health = health
self.damage = damage
self.speed = ZOMBIE_SPEED
self.row = y // CELL_HEIGHT

def update(self, plants):
    self.rect.x -= self.speed
    if self.rect.x < 0:
        return True  # 僵尸到达房子,游戏失败
    
    # 检查与植物的碰撞
    for plant in plants:
        if plant.planted and self.rect.colliderect(plant.rect):
            if plant.take_damage(self.damage):
                plants.remove(plant)
            return False
    return False
    
def draw(self, surface):
    surface.blit(self.image, self.rect)
    
def take_damage(self, damage):
    self.health -= damage
    if self.health <= 0:
        return True
    return False

普通僵尸

class NormalZombie(Zombie):
def init(self, y):
super().init(SCREEN_WIDTH, y, 100, 10)

路障僵尸

class ConeZombie(Zombie):
def init(self, y):
super().init(SCREEN_WIDTH, y, 200, 10)
# 路障僵尸图片可以在这里修改,这里简化处理

游戏类

class Game:
def init(self):
self.plants = []
self.zombies = []
self.bullets = []
self.suns = []
self.sun = 50
self.plant_selected = None
self.plant_types = {
"sunflower": Sunflower,
"peashooter": Peashooter,
"wallnut": WallNut
}
self.last_plant_time = 0
self.last_zombie_time = 0
self.game_over = False
self.victory = False
self.zombies_killed = 0
self.zombies_to_kill = 10
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont('simhei', 24)

def handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
            
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if not self.game_over and not self.victory:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                # 检查是否点击了阳光
                for sun in self.suns[:]:
                    if sun.rect.collidepoint(mouse_x, mouse_y):
                        self.sun += sun.value
                        self.suns.remove(sun)
                        break
                
                # 检查是否选择了植物
                if self.plant_selected and self.sun >= self.plant_types[self.plant_selected].__init__.__defaults__[2]:
                    grid_x = mouse_x // CELL_WIDTH
                    grid_y = mouse_y // CELL_HEIGHT
                    x = grid_x * CELL_WIDTH
                    y = grid_y * CELL_HEIGHT
                    
                    # 检查是否可以种植植物(在网格内且没有植物)
                    if 0 <= grid_x < GRID_COLS and 0 <= grid_y < GRID_ROWS:
                        can_plant = True
                        for plant in self.plants:
                            if plant.rect.collidepoint(x, y) and plant.planted:
                                can_plant = False
                                break
                        
                        if can_plant:
                            plant_class = self.plant_types[self.plant_selected]
                            plant = plant_class(x, y)
                            plant.planted = True
                            self.plants.append(plant)
                            self.sun -= plant.cost
                            self.plant_selected = None

def update(self):
    if self.game_over or self.victory:
        return
        
    # 更新阳光
    for sun in self.suns[:]:
        sun.update()
        if sun.collected:
            self.suns.remove(sun)
            
    # 随机生成阳光
    current_time = pygame.time.get_ticks()
    if current_time - self.last_plant_time > PLANT_SPAWN_DELAY:
        self.last_plant_time = current_time
        y = random.randint(0, GRID_ROWS - 1) * CELL_HEIGHT
        sun = Sun(random.randint(0, SCREEN_WIDTH - CELL_WIDTH), y - CELL_HEIGHT)
        self.suns.append(sun)
        
    # 生成僵尸
    if current_time - self.last_zombie_time > ZOMBIE_SPAWN_DELAY:
        self.last_zombie_time = current_time
        y = random.randint(0, GRID_ROWS - 1) * CELL_HEIGHT
        # 随机生成普通僵尸或路障僵尸
        if random.random() < 0.7:
            zombie = NormalZombie(y)
        else:
            zombie = ConeZombie(y)
        self.zombies.append(zombie)
        
    # 更新子弹
    for bullet in self.bullets[:]:
        if bullet.update(self.zombies):
            self.bullets.remove(bullet)
            
    # 更新僵尸
    for zombie in self.zombies[:]:
        if zombie.update(self.plants):
            if zombie.rect.x < 0:
                # 僵尸到达房子,减少生命值
                self.zombies.remove(zombie)
                # 这里应该有房子被攻击的逻辑
                self.game_over = True
            continue
        if zombie.take_damage(0):  # 检查僵尸是否被消灭
            self.zombies_killed += 1
            self.zombies.remove(zombie)
            
    # 更新植物
    for plant in self.plants[:]:
        plant.update(self.zombies, self.bullets)
        
    # 检查游戏胜利条件
    if self.zombies_killed >= self.zombies_to_kill:
        self.victory = True

def draw(self):
    # 绘制背景
    if DAY:
        screen.fill((100, 200, 100))  # 草地
    else:
        screen.fill((50, 50, 100))  # 夜晚
        
    # 绘制网格
    for i in range(GRID_ROWS + 1):
        pygame.draw.line(screen, (0, 0, 0), (0, i * CELL_HEIGHT), (SCREEN_WIDTH, i * CELL_HEIGHT), 1)
    for i in range(GRID_COLS + 1):
        pygame.draw.line(screen, (0, 0, 0), (i * CELL_WIDTH, 0), (i * CELL_WIDTH, SCREEN_HEIGHT), 1)
        
    # 绘制阳光
    for sun in self.suns:
        sun.draw(screen)
        
    # 绘制植物
    for plant in self.plants:
        plant.draw(screen)
        
    # 绘制子弹
    for bullet in self.bullets:
        bullet.draw(screen)
        
    # 绘制僵尸
    for zombie in self.zombies:
        zombie.draw(screen)
        
    # 绘制UI
    sun_text = self.font.render(f"阳光: {self.sun}", True, BLACK)
    screen.blit(sun_text, (10, 10))
    
    if self.plant_selected:
        plant_name = ""
        if self.plant_selected == "sunflower":
            plant_name = "向日葵"
        elif self.plant_selected == "peashooter":
            plant_name = "豌豆射手"
        elif self.plant_selected == "wallnut":
            plant_name = "坚果墙"
            
        plant_cost = self.plant_types[self.plant_selected].__init__.__defaults__[2]
        plant_text = self.font.render(f"选中: {plant_name} (消耗: {plant_cost})", True, BLACK)
        screen.blit(plant_text, (10, 40))
        
    # 绘制游戏状态
    if self.game_over:
        game_over_text = self.font.render("游戏结束! 僵尸吃掉了你的脑子!", True, RED)
        screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, 
                                    SCREEN_HEIGHT // 2 - 30))
        restart_text = self.font.render("按R键重新开始", True, BLACK)
        screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, 
                                   SCREEN_HEIGHT // 2 + 30))
                                   
    if self.victory:
        victory_text = self.font.render("胜利! 你成功抵御了僵尸入侵!", True, YELLOW)
        screen.blit(victory_text, (SCREEN_WIDTH // 2 - victory_text.get_width() // 2, 
                                   SCREEN_HEIGHT // 2 - 30))
        next_text = self.font.render("按N键进入下一关", True, BLACK)
        screen.blit(next_text, (SCREEN_WIDTH // 2 - next_text.get_width() // 2, 
                               SCREEN_HEIGHT // 2 + 30))
    
    pygame.display.flip()

def run(self):
    while True:
        self.handle_events()
        
        if self.game_over:
            keys = pygame.key.get_pressed()
            if keys[pygame.K_r]:
                self.__init__()  # 重新初始化游戏
                
        if self.victory:
            keys = pygame.key.get_pressed()
            if keys[pygame.K_n]:
                self.__init__()  # 下一关,这里简化为重新开始
                self.zombies_to_kill += 5  # 增加下一关的僵尸数量
        
        self.update()
        self.draw()
        self.clock.tick(60)

启动游戏

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

posted @ 2025-06-21 17:00  鳕鱼xx  阅读(55)  评论(0)    收藏  举报