植物大战僵尸

09

植物大战僵尸1

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

颜色定义

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)

游戏常量

LANES = 5
LANE_HEIGHT = SCREEN_HEIGHT // LANES
ZOMBIE_WIDTH = 60
ZOMBIE_HEIGHT = 80
PLANT_WIDTH = 50
PLANT_HEIGHT = 50
PEA_WIDTH = 10
PEA_HEIGHT = 10
SUN_WIDTH = 30
SUN_HEIGHT = 30
SUN_COST = 50
SUNFLOWER_COST = 50
PEASHOOTER_COST = 100

加载图片(这里用颜色块代替实际图片)

def draw_plant(screen, x, y, plant_type):
if plant_type == "sunflower":
pygame.draw.rect(screen, (255, 255, 0), (x, y, PLANT_WIDTH, PLANT_HEIGHT)) # 向日葵为黄色
elif plant_type == "peashooter":
pygame.draw.rect(screen, (0, 255, 0), (x, y, PLANT_WIDTH, PLANT_HEIGHT)) # 豌豆射手为绿色

def draw_zombie(screen, x, y, health):
# 僵尸的颜色根据生命值变化
health_ratio = health / 100
color = (255, int(255 * health_ratio), int(255 * health_ratio))
pygame.draw.rect(screen, color, (x, y, ZOMBIE_WIDTH, ZOMBIE_HEIGHT))

def draw_pea(screen, x, y):
pygame.draw.rect(screen, WHITE, (x, y, PEA_WIDTH, PEA_HEIGHT))

def draw_sun(screen, x, y):
pygame.draw.rect(screen, YELLOW, (x, y, SUN_WIDTH, SUN_HEIGHT))

植物类

class Plant:
def init(self, x, y, plant_type):
self.x = x
self.y = y
self.plant_type = plant_type
self.health = 100
self.sun_timer = 0
self.attack_timer = 0

