点击查看代码
import pygame
import random
import sys
#学号后两位:07
# 初始化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)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)
# 游戏参数
FPS = 60
LANES = 5
LANE_HEIGHT = SCREEN_HEIGHT // LANES
SUN_COOLDOWN = 3000 # 阳光生成冷却时间(毫秒)
ZOMBIE_SPAWN_RATE = 5000 # 僵尸生成间隔(毫秒)
# 加载图片(使用简单的矩形代替真实图片)
class Images:
sunflower = pygame.Surface((50, 50))
sunflower.fill(YELLOW)
peashooter = pygame.Surface((50, 50))
peashooter.fill(GREEN)
zombie = pygame.Surface((60, 80))
zombie.fill(RED)
sun = pygame.Surface((30, 30))
sun.fill(YELLOW)
pea = pygame.Surface((10, 10))
pea.fill(YELLOW)
# 植物基类
class Plant(pygame.sprite.Sprite):
def __init__(self, x, y, cost, health=100):
super().__init__()
self.image = pygame.Surface((50, 50))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.cost = cost
self.health = health
self.cooldown = 0
self.last_attack = 0
def update(self, current_time):
if self.health <= 0:
self.kill()
# 向日葵类
class Sunflower(Plant):
def __init__(self, x, y):
super().__init__(x, y, 50)
self.image = Images.sunflower.copy()
self.sun_production_time = 5000 # 产生阳光的间隔(毫秒)
self.last_sun_time = pygame.time.get_ticks()
def update(self, current_time):
super().update(current_time)
if current_time - self.last_sun_time > self.sun_production_time:
return True
return False
# 豌豆射手类
class Peashooter(Plant):
def __init__(self, x, y):
super().__init__(x, y, 100)
self.image = Images.peashooter.copy()
self.attack_cooldown = 1500 # 攻击间隔(毫秒)
self.last_attack = pygame.time.get_ticks()
def can_shoot(self, current_time):
return current_time - self.last_attack > self.attack_cooldown
# 豌豆类
class Pea(pygame.sprite.Sprite):
def __init__(self, x, y, lane):
super().__init__()
self.image = Images.pea.copy()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y + LANE_HEIGHT // 2 - 5 # 居中放置豌豆
self.lane = lane
self.speed = 10
def update(self):
self.rect.x += self.speed
if self.rect.x > SCREEN_WIDTH:
self.kill()
# 僵尸类
class Zombie(pygame.sprite.Sprite):
def __init__(self, lane):
super().__init__()
self.image = Images.zombie.copy()
self.rect = self.image.get_rect()
self.rect.x = SCREEN_WIDTH
self.rect.y = lane * LANE_HEIGHT + 10
self.lane = lane
self.health = 200
self.speed = 1
self.attack_damage = 10
self.attack_cooldown = 1000
self.last_attack = 0
def update(self, current_time, plants):
if self.health <= 0:
self.kill()
return
# 检查是否有植物可以攻击
for plant in plants:
if (plant.rect.y // LANE_HEIGHT == self.lane and
self.rect.x <= plant.rect.x + 50 and
self.rect.x + 60 >= plant.rect.x):
if current_time - self.last_attack > self.attack_cooldown:
plant.health -= self.attack_damage
self.last_attack = current_time
return
# 没有植物可以攻击,继续移动
self.rect.x -= self.speed
# 阳光类
class Sun(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = Images.sun.copy()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.value = 25
self.target_y = y + random.randint(30, 100)
self.speed = 1
self.collected = False
self.collect_time = 0
def update(self, current_time):
if not self.collected:
if self.rect.y < self.target_y:
self.rect.y += self.speed
else:
# 阳光被收集后飞向阳光槽
dx = 50 - self.rect.x
dy = 50 - self.rect.y
distance = max(1, (dx**2 + dy**2)**0.5) # 避免除以零
self.rect.x += dx / distance * 8
self.rect.y += dy / distance * 8
if abs(self.rect.x - 50) < 5 and abs(self.rect.y - 50) < 5:
self.kill()
# 游戏类
class Game:
def __init__(self):
self.sun = 150
self.plants = pygame.sprite.Group()
self.zombies = pygame.sprite.Group()
self.peas = pygame.sprite.Group()
self.suns = pygame.sprite.Group()
self.selected_plant = None
self.clock = pygame.time.Clock()
self.last_sun_time = pygame.time.get_ticks()
self.last_zombie_time = pygame.time.get_ticks()
self.font = pygame.font.SysFont("Arial", 24)
self.running = True
def generate_sun(self, current_time):
if current_time - self.last_sun_time > SUN_COOLDOWN:
x = random.randint(100, SCREEN_WIDTH - 100)
y = random.randint(0, SCREEN_HEIGHT - 100)
self.suns.add(Sun(x, y))
self.last_sun_time = current_time
def spawn_zombie(self, current_time):
global ZOMBIE_SPAWN_RATE # 将global声明移到函数开始处
if current_time - self.last_zombie_time > ZOMBIE_SPAWN_RATE:
lane = random.randint(0, LANES - 1)
self.zombies.add(Zombie(lane))
self.last_zombie_time = current_time
# 随着时间增加,僵尸生成速度加快
ZOMBIE_SPAWN_RATE = max(1000, ZOMBIE_SPAWN_RATE - 10)
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = pygame.mouse.get_pos()
# 检查是否点击了阳光
sun_collected = False
for sun in self.suns:
if sun.rect.collidepoint(x, y) and not sun.collected:
sun.collected = True
self.sun += sun.value
sun_collected = True
break
# 检查是否点击了植物选择栏
if not sun_collected and y < 70:
if 100 <= x < 150 and self.sun >= 50:
self.selected_plant = "sunflower"
elif 200 <= x < 250 and self.sun >= 100:
self.selected_plant = "peashooter"
else:
self.selected_plant = None
# 检查是否种植植物
elif self.selected_plant and y >= 70:
lane = y // LANE_HEIGHT
plant_x = (x // 50) * 50
plant_y = lane * LANE_HEIGHT + 10
# 检查该位置是否已有植物
plant_exists = False
for plant in self.plants:
if (abs(plant.rect.x - plant_x) < 50 and
abs(plant.rect.y - plant_y) < 50):
plant_exists = True
break
if not plant_exists:
if self.selected_plant == "sunflower" and self.sun >= 50:
self.plants.add(Sunflower(plant_x, plant_y))
self.sun -= 50
elif self.selected_plant == "peashooter" and self.sun >= 100:
self.plants.add(Peashooter(plant_x, plant_y))
self.sun -= 100
def update(self):
current_time = pygame.time.get_ticks()
self.generate_sun(current_time)
self.spawn_zombie(current_time)
# 更新向日葵产生阳光
for plant in self.plants:
if isinstance(plant, Sunflower):
if plant.update(current_time):
self.suns.add(Sun(plant.rect.x, plant.rect.y))
plant.last_sun_time = current_time
elif isinstance(plant, Peashooter):
plant.update(current_time)
if plant.can_shoot(current_time):
# 检查该车道是否有僵尸
for zombie in self.zombies:
if zombie.lane == plant.rect.y // LANE_HEIGHT and zombie.rect.x < SCREEN_WIDTH:
self.peas.add(Pea(plant.rect.x + 50, plant.rect.y, plant.rect.y // LANE_HEIGHT))
plant.last_attack = current_time
break
# 更新僵尸攻击植物
for zombie in self.zombies:
zombie.update(current_time, self.plants)
# 更新豌豆和僵尸的碰撞
for pea in self.peas:
pea.update()
for zombie in self.zombies:
if (pea.lane == zombie.lane and
pea.rect.x > zombie.rect.x and
pea.rect.x < zombie.rect.x + zombie.rect.width):
zombie.health -= 50
pea.kill()
break
# 更新所有精灵
self.suns.update(current_time)
self.plants.update(current_time)
self.zombies.update(current_time, self.plants)
# 检查游戏是否结束
for zombie in self.zombies:
if zombie.rect.x < 50:
self.running = False
def draw(self):
screen.fill(WHITE)
# 绘制网格线
for i in range(LANES + 1):
pygame.draw.line(screen, BLACK, (0, i * LANE_HEIGHT), (SCREEN_WIDTH, i * LANE_HEIGHT), 1)
for i in range(SCREEN_WIDTH // 50 + 1):
pygame.draw.line(screen, BLACK, (i * 50, 70), (i * 50, SCREEN_HEIGHT), 1)
# 绘制阳光数量
sun_text = self.font.render(f"阳光: {self.sun}", True, BLACK)
screen.blit(sun_text, (10, 10))
# 绘制阳光槽
pygame.draw.rect(screen, YELLOW, (50, 50, 30, 30))
# 绘制植物选择栏
pygame.draw.rect(screen, GREEN, (100, 10, 50, 50))
screen.blit(Images.sunflower, (100, 10))
sunflower_text = self.font.render("50", True, BLACK)
screen.blit(sunflower_text, (100, 65))
pygame.draw.rect(screen, GREEN, (200, 10, 50, 50))
screen.blit(Images.peashooter, (200, 10))
peashooter_text = self.font.render("100", True, BLACK)
screen.blit(peashooter_text, (200, 65))
# 绘制选中的植物
if self.selected_plant:
x, y = pygame.mouse.get_pos()
if self.selected_plant == "sunflower":
screen.blit(Images.sunflower, (x - 25, y - 25))
elif self.selected_plant == "peashooter":
screen.blit(Images.peashooter, (x - 25, y - 25))
# 绘制所有精灵
self.suns.draw(screen)
self.plants.draw(screen)
self.zombies.draw(screen)
self.peas.draw(screen)
# 显示游戏状态
if not self.running:
game_over_text = self.font.render("游戏结束!", True, RED)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 - 12))
pygame.display.flip()
def run(self):
while self.running:
self.handle_events()
self.update()
self.draw()
self.clock.tick(FPS)
# 游戏结束画面
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN:
pygame.quit()
sys.exit()
game_over_text = self.font.render("游戏结束! 按任意键退出", True, RED)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 12))
pygame.display.flip()
self.clock.tick(FPS)
# 主程序
if __name__ == "__main__":
game = Game()
game.run()