植物大战僵尸
import pygame
import random
import sys
import os
初始化pygame
pygame.init()
学号后四位特殊标志:3006
print("植物大战僵尸游戏 - 特殊标志:3006")
游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_ROWS = 5
GRID_COLS = 9
CELL_WIDTH = SCREEN_WIDTH // GRID_COLS
CELL_HEIGHT = SCREEN_HEIGHT // GRID_ROWS
SUN_VALUE = 25
PLANT_SPAWN_DELAY = 10000 # 10秒
ZOMBIE_SPAWN_DELAY = 8000 # 8秒
BULLET_SPEED = 5
ZOMBIE_SPEED = 1
DAY = True
颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BROWN = (139, 69, 19)
YELLOW = (255, 255, 0)
RED = (255, 0, 0)
创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("植物大战僵尸")
加载图片资源(这里使用简单的颜色块代替实际图片)
def load_image(name, size=(CELL_WIDTH, CELL_HEIGHT)):
try:
image = pygame.Surface(size)
if name == "sun":
image.fill(YELLOW)
pygame.draw.circle(image, (255, 255, 0), (size[0]//2, size[1]//2), size[0]//2)
pygame.draw.circle(image, (255, 255, 255), (size[0]//2, size[1]//2), size[0]//4)
elif name == "sunflower":
image.fill(GREEN)
pygame.draw.circle(image, YELLOW, (size[0]//2, size[1]//2), size[0]//3)
elif name == "peashooter":
image.fill(GREEN)
pygame.draw.rect(image, (0, 100, 0), (size[0]//2, size[1]//2, size[0]//3, size[0]//6))
elif name == "wallnut":
image.fill(BROWN)
pygame.draw.ellipse(image, (100, 50, 0), (size[0]//4, size[1]//4, size[0]//2, size[0]//2))
elif name == "zombie":
image.fill((128, 0, 0))
pygame.draw.rect(image, (100, 0, 0), (size[0]//4, size[1]//3, size[0]//2, size[0]//2))
pygame.draw.circle(image, (150, 0, 0), (size[0]//2, size[1]//4), size[0]//4)
elif name == "bullet":
image.fill((100, 200, 100))
pygame.draw.circle(image, (50, 150, 50), (size[0]//2, size[1]//2), size[0]//4)
return image
except pygame.error as e:
print(f"无法加载图片: {e}")
return pygame.Surface(size)
阳光类
class Sun:
def init(self, x, y):
self.image = load_image("sun")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.value = SUN_VALUE
self.collected = False
self.falling = True
self.speed = 1
def update(self):
if self.falling:
self.rect.y += self.speed
if self.rect.y >= SCREEN_HEIGHT:
self.collected = True
def draw(self, surface):
if not self.collected:
surface.blit(self.image, self.rect)
植物基类
class Plant:
def init(self, x, y, cost, health):
self.x = x
self.y = y
self.cost = cost
self.health = health
self.rect = pygame.Rect(x, y, CELL_WIDTH, CELL_HEIGHT)
self.planted = False
def update(self, zombies, bullets):
pass
def draw(self, surface):
pass
def take_damage(self, damage):
self.health -= damage
if self.health <= 0:
return True
return False
向日葵类
class Sunflower(Plant):
def init(self, x, y):
super().init(x, y, 50, 100)
self.image = load_image("sunflower")
self.sun_timer = 0
self.sun_interval = 20000 # 20秒生产一次阳光
def update(self, zombies, bullets):
self.sun_timer += 1
if self.sun_timer >= self.sun_interval:
sun = Sun(self.x + CELL_WIDTH//2 - SUN_VALUE//2, self.y - CELL_HEIGHT)
sun.falling = True
suns.append(sun)
self.sun_timer = 0
def draw(self, surface):
if self.planted:
surface.blit(self.image, self.rect)
豌豆射手类
class Peashooter(Plant):
def init(self, x, y):
super().init(x, y, 100, 100)
self.image = load_image("peashooter")
self.shoot_timer = 0
self.shoot_interval = 2000 # 2秒发射一次
self.bullet_damage = 20
def update(self, zombies, bullets):
self.shoot_timer += 1
if self.shoot_timer >= self.shoot_interval:
# 检查同一行是否有僵尸
for zombie in zombies:
if zombie.row == self.y // CELL_HEIGHT and zombie.rect.x < self.rect.x + CELL_WIDTH:
bullet = Bullet(self.rect.right, self.rect.centery - 10, self.bullet_damage)
bullets.append(bullet)
self.shoot_timer = 0
break
def draw(self, surface):
if self.planted:
surface.blit(self.image, self.rect)
坚果墙类
class WallNut(Plant):
def init(self, x, y):
super().init(x, y, 50, 400)
self.image = load_image("wallnut")
def draw(self, surface):
if self.planted:
surface.blit(self.image, self.rect)
子弹类
class Bullet:
def init(self, x, y, damage):
self.image = load_image("bullet")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.damage = damage
self.speed = BULLET_SPEED
def update(self, zombies):
self.rect.x += self.speed
if self.rect.x > SCREEN_WIDTH:
return True # 子弹超出屏幕,移除
# 检查与僵尸的碰撞
for zombie in zombies:
if self.rect.colliderect(zombie.rect):
zombie.take_damage(self.damage)
return True
return False
def draw(self, surface):
surface.blit(self.image, self.rect)
僵尸基类
class Zombie:
def init(self, x, y, health, damage):
self.image = load_image("zombie")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.health = health
self.damage = damage
self.speed = ZOMBIE_SPEED
self.row = y // CELL_HEIGHT
def update(self, plants):
self.rect.x -= self.speed
if self.rect.x < 0:
return True # 僵尸到达房子,游戏失败
# 检查与植物的碰撞
for plant in plants:
if plant.planted and self.rect.colliderect(plant.rect):
if plant.take_damage(self.damage):
plants.remove(plant)
return False
return False
def draw(self, surface):
surface.blit(self.image, self.rect)
def take_damage(self, damage):
self.health -= damage
if self.health <= 0:
return True
return False
普通僵尸
class NormalZombie(Zombie):
def init(self, y):
super().init(SCREEN_WIDTH, y, 100, 10)
路障僵尸
class ConeZombie(Zombie):
def init(self, y):
super().init(SCREEN_WIDTH, y, 200, 10)
# 路障僵尸图片可以在这里修改,这里简化处理
游戏类
class Game:
def init(self):
self.plants = []
self.zombies = []
self.bullets = []
self.suns = []
self.sun = 50
self.plant_selected = None
self.plant_types = {
"sunflower": Sunflower,
"peashooter": Peashooter,
"wallnut": WallNut
}
self.last_plant_time = 0
self.last_zombie_time = 0
self.game_over = False
self.victory = False
self.zombies_killed = 0
self.zombies_to_kill = 10
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont('simhei', 24)
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if not self.game_over and not self.victory:
mouse_x, mouse_y = pygame.mouse.get_pos()
# 检查是否点击了阳光
for sun in self.suns[:]:
if sun.rect.collidepoint(mouse_x, mouse_y):
self.sun += sun.value
self.suns.remove(sun)
break
# 检查是否选择了植物
if self.plant_selected and self.sun >= self.plant_types[self.plant_selected].__init__.__defaults__[2]:
grid_x = mouse_x // CELL_WIDTH
grid_y = mouse_y // CELL_HEIGHT
x = grid_x * CELL_WIDTH
y = grid_y * CELL_HEIGHT
# 检查是否可以种植植物(在网格内且没有植物)
if 0 <= grid_x < GRID_COLS and 0 <= grid_y < GRID_ROWS:
can_plant = True
for plant in self.plants:
if plant.rect.collidepoint(x, y) and plant.planted:
can_plant = False
break
if can_plant:
plant_class = self.plant_types[self.plant_selected]
plant = plant_class(x, y)
plant.planted = True
self.plants.append(plant)
self.sun -= plant.cost
self.plant_selected = None
def update(self):
if self.game_over or self.victory:
return
# 更新阳光
for sun in self.suns[:]:
sun.update()
if sun.collected:
self.suns.remove(sun)
# 随机生成阳光
current_time = pygame.time.get_ticks()
if current_time - self.last_plant_time > PLANT_SPAWN_DELAY:
self.last_plant_time = current_time
y = random.randint(0, GRID_ROWS - 1) * CELL_HEIGHT
sun = Sun(random.randint(0, SCREEN_WIDTH - CELL_WIDTH), y - CELL_HEIGHT)
self.suns.append(sun)
# 生成僵尸
if current_time - self.last_zombie_time > ZOMBIE_SPAWN_DELAY:
self.last_zombie_time = current_time
y = random.randint(0, GRID_ROWS - 1) * CELL_HEIGHT
# 随机生成普通僵尸或路障僵尸
if random.random() < 0.7:
zombie = NormalZombie(y)
else:
zombie = ConeZombie(y)
self.zombies.append(zombie)
# 更新子弹
for bullet in self.bullets[:]:
if bullet.update(self.zombies):
self.bullets.remove(bullet)
# 更新僵尸
for zombie in self.zombies[:]:
if zombie.update(self.plants):
if zombie.rect.x < 0:
# 僵尸到达房子,减少生命值
self.zombies.remove(zombie)
# 这里应该有房子被攻击的逻辑
self.game_over = True
continue
if zombie.take_damage(0): # 检查僵尸是否被消灭
self.zombies_killed += 1
self.zombies.remove(zombie)
# 更新植物
for plant in self.plants[:]:
plant.update(self.zombies, self.bullets)
# 检查游戏胜利条件
if self.zombies_killed >= self.zombies_to_kill:
self.victory = True
def draw(self):
# 绘制背景
if DAY:
screen.fill((100, 200, 100)) # 草地
else:
screen.fill((50, 50, 100)) # 夜晚
# 绘制网格
for i in range(GRID_ROWS + 1):
pygame.draw.line(screen, (0, 0, 0), (0, i * CELL_HEIGHT), (SCREEN_WIDTH, i * CELL_HEIGHT), 1)
for i in range(GRID_COLS + 1):
pygame.draw.line(screen, (0, 0, 0), (i * CELL_WIDTH, 0), (i * CELL_WIDTH, SCREEN_HEIGHT), 1)
# 绘制阳光
for sun in self.suns:
sun.draw(screen)
# 绘制植物
for plant in self.plants:
plant.draw(screen)
# 绘制子弹
for bullet in self.bullets:
bullet.draw(screen)
# 绘制僵尸
for zombie in self.zombies:
zombie.draw(screen)
# 绘制UI
sun_text = self.font.render(f"阳光: {self.sun}", True, BLACK)
screen.blit(sun_text, (10, 10))
if self.plant_selected:
plant_name = ""
if self.plant_selected == "sunflower":
plant_name = "向日葵"
elif self.plant_selected == "peashooter":
plant_name = "豌豆射手"
elif self.plant_selected == "wallnut":
plant_name = "坚果墙"
plant_cost = self.plant_types[self.plant_selected].__init__.__defaults__[2]
plant_text = self.font.render(f"选中: {plant_name} (消耗: {plant_cost})", True, BLACK)
screen.blit(plant_text, (10, 40))
# 绘制游戏状态
if self.game_over:
game_over_text = self.font.render("游戏结束! 僵尸吃掉了你的脑子!", True, RED)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2,
SCREEN_HEIGHT // 2 - 30))
restart_text = self.font.render("按R键重新开始", True, BLACK)
screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2,
SCREEN_HEIGHT // 2 + 30))
if self.victory:
victory_text = self.font.render("胜利! 你成功抵御了僵尸入侵!", True, YELLOW)
screen.blit(victory_text, (SCREEN_WIDTH // 2 - victory_text.get_width() // 2,
SCREEN_HEIGHT // 2 - 30))
next_text = self.font.render("按N键进入下一关", True, BLACK)
screen.blit(next_text, (SCREEN_WIDTH // 2 - next_text.get_width() // 2,
SCREEN_HEIGHT // 2 + 30))
pygame.display.flip()
def run(self):
while True:
self.handle_events()
if self.game_over:
keys = pygame.key.get_pressed()
if keys[pygame.K_r]:
self.__init__() # 重新初始化游戏
if self.victory:
keys = pygame.key.get_pressed()
if keys[pygame.K_n]:
self.__init__() # 下一关,这里简化为重新开始
self.zombies_to_kill += 5 # 增加下一关的僵尸数量
self.update()
self.draw()
self.clock.tick(60)
启动游戏
if name == "main":
game = Game()
game.run()

浙公网安备 33010602011771号