点击查看代码
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("植物大战僵尸简化版 - 学号后四位: 3034")
# 颜色定义
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BROWN = (139, 69, 19)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
# 游戏参数
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.health = 100
self.x = LAWN_LEFT + col * GRID_SIZE
self.y = LAWN_TOP + row * GRID_SIZE
self.attack_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.attack_cooldown > 0:
self.attack_cooldown -= 1
def can_attack(self):
return self.attack_cooldown == 0
def attack(self):
self.attack_cooldown = 60 # 1秒冷却
return Projectile(self.row, self.col)
# 豌豆射手
class Peashooter(Plant):
def __init__(self, row, col):
super().__init__(row, col)
self.health = 150
def draw(self):
pygame.draw.circle(screen, GREEN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
pygame.draw.circle(screen, BLACK, (self.x + GRID_SIZE//2 + 15, self.y + GRID_SIZE//2 - 10), 5)
# 向日葵
class Sunflower(Plant):
def __init__(self, row, col):
super().__init__(row, col)
self.health = 100
self.sun_cooldown = 0
def draw(self):
pygame.draw.circle(screen, (255, 255, 0), (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
def update(self):
super().update()
if self.sun_cooldown > 0:
self.sun_cooldown -= 1
else:
self.sun_cooldown = 300 # 5秒产生阳光
return Sun(self.x, self.y)
return None
# 坚果墙
class WallNut(Plant):
def __init__(self, row, col):
super().__init__(row, col)
self.health = 400
def draw(self):
pygame.draw.circle(screen, BROWN, (self.x + GRID_SIZE//2, self.y + GRID_SIZE//2), 30)
# 僵尸类
class Zombie:
def __init__(self, row):
self.row = row
self.col = GRID_COLS - 1
self.x = LAWN_LEFT + self.col * GRID_SIZE
self.y = LAWN_TOP + row * GRID_SIZE
self.health = 200
self.speed = 0.5
self.attack_cooldown = 0
def draw(self):
pygame.draw.rect(screen, RED, (self.x, self.y, GRID_SIZE, GRID_SIZE))
def update(self, plants):
# 检查前方是否有植物
attacking = False
for plant in plants:
if plant.row == self.row and plant.col == self.col:
attacking = True
if self.attack_cooldown == 0:
plant.health -= 10
self.attack_cooldown = 30
else:
self.attack_cooldown -= 1
break
if not attacking:
self.x -= self.speed
self.col = int((self.x - LAWN_LEFT) / GRID_SIZE)
return self.x < LAWN_LEFT # 是否到达最左边(游戏失败)
# 阳光类
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.collected = False
self.value = 25
def draw(self):
pygame.draw.circle(screen, (255, 255, 0), (self.x + GRID_SIZE//2, self.y), 20)
def update(self):
if self.y < self.target_y:
self.y += self.speed
return self.collected
# 豌豆子弹
class Projectile:
def __init__(self, row, col):
self.row = row
self.col = col
self.x = LAWN_LEFT + col * GRID_SIZE + GRID_SIZE
self.y = LAWN_TOP + row * GRID_SIZE + GRID_SIZE//2
self.speed = 5
self.damage = 20
def draw(self):
pygame.draw.circle(screen, GREEN, (self.x, self.y), 5)
def update(self):
self.x += self.speed
return self.x > SCREEN_WIDTH # 是否飞出屏幕
# 游戏主类
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.zombie_spawn_timer = 0
self.font = pygame.font.SysFont(None, 36)
def draw_lawn(self):
# 绘制草坪网格
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(screen, (144, 238, 144), rect, 1)
def draw_ui(self):
# 绘制阳光数量
sun_text = self.font.render(f"阳光: {self.sun_count}", True, BLACK)
screen.blit(sun_text, (20, 20))
# 绘制植物选择菜单
pygame.draw.rect(screen, GREEN, (20, 60, 60, 60))
pygame.draw.rect(screen, (255, 255, 0), (90, 60, 60, 60))
pygame.draw.rect(screen, BROWN, (160, 60, 60, 60))
# 显示游戏结束
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))
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
# 检查是否点击了植物选择菜单
if 20 <= mouse_x <= 80 and 60 <= mouse_y <= 120:
self.selected_plant = "peashooter"
elif 90 <= mouse_x <= 150 and 60 <= mouse_y <= 120:
self.selected_plant = "sunflower"
elif 160 <= mouse_x <= 220 and 60 <= mouse_y <= 120:
self.selected_plant = "wallnut"
# 检查是否点击了草坪
if (LAWN_LEFT <= mouse_x <= LAWN_LEFT + GRID_COLS * GRID_SIZE and
LAWN_TOP <= mouse_y <= LAWN_TOP + GRID_ROWS * GRID_SIZE):
col = (mouse_x - LAWN_LEFT) // GRID_SIZE
row = (mouse_y - LAWN_TOP) // GRID_SIZE
# 检查该位置是否已有植物
position_empty = True
for plant in self.plants:
if plant.row == row and plant.col == col:
position_empty = False
break
if position_empty and self.selected_plant:
cost = 0
if self.selected_plant == "peashooter":
cost = 100
elif self.selected_plant == "sunflower":
cost = 50
elif self.selected_plant == "wallnut":
cost = 75
if self.sun_count >= cost:
self.sun_count -= cost
if self.selected_plant == "peashooter":
self.plants.append(Peashooter(row, col))
elif self.selected_plant == "sunflower":
self.plants.append(Sunflower(row, col))
elif self.selected_plant == "wallnut":
self.plants.append(WallNut(row, col))
# 检查是否点击了阳光
for sun in self.suns:
if (abs(mouse_x - (sun.x + GRID_SIZE//2)) < 20 and
abs(mouse_y - sun.y) < 20):
sun.collected = True
self.sun_count += sun.value
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and self.game_over:
self.__init__() # 重置游戏
def update(self):
if self.game_over:
return
# 生成僵尸
self.zombie_spawn_timer += 1
if self.zombie_spawn_timer >= 300: # 每5秒生成一个僵尸
self.zombie_spawn_timer = 0
row = random.randint(0, GRID_ROWS - 1)
self.zombies.append(Zombie(row))
# 更新植物
for plant in self.plants[:]:
plant.update()
if isinstance(plant, Sunflower):
sun = plant.update()
if sun:
self.suns.append(sun)
if plant.health <= 0:
self.plants.remove(plant)
elif plant.can_attack() and isinstance(plant, Peashooter):
# 检查该行是否有僵尸
for zombie in self.zombies:
if zombie.row == plant.row and zombie.col > plant.col:
self.projectiles.append(plant.attack())
break
# 更新僵尸
for zombie in self.zombies[:]:
if zombie.update(self.plants):
self.game_over = True
if zombie.health <= 0:
self.zombies.remove(zombie)
# 更新子弹
for projectile in self.projectiles[:]:
if projectile.update():
self.projectiles.remove(projectile)
else:
# 检查是否击中僵尸
for zombie in self.zombies:
if (zombie.row == projectile.row and
zombie.x <= projectile.x <= zombie.x + GRID_SIZE):
zombie.health -= projectile.damage
self.projectiles.remove(projectile)
break
# 更新阳光
for sun in self.suns[:]:
if sun.update():
self.suns.remove(sun)
# 随机生成阳光
if random.random() < 0.005: # 0.5%的几率每帧生成阳光
x = random.randint(LAWN_LEFT, LAWN_LEFT + GRID_COLS * GRID_SIZE)
self.suns.append(Sun(x, 0))
def draw(self):
screen.fill(WHITE)
self.draw_lawn()
# 绘制植物
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()
self.draw_ui()
# 显示选中的植物
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)
elif self.selected_plant == "wallnut":
pygame.draw.circle(screen, BROWN, (mouse_x, mouse_y), 30)
pygame.display.flip()
# 主游戏循环
def main():
game = Game()
while True:
game.handle_events()
game.update()
game.draw()
clock.tick(FPS)
if __name__ == "__main__":
main()