点击查看代码
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("植物大战僵尸简易版")
# 颜色定义
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
GRID_OFFSET_X = 50
GRID_OFFSET_Y = 100
# 植物类
class Plant:
def __init__(self, row, col):
self.row = row
self.col = col
self.health = 100
self.x = GRID_OFFSET_X + col * GRID_SIZE
self.y = GRID_OFFSET_Y + row * GRID_SIZE
self.cooldown = 0
def draw(self):
pygame.draw.circle(screen, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
def update(self):
if self.cooldown > 0:
self.cooldown -= 1
def can_shoot(self):
return self.cooldown == 0
# 豌豆射手类
class Peashooter(Plant):
def __init__(self, row, col):
super().__init__(row, col)
self.cooldown_max = 60
def shoot(self, projectiles):
if self.can_shoot():
projectiles.append(Projectile(self.row, self.col))
self.cooldown = self.cooldown_max
def draw(self):
pygame.draw.circle(screen, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
# 绘制豌豆射手头部
pygame.draw.circle(screen, (0, 200, 0), (self.x + GRID_SIZE//2 + 15, self.y + GRID_SIZE//2 - 10), 15)
# 向日葵类
class Sunflower(Plant):
def __init__(self, row, col):
super().__init__(row, col)
self.cooldown_max = 300 # 生产阳光的冷却时间
def produce_sun(self, suns):
if self.can_shoot(): # 复用can_shoot方法判断是否可以生产阳光
suns.append(Sun(self.row, self.col))
self.cooldown = self.cooldown_max
def draw(self):
pygame.draw.circle(screen, (255, 255, 0), (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
# 绘制向日葵花瓣
for i in range(8):
angle = i * 45
pygame.draw.ellipse(screen, (255, 200, 0),
(self.x + GRID_SIZE//2 - 20 + 10 * pygame.math.Vector2(1, 0).rotate(angle).x,
self.y + GRID_SIZE//2 - 20 + 10 * pygame.math.Vector2(1, 0).rotate(angle).y,
40, 20))
# 阳光类
class Sun:
def __init__(self, row, col):
self.row = row
self.col = col
self.x = GRID_OFFSET_X + col * GRID_SIZE + random.randint(-20, 20)
self.y = GRID_OFFSET_Y + row * GRID_SIZE + random.randint(-20, 20)
self.target_y = self.y + random.randint(50, 150)
self.speed = 1
self.collected = False
self.value = 25
self.lifetime = 300 # 阳光存在时间
def update(self):
if self.y < self.target_y and not self.collected:
self.y += self.speed
self.lifetime -= 1
def draw(self):
if not self.collected and self.lifetime > 0:
pygame.draw.circle(screen, (255, 255, 0), (self.x, self.y), 20)
# 绘制阳光光芒
for i in range(8):
angle = i * 45
start_pos = (self.x + 20 * pygame.math.Vector2(1, 0).rotate(angle).x,
self.y + 20 * pygame.math.Vector2(1, 0).rotate(angle).y)
end_pos = (self.x + 30 * pygame.math.Vector2(1, 0).rotate(angle).x,
self.y + 30 * pygame.math.Vector2(1, 0).rotate(angle).y)
pygame.draw.line(screen, (255, 200, 0), start_pos, end_pos, 3)
# 子弹类
class Projectile:
def __init__(self, row, col):
self.row = row
self.col = col
self.x = GRID_OFFSET_X + col * GRID_SIZE + GRID_SIZE
self.y = GRID_OFFSET_Y + row * GRID_SIZE + GRID_SIZE//2
self.speed = 5
self.damage = 20
def update(self):
self.x += self.speed
def draw(self):
pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 10)
def is_off_screen(self):
return self.x > SCREEN_WIDTH
# 僵尸类
class Zombie:
def __init__(self, row):
self.row = row
self.col = GRID_COLS
self.x = SCREEN_WIDTH
self.y = GRID_OFFSET_Y + row * GRID_SIZE
self.speed = 0.5
self.health = 100
self.damage = 0.5
def update(self):
self.x -= self.speed
self.col = int((self.x - GRID_OFFSET_X) / GRID_SIZE)
def draw(self):
# 绘制僵尸身体
pygame.draw.rect(screen, (100, 100, 100), (self.x, self.y + 10, 40, 60))
# 绘制僵尸头部
pygame.draw.circle(screen, (150, 150, 150), (int(self.x + 20), int(self.y)), 20)
# 绘制血条
pygame.draw.rect(screen, RED, (self.x, self.y - 10, 40, 5))
pygame.draw.rect(screen, GREEN, (self.x, self.y - 10, 40 * (self.health / 100), 5)) # 这里修复了括号
def is_dead(self):
return self.health <= 0
def is_at_house(self):
return self.x <= GRID_OFFSET_X
# 游戏主类
class Game:
def __init__(self):
self.plants = []
self.zombies = []
self.projectiles = []
self.suns = []
self.sun_count = 100
self.selected_plant = None
self.game_over = False
self.wave_timer = 0
self.wave_count = 0
self.font = pygame.font.SysFont(None, 36)
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and not self.game_over:
mouse_x, mouse_y = pygame.mouse.get_pos()
# 检查是否点击了阳光
for sun in self.suns:
if (not sun.collected and sun.lifetime > 0 and
(mouse_x - sun.x)**2 + (mouse_y - sun.y)**2 <= 400): # 20^2
sun.collected = True
self.sun_count += sun.value
# 检查是否点击了植物选择区域
if 10 <= mouse_x <= 50 and 10 <= mouse_y <= 50:
self.selected_plant = "peashooter"
elif 60 <= mouse_x <= 100 and 10 <= mouse_y <= 50:
self.selected_plant = "sunflower"
# 检查是否在草坪上种植植物
if (GRID_OFFSET_X <= mouse_x <= GRID_OFFSET_X + GRID_COLS * GRID_SIZE and
GRID_OFFSET_Y <= mouse_y <= GRID_OFFSET_Y + GRID_ROWS * GRID_SIZE):
col = (mouse_x - GRID_OFFSET_X) // GRID_SIZE
row = (mouse_y - GRID_OFFSET_Y) // GRID_SIZE
# 检查该位置是否已有植物
cell_empty = True
for plant in self.plants:
if plant.row == row and plant.col == col:
cell_empty = False
break
if cell_empty and self.selected_plant:
if self.selected_plant == "peashooter" and self.sun_count >= 100:
self.plants.append(Peashooter(row, col))
self.sun_count -= 100
elif self.selected_plant == "sunflower" and self.sun_count >= 50:
self.plants.append(Sunflower(row, col))
self.sun_count -= 50
def update(self):
if self.game_over:
return
# 更新植物
for plant in self.plants:
plant.update()
if isinstance(plant, Peashooter):
# 检查该行是否有僵尸
has_zombie = False
for zombie in self.zombies:
if zombie.row == plant.row and zombie.col > plant.col:
has_zombie = True
break
if has_zombie:
plant.shoot(self.projectiles)
elif isinstance(plant, Sunflower):
plant.produce_sun(self.suns)
# 更新子弹
for projectile in self.projectiles[:]:
projectile.update()
if projectile.is_off_screen():
self.projectiles.remove(projectile)
continue
# 检查子弹是否击中僵尸
for zombie in self.zombies:
if (zombie.row == projectile.row and
zombie.x <= projectile.x <= zombie.x + 40 and
zombie.y <= projectile.y <= zombie.y + 70):
zombie.health -= projectile.damage
if projectile in self.projectiles:
self.projectiles.remove(projectile)
break
# 更新僵尸
for zombie in self.zombies[:]:
zombie.update()
# 检查僵尸是否到达房子
if zombie.is_at_house():
self.game_over = True
# 检查僵尸是否死亡
if zombie.is_dead():
self.zombies.remove(zombie)
continue
# 检查僵尸是否在吃植物
for plant in self.plants[:]:
if (zombie.row == plant.row and
zombie.col == plant.col + 1):
plant.health -= zombie.damage
if plant.health <= 0:
self.plants.remove(plant)
# 更新阳光
for sun in self.suns[:]:
sun.update()
if sun.lifetime <= 0 or sun.collected:
if sun in self.suns:
self.suns.remove(sun)
# 生成僵尸波次
self.wave_timer += 1
if self.wave_timer >= 600: # 每10秒一波
self.wave_timer = 0
self.wave_count += 1
# 每波生成1-3个僵尸
for _ in range(random.randint(1, min(3, self.wave_count))):
self.zombies.append(Zombie(random.randint(0, GRID_ROWS - 1)))
def draw(self):
screen.fill(BLACK)
# 绘制草坪网格
for row in range(GRID_ROWS):
for col in range(GRID_COLS):
pygame.draw.rect(screen, (0, 100, 0) if (row + col) % 2 == 0 else (0, 80, 0),
(GRID_OFFSET_X + col * GRID_SIZE,
GRID_OFFSET_Y + row * GRID_SIZE,
GRID_SIZE, GRID_SIZE), 0)
pygame.draw.rect(screen, (0, 50, 0),
(GRID_OFFSET_X + col * GRID_SIZE,
GRID_OFFSET_Y + row * GRID_SIZE,
GRID_SIZE, GRID_SIZE), 1)
# 绘制植物选择区域
pygame.draw.rect(screen, GREEN, (10, 10, 40, 40))
pygame.draw.rect(screen, (255, 255, 0), (60, 10, 40, 40))
# 绘制植物价格
peashooter_text = self.font.render("100", True, WHITE)
sunflower_text = self.font.render("50", True, WHITE)
screen.blit(peashooter_text, (10, 50))
screen.blit(sunflower_text, (60, 50))
# 绘制当前阳光数量
sun_text = self.font.render(f"阳光: {self.sun_count}", True, (255, 255, 0))
screen.blit(sun_text, (SCREEN_WIDTH - 150, 10))
# 绘制植物
for plant in self.plants:
plant.draw()
# 绘制僵尸
for zombie in self.zombies:
zombie.draw()
# 绘制子弹
for projectile in self.projectiles:
projectile.draw()
# 绘制阳光
for sun in self.suns:
sun.draw()
# 绘制选中的植物
if self.selected_plant:
mouse_x, mouse_y = pygame.mouse.get_pos()
if self.selected_plant == "peashooter":
pygame.draw.circle(screen, GREEN, (mouse_x, mouse_y), 30)
elif self.selected_plant == "sunflower":
pygame.draw.circle(screen, (255, 255, 0), (mouse_x, mouse_y), 30)
# 游戏结束画面
if self.game_over:
game_over_text = self.font.render("游戏结束! 按R键重新开始", True, RED)
screen.blit(game_over_text, (SCREEN_WIDTH//2 - 150, SCREEN_HEIGHT//2))
pygame.display.flip()
# 主游戏循环
def main():
game = Game()
while True:
game.handle_events()
game.update()
game.draw()
clock.tick(FPS)
# 检查重新开始
keys = pygame.key.get_pressed()
if game.game_over and keys[pygame.K_r]:
game = Game()
if __name__ == "__main__":
main()