植物大战僵尸
09
植物大战僵尸1
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("植物大战僵尸")
颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
游戏常量
LANES = 5
LANE_HEIGHT = SCREEN_HEIGHT // LANES
ZOMBIE_WIDTH = 60
ZOMBIE_HEIGHT = 80
PLANT_WIDTH = 50
PLANT_HEIGHT = 50
PEA_WIDTH = 10
PEA_HEIGHT = 10
SUN_WIDTH = 30
SUN_HEIGHT = 30
SUN_COST = 50
SUNFLOWER_COST = 50
PEASHOOTER_COST = 100
加载图片(这里用颜色块代替实际图片)
def draw_plant(screen, x, y, plant_type):
if plant_type == "sunflower":
pygame.draw.rect(screen, (255, 255, 0), (x, y, PLANT_WIDTH, PLANT_HEIGHT)) # 向日葵为黄色
elif plant_type == "peashooter":
pygame.draw.rect(screen, (0, 255, 0), (x, y, PLANT_WIDTH, PLANT_HEIGHT)) # 豌豆射手为绿色
def draw_zombie(screen, x, y, health):
# 僵尸的颜色根据生命值变化
health_ratio = health / 100
color = (255, int(255 * health_ratio), int(255 * health_ratio))
pygame.draw.rect(screen, color, (x, y, ZOMBIE_WIDTH, ZOMBIE_HEIGHT))
def draw_pea(screen, x, y):
pygame.draw.rect(screen, WHITE, (x, y, PEA_WIDTH, PEA_HEIGHT))
def draw_sun(screen, x, y):
pygame.draw.rect(screen, YELLOW, (x, y, SUN_WIDTH, SUN_HEIGHT))
植物类
class Plant:
def init(self, x, y, plant_type):
self.x = x
self.y = y
self.plant_type = plant_type
self.health = 100
self.sun_timer = 0
self.attack_timer = 0
def update(self):
if self.plant_type == "sunflower":
self.sun_timer += 1
if self.sun_timer >= 300: # 每300帧产生一次阳光
self.sun_timer = 0
return Sun(self.x + PLANT_WIDTH//2 - SUN_WIDTH//2, self.y - SUN_HEIGHT)
elif self.plant_type == "peashooter":
self.attack_timer += 1
if self.attack_timer >= 100: # 每100帧发射一次豌豆
self.attack_timer = 0
return Pea(self.x + PLANT_WIDTH, self.y + PLANT_HEIGHT//2 - PEA_HEIGHT//2, self.y // LANE_HEIGHT)
return None
def draw(self, screen):
draw_plant(screen, self.x, self.y, self.plant_type)
僵尸类
class Zombie:
def init(self, lane):
self.x = SCREEN_WIDTH
self.y = lane * LANE_HEIGHT + 10
self.health = 100
self.speed = 0.5
def update(self):
self.x -= self.speed
def draw(self, screen):
draw_zombie(screen, self.x, self.y, self.health)
def is_dead(self):
return self.health <= 0
def is_in_lane(self, lane):
return self.y // LANE_HEIGHT == lane
def collide_with_plant(self, plant):
return (self.x < plant.x + PLANT_WIDTH and
self.x + ZOMBIE_WIDTH > plant.x and
self.y < plant.y + PLANT_HEIGHT and
self.y + ZOMBIE_HEIGHT > plant.y)
豌豆类
class Pea:
def init(self, x, y, lane):
self.x = x
self.y = y
self.lane = lane
self.speed = 2
def update(self):
self.x += self.speed
def draw(self, screen):
draw_pea(screen, self.x, self.y)
def collide_with_zombie(self, zombie):
return (self.x < zombie.x + ZOMBIE_WIDTH and
self.x + PEA_WIDTH > zombie.x and
self.y < zombie.y + ZOMBIE_HEIGHT and
self.y + PEA_HEIGHT > zombie.y)
def is_off_screen(self):
return self.x > SCREEN_WIDTH
阳光类
class Sun:
def init(self, x, y):
self.x = x
self.y = y
self.target_y = y + random.randint(30, 100)
self.speed = 1
self.collected = False
self.timer = 300 # 阳光存在时间
def update(self):
if self.y < self.target_y:
self.y += self.speed
self.timer -= 1
def draw(self, screen):
if not self.collected:
draw_sun(screen, self.x, self.y)
def is_collected(self, mouse_pos):
if not self.collected and self.timer > 0:
mx, my = mouse_pos
if (mx > self.x and mx < self.x + SUN_WIDTH and
my > self.y and my < self.y + SUN_HEIGHT):
self.collected = True
return True
return False
def is_expired(self):
return self.collected or self.timer <= 0
游戏类
class Game:
def init(self):
self.plants = []
self.zombies = []
self.peas = []
self.sunflowers = []
self.sun = 50
self.suns = []
self.selected_plant = None
self.score = 0
self.wave = 1
self.zombie_timer = 0
self.zombie_spawn_rate = 200 # 僵尸生成速率
self.game_over = False
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
mx, my = pygame.mouse.get_pos()
# 检查是否点击了阳光
for sun in self.suns:
if sun.is_collected((mx, my)):
self.sun += 25
break
# 检查是否选择了植物
if my < 60: # 顶部工具栏
if 20 < mx < 90: # 向日葵按钮
if self.sun >= SUNFLOWER_COST:
self.selected_plant = "sunflower"
elif 120 < mx < 190: # 豌豆射手按钮
if self.sun >= PEASHOOTER_COST:
self.selected_plant = "peashooter"
else:
self.selected_plant = None
else: # 放置植物
if self.selected_plant:
lane = my // LANE_HEIGHT
grid_x = (mx // 50) * 50
grid_y = lane * LANE_HEIGHT + 60
# 检查是否可以放置植物
can_place = True
for plant in self.plants:
if (abs(plant.x - grid_x) < PLANT_WIDTH and
abs(plant.y - grid_y) < PLANT_HEIGHT):
can_place = False
break
if can_place:
if self.selected_plant == "sunflower" and self.sun >= SUNFLOWER_COST:
self.plants.append(Plant(grid_x, grid_y, "sunflower"))
self.sun -= SUNFLOWER_COST
elif self.selected_plant == "peashooter" and self.sun >= PEASHOOTER_COST:
self.plants.append(Plant(grid_x, grid_y, "peashooter"))
self.sun -= PEASHOOTER_COST
self.selected_plant = None
def update(self):
if self.game_over:
return
# 更新阳光
for sun in self.suns[:]:
sun.update()
if sun.is_expired():
self.suns.remove(sun)
# 随机生成阳光
if random.random() < 0.01:
lane = random.randint(0, LANES-1)
x = random.randint(50, SCREEN_WIDTH-50)
self.suns.append(Sun(x, 0))
# 更新植物
new_plants = []
for plant in self.plants:
new_object = plant.update()
if new_object:
if isinstance(new_object, Sun):
self.suns.append(new_object)
elif isinstance(new_object, Pea):
self.peas.append(new_object)
# 检查植物是否被僵尸吃掉
alive = True
for zombie in self.zombies:
if zombie.collide_with_plant(plant):
plant.health -= 0.5
zombie.speed = 0 # 僵尸吃到植物时停止移动
if plant.health <= 0:
alive = False
zombie.speed = 0.5 # 僵尸继续移动
break
if alive:
new_plants.append(plant)
self.plants = new_plants
# 更新僵尸
self.zombie_timer += 1
if self.zombie_timer >= self.zombie_spawn_rate:
self.zombie_timer = 0
lane = random.randint(0, LANES-1)
self.zombies.append(Zombie(lane))
# 每波僵尸后增加难度
if len(self.zombies) % 5 == 0:
self.wave += 1
if self.zombie_spawn_rate > 50:
self.zombie_spawn_rate -= 10
for zombie in self.zombies[:]:
zombie.update()
if zombie.x < 0:
self.game_over = True
break
if zombie.is_dead():
self.zombies.remove(zombie)
self.score += 10
# 更新豌豆
for pea in self.peas[:]:
pea.update()
if pea.is_off_screen():
self.peas.remove(pea)
continue
# 检查豌豆是否击中僵尸
hit = False
for zombie in self.zombies:
if pea.collide_with_zombie(zombie) and pea.lane == zombie.y // LANE_HEIGHT:
zombie.health -= 20
self.peas.remove(pea)
hit = True
break
if hit:
continue
def draw(self, screen):
# 绘制背景
screen.fill((150, 200, 150))
# 绘制车道分隔线
for i in range(1, LANES):
pygame.draw.line(screen, BLACK, (0, i * LANE_HEIGHT), (SCREEN_WIDTH, i * LANE_HEIGHT), 2)
# 绘制顶部工具栏
pygame.draw.rect(screen, (100, 100, 100), (0, 0, SCREEN_WIDTH, 60))
# 绘制植物选择按钮
pygame.draw.rect(screen, (200, 200, 200), (20, 10, 70, 40))
pygame.draw.rect(screen, (200, 200, 200), (120, 10, 70, 40))
font = pygame.font.SysFont("Arial", 16)
screen.blit(font.render("向日葵 - 50", True, BLACK), (25, 20))
screen.blit(font.render("豌豆射手 - 100", True, BLACK), (125, 20))
# 绘制阳光数量
screen.blit(font.render(f"阳光: {self.sun}", True, YELLOW), (250, 20))
# 绘制分数和波数
screen.blit(font.render(f"分数: {self.score}", True, WHITE), (400, 20))
screen.blit(font.render(f"波数: {self.wave}", True, WHITE), (520, 20))
# 绘制植物
for plant in self.plants:
plant.draw(screen)
# 绘制僵尸
for zombie in self.zombies:
zombie.draw(screen)
# 绘制豌豆
for pea in self.peas:
pea.draw(screen)
# 绘制阳光
for sun in self.suns:
sun.draw(screen)
# 绘制选中的植物
if self.selected_plant:
mx, my = pygame.mouse.get_pos()
if my > 60: # 不在工具栏区域
draw_plant(screen, mx - PLANT_WIDTH//2, my - PLANT_HEIGHT//2, self.selected_plant)
# 游戏结束画面
if self.game_over:
font = pygame.font.SysFont("Arial", 72)
text = font.render("游戏结束", True, RED)
text_rect = text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
screen.blit(text, text_rect)
font = pygame.font.SysFont("Arial", 36)
score_text = font.render(f"最终分数: {self.score}", True, WHITE)
score_rect = score_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 50))
screen.blit(score_text, score_rect)
restart_text = font.render("按R键重新开始", True, WHITE)
restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 100))
screen.blit(restart_text, restart_rect)
def restart(self):
self.__init__()
主游戏循环
def main():
clock = pygame.time.Clock()
game = Game()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and game.game_over:
game.restart()
else:
game.handle_event(event)
game.update()
game.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
if name == "main":
main()


浙公网安备 33010602011771号