植物大战僵尸简化版

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。  阅读(81)  评论(0)    收藏  举报