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

浙公网安备 33010602011771号