def update(self):
    if self.plant_type == "sunflower":
        self.sun_timer += 1
        if self.sun_timer >= 300:  # 每300帧产生一次阳光
            self.sun_timer = 0
            return Sun(self.x + PLANT_WIDTH//2 - SUN_WIDTH//2, self.y - SUN_HEIGHT)
    elif self.plant_type == "peashooter":
        self.attack_timer += 1
        if self.attack_timer >= 100:  # 每100帧发射一次豌豆
            self.attack_timer = 0
            return Pea(self.x + PLANT_WIDTH, self.y + PLANT_HEIGHT//2 - PEA_HEIGHT//2, self.y // LANE_HEIGHT)
    return None

def draw(self, screen):
    draw_plant(screen, self.x, self.y, self.plant_type)

僵尸类

class Zombie:
def init(self, lane):
self.x = SCREEN_WIDTH
self.y = lane * LANE_HEIGHT + 10
self.health = 100
self.speed = 0.5

def update(self):
    self.x -= self.speed
    
def draw(self, screen):
    draw_zombie(screen, self.x, self.y, self.health)
    
def is_dead(self):
    return self.health <= 0

def is_in_lane(self, lane):
    return self.y // LANE_HEIGHT == lane

def collide_with_plant(self, plant):
    return (self.x < plant.x + PLANT_WIDTH and 
            self.x + ZOMBIE_WIDTH > plant.x and 
            self.y < plant.y + PLANT_HEIGHT and 
            self.y + ZOMBIE_HEIGHT > plant.y)

豌豆类

class Pea:
def init(self, x, y, lane):
self.x = x
self.y = y
self.lane = lane
self.speed = 2

def update(self):
    self.x += self.speed
    
def draw(self, screen):
    draw_pea(screen, self.x, self.y)
    
def collide_with_zombie(self, zombie):
    return (self.x < zombie.x + ZOMBIE_WIDTH and 
            self.x + PEA_WIDTH > zombie.x and 
            self.y < zombie.y + ZOMBIE_HEIGHT and 
            self.y + PEA_HEIGHT > zombie.y)
    
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(30, 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
    
def draw(self, screen):
    if not self.collected:
        draw_sun(screen, self.x, self.y)
        
def is_collected(self, mouse_pos):
    if not self.collected and self.timer > 0:
        mx, my = mouse_pos
        if (mx > self.x and mx < self.x + SUN_WIDTH and 
            my > self.y and my < self.y + SUN_HEIGHT):
            self.collected = True
            return True
    return False
    
def is_expired(self):
    return self.collected or self.timer <= 0

游戏类

class Game:
def init(self):
self.plants = []
self.zombies = []
self.peas = []
self.sunflowers = []
self.sun = 50
self.suns = []
self.selected_plant = None
self.score = 0
self.wave = 1
self.zombie_timer = 0
self.zombie_spawn_rate = 200 # 僵尸生成速率
self.game_over = False

def handle_event(self, event):
    if event.type == pygame.MOUSEBUTTONDOWN:
        mx, my = pygame.mouse.get_pos()
        
        # 检查是否点击了阳光
        for sun in self.suns:
            if sun.is_collected((mx, my)):
                self.sun += 25
                break
        
        # 检查是否选择了植物
        if my < 60:  # 顶部工具栏
            if 20 < mx < 90:  # 向日葵按钮
                if self.sun >= SUNFLOWER_COST:
                    self.selected_plant = "sunflower"
            elif 120 < mx < 190:  # 豌豆射手按钮
                if self.sun >= PEASHOOTER_COST:
                    self.selected_plant = "peashooter"
            else:
                self.selected_plant = None
        else:  # 放置植物
            if self.selected_plant:
                lane = my // LANE_HEIGHT
                grid_x = (mx // 50) * 50
                grid_y = lane * LANE_HEIGHT + 60
                
                # 检查是否可以放置植物
                can_place = True
                for plant in self.plants:
                    if (abs(plant.x - grid_x) < PLANT_WIDTH and 
                        abs(plant.y - grid_y) < PLANT_HEIGHT):
                        can_place = False
                        break
                
                if can_place:
                    if self.selected_plant == "sunflower" and self.sun >= SUNFLOWER_COST:
                        self.plants.append(Plant(grid_x, grid_y, "sunflower"))
                        self.sun -= SUNFLOWER_COST
                    elif self.selected_plant == "peashooter" and self.sun >= PEASHOOTER_COST:
                        self.plants.append(Plant(grid_x, grid_y, "peashooter"))
                        self.sun -= PEASHOOTER_COST
                    self.selected_plant = None

def update(self):
    if self.game_over:
        return
        
    # 更新阳光
    for sun in self.suns[:]:
        sun.update()
        if sun.is_expired():
            self.suns.remove(sun)
            
    # 随机生成阳光
    if random.random() < 0.01:
        lane = random.randint(0, LANES-1)
        x = random.randint(50, SCREEN_WIDTH-50)
        self.suns.append(Sun(x, 0))
            
    # 更新植物
    new_plants = []
    for plant in self.plants:
        new_object = plant.update()
        if new_object:
            if isinstance(new_object, Sun):
                self.suns.append(new_object)
            elif isinstance(new_object, Pea):
                self.peas.append(new_object)
                
        # 检查植物是否被僵尸吃掉
        alive = True
        for zombie in self.zombies:
            if zombie.collide_with_plant(plant):
                plant.health -= 0.5
                zombie.speed = 0  # 僵尸吃到植物时停止移动
                if plant.health <= 0:
                    alive = False
                    zombie.speed = 0.5  # 僵尸继续移动
                break
                
        if alive:
            new_plants.append(plant)
    self.plants = new_plants
            
    # 更新僵尸
    self.zombie_timer += 1
    if self.zombie_timer >= self.zombie_spawn_rate:
        self.zombie_timer = 0
        lane = random.randint(0, LANES-1)
        self.zombies.append(Zombie(lane))
        
        # 每波僵尸后增加难度
        if len(self.zombies) % 5 == 0:
            self.wave += 1
            if self.zombie_spawn_rate > 50:
                self.zombie_spawn_rate -= 10
            
    for zombie in self.zombies[:]:
        zombie.update()
        if zombie.x < 0:
            self.game_over = True
            break
        if zombie.is_dead():
            self.zombies.remove(zombie)
            self.score += 10
            
    # 更新豌豆
    for pea in self.peas[:]:
        pea.update()
        if pea.is_off_screen():
            self.peas.remove(pea)
            continue
            
        # 检查豌豆是否击中僵尸
        hit = False
        for zombie in self.zombies:
            if pea.collide_with_zombie(zombie) and pea.lane == zombie.y // LANE_HEIGHT:
                zombie.health -= 20
                self.peas.remove(pea)
                hit = True
                break
        if hit:
            continue
            
def draw(self, screen):
    # 绘制背景
    screen.fill((150, 200, 150))
    
    # 绘制车道分隔线
    for i in range(1, LANES):
        pygame.draw.line(screen, BLACK, (0, i * LANE_HEIGHT), (SCREEN_WIDTH, i * LANE_HEIGHT), 2)
        
    # 绘制顶部工具栏
    pygame.draw.rect(screen, (100, 100, 100), (0, 0, SCREEN_WIDTH, 60))
    
    # 绘制植物选择按钮
    pygame.draw.rect(screen, (200, 200, 200), (20, 10, 70, 40))
    pygame.draw.rect(screen, (200, 200, 200), (120, 10, 70, 40))
    font = pygame.font.SysFont("Arial", 16)
    screen.blit(font.render("向日葵 - 50", True, BLACK), (25, 20))
    screen.blit(font.render("豌豆射手 - 100", True, BLACK), (125, 20))
    
    # 绘制阳光数量
    screen.blit(font.render(f"阳光: {self.sun}", True, YELLOW), (250, 20))
    
    # 绘制分数和波数
    screen.blit(font.render(f"分数: {self.score}", True, WHITE), (400, 20))
    screen.blit(font.render(f"波数: {self.wave}", True, WHITE), (520, 20))
    
    # 绘制植物
    for plant in self.plants:
        plant.draw(screen)
        
    # 绘制僵尸
    for zombie in self.zombies:
        zombie.draw(screen)
        
    # 绘制豌豆
    for pea in self.peas:
        pea.draw(screen)
        
    # 绘制阳光
    for sun in self.suns:
        sun.draw(screen)
        
    # 绘制选中的植物
    if self.selected_plant:
        mx, my = pygame.mouse.get_pos()
        if my > 60:  # 不在工具栏区域
            draw_plant(screen, mx - PLANT_WIDTH//2, my - PLANT_HEIGHT//2, self.selected_plant)
            
    # 游戏结束画面
    if self.game_over:
        font = pygame.font.SysFont("Arial", 72)
        text = font.render("游戏结束", True, RED)
        text_rect = text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
        screen.blit(text, text_rect)
        
        font = pygame.font.SysFont("Arial", 36)
        score_text = font.render(f"最终分数: {self.score}", True, WHITE)
        score_rect = score_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 50))
        screen.blit(score_text, score_rect)
        
        restart_text = font.render("按R键重新开始", True, WHITE)
        restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 100))
        screen.blit(restart_text, restart_rect)
        
def restart(self):
    self.__init__()

主游戏循环

def main():
clock = pygame.time.Clock()
game = Game()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r and game.game_over:
                game.restart()
        else:
            game.handle_event(event)
            
    game.update()
    game.draw(screen)
    
    pygame.display.flip()
    clock.tick(60)
    
pygame.quit()
sys.exit()

if name == "main":
main()
屏幕截图 2025-06-27 205151

posted @ 2025-06-27 20:52  南萱  阅读(108)  评论(0)    收藏  举报