植物大战僵尸python实现1.0
1.简介
用python的pygame库初步实现植物大战僵尸的一些功能,并做成windows安装包。记录自己的学习过程,版本1.0
结果展示:
2.文件组织
文件组织如下
3.代码
参考代码
pz.py:
# 主程序
import time
import pygame
# 导入库
from Plants import Peashooter, SunFlower, WallNut, Plant # 导入植物
from Other import Sun,Bullet # 导入太阳花和子弹
from Zoombie import Zombie,FlagZombie # 导入僵尸
# 参数,屏幕尺寸,背景图地址,僵尸出现的时间间隔
backgd_size = (1000,600)
bg_image_path = "material/images/background2.jpg"
sun_image_path = "material/images/SeedBank.png"
Zombie_time = 4000
# 初始化
pygame.init()
screen = pygame.display.set_mode(size=backgd_size) # 框架大小
pygame.display.set_caption('植物大战僵尸') # 标题
clock = pygame.time.Clock() # 时钟
plants_sprites = pygame.sprite.Group() # 植物组
sun_sprites = pygame.sprite.Group() # 太阳组
zoombie_sprites = pygame.sprite.Group() # 僵尸组
bullet_sprites = pygame.sprite.Group() # 子弹组
# 音乐,加载进来
pygame.mixer.init()
pygame.mixer.music.load("material/music/02 - Crazy Dave (Intro Theme).mp3")
# 定义事件,生成太阳,子弹,僵尸,旗帜僵尸
GET_SUN_EVENT = pygame.USEREVENT + 1
pygame.time.set_timer(GET_SUN_EVENT, 100)
GET_BULLET_EVENT = pygame.USEREVENT + 2
pygame.time.set_timer(GET_BULLET_EVENT, 100)
ZOOMBIE_EVENT = pygame.USEREVENT + 3
pygame.time.set_timer(ZOOMBIE_EVENT, Zombie_time)
FLAGZOOMBIE_EVENT = pygame.USEREVENT + 4
pygame.time.set_timer(FLAGZOOMBIE_EVENT, 5000)
def main(sun_value = 900,plants_list = (Peashooter, SunFlower, WallNut)):
# 参数设置,植物被选择的下标
choose = -1
# 循环运行的次数记录
index = 0
# 读取背景地址图片
bg_image = pygame.image.load(bg_image_path).convert_alpha()
sun_bg_image = pygame.image.load(sun_image_path).convert_alpha()
# 字体设定
sun_font = pygame.font.SysFont('Arial', 20)
# 植物卡槽
plants_choice = [plant(None) for plant in plants_list]
# 植物卡槽的摆放位置
plants_weizi = [(235+51*i,7) for i in range(len(plants_choice))]
# 每帧循环的动作操作
while True:
# 帧数设置
clock.tick(20)
# 音乐
if not pygame.mixer.music.get_busy():
pygame.mixer.music.play()
# 排背景图,位置
screen.blit(bg_image, (-100, 0))
screen.blit(sun_bg_image, (155, 0))
# 太阳花数量字体设置
sum_value_surface = sun_font.render(str(sun_value), True, (0, 0, 0))
screen.blit(sum_value_surface, (175, 60))
# 更新卡槽
for i in range(len(plants_choice)):
screen.blit(plants_choice[i].pic, plants_weizi[i])
# 如果有选择植物,鼠标下出现植物图片
if choose >= 0:
x, y = pygame.mouse.get_pos()
img = plants_choice[choose].click_image
screen.blit(img, (x-30, y-30))
# 对事件遍历
for event in pygame.event.get():
# 退出
if event.type == pygame.QUIT:
exit()
# 鼠标点击
elif event.type == pygame.MOUSEBUTTONDOWN:
# 鼠标点击判断
pressed_key = pygame.mouse.get_pressed()
if pressed_key[0] == 1: # 如果是左键[1,0,0]
x,y = pygame.mouse.get_pos() # 得到按键的位置
for weizi in plants_weizi:
# 点击卡槽位置判断
if weizi[0] < x< weizi[0]+50 and weizi[1] < y < weizi[1]+70:
if sun_value>=plants_choice[plants_weizi.index(weizi)].need_sun:
choose = plants_weizi.index(weizi)
else:
print("能量不足")
# 点击种植区域判断
if 100 < x < 900 and 80 < y < 550 and choose >= 0:
current = time.time()
plant = plants_list[choose](current)
plant.rect.center = (x, y)
plants_sprites.add(plant)
sun_value -= plant.need_sun
choose = -1
# 点击太阳花判断
for sun in sun_sprites:
if sun.rect.collidepoint((x,y)):
sun.kill()
sun_value += 25
break
# 事件:产生太阳花
elif event.type == GET_SUN_EVENT:
for plants in plants_sprites:
if isinstance(plants,SunFlower) and time.time() - plants.starttime >= 3:
sun = Sun(plants.rect)
sun_sprites.add(sun)
plants.starttime = time.time()
# 事件子弹
elif event.type == GET_BULLET_EVENT:
for plants in plants_sprites:
if isinstance(plants, Peashooter) and time.time() - plants.starttime >= 0.8:
bullet = Bullet(plants.rect, backgd_size)
bullet_sprites.add(bullet)
plants.starttime = time.time()
# 事件两个僵尸
elif event.type == ZOOMBIE_EVENT:
zombie = Zombie(None)
zoombie_sprites.add(zombie)
elif event.type == FLAGZOOMBIE_EVENT:
flagzombie = FlagZombie(None)
zoombie_sprites.add(flagzombie)
# 子弹碰撞检测
for bull in bullet_sprites:
for zoom in zoombie_sprites:
if pygame.sprite.collide_mask(bull,zoom):
bullet_sprites.remove(bull)
zoom.energy -= 1
# 植物碰撞检测
for plants in plants_sprites:
if isinstance(plants,Plant):
for zoom in zoombie_sprites:
if pygame.sprite.collide_mask(plants,zoom):
zoom.ismeetplant = True
plants.zoombies.add(zoom)
# 更新画面,开始下一帧
index += 1
plants_sprites.update(index)
plants_sprites.draw(screen)
zoombie_sprites.update(index)
zoombie_sprites.draw(screen)
bullet_sprites.update(index)
bullet_sprites.draw(screen)
sun_sprites.update(index)
sun_sprites.draw(screen)
pygame.display.update()
if __name__ == '__main__':
plants_list = (Peashooter, SunFlower, WallNut,Peashooter,SunFlower,WallNut,Peashooter)
main(plants_list=plants_list)
Plants.py
import pygame
import random
# 写个植物基础类,让其它植物继承
class Plant(pygame.sprite.Sprite):
def __init__(self, starttime): # 记录种植时间
pygame.sprite.Sprite.__init__(self)
# 植物在卡槽图片
self.pic = pygame.image.load("material/images/TwinSunflower.gif").convert_alpha()
# 植物点击的图像
self.click_image = pygame.image.load(("material/images/SunFlower_00.png")).convert_alpha()
# 初始图像
self.image = pygame.image.load(("material/images/SunFlower_00.png")).convert_alpha()
# 循环动画图像
self.images = [pygame.image.load("material/images/SunFlower_{:02d}.png".format(i)).convert_alpha() for i
in range(0, 13)]
# 被咬图片,一般不变
self.crack_img = self.images
# 位置信息
self.rect = self.image.get_rect()
# 初始化数据
self.need_sun = 50 # 太阳需要值
self.starttime = starttime # 种植时间
self.energy = 20 # 生命能量
self.zoombies = set() # 吃该植物的僵尸
def update(self,*args):
# 更新函数
if self.energy <= 0:
# 生命小于0,死掉
for zoom in self.zoombies:
# 不在阻挡僵尸
zoom.ismeetplant = False
# 植物消失
self.kill()
else:
if self.zoombies is set():
# 无僵尸动作
self.image = self.images[args[0]%len(self.images)]
else:
# 有僵尸动作
self.image = self.images[args[0]%len(self.images)]
# 扣除生命值
for zoombie in self.zoombies:
if zoombie.isalive == True:
self.energy -= 1
# 太阳花,继承Plant
class SunFlower(Plant):
def __init__(self, starttime):
super().__init__(starttime)
# 卡槽图片
self.pic = pygame.image.load("material/images/TwinSunflower.gif").convert_alpha()
# 点击图像
self.click_image = pygame.image.load(("material/images/SunFlower_00.png")).convert_alpha()
# 初始图像
self.image = pygame.image.load(("material/images/SunFlower_00.png")).convert_alpha()
# 循环图像
self.images = [pygame.image.load("material/images/SunFlower_{:02d}.png".format(i)).convert_alpha() for i in range(0,13)]
# 初始化数据
self.need_sun = 50
# 豌豆射手
class Peashooter(Plant):
def __init__(self, starttime):
super().__init__(starttime)
# 卡槽图片
self.pic = pygame.image.load("../pz/material/images/Peashooter.gif").convert_alpha()
# 点击图像
self.click_image = pygame.image.load(("material/images/Peashooter_00.png")).convert_alpha()
# 初始图像
self.image = pygame.image.load(("material/images/Peashooter_00.png")).convert_alpha()
# 循环图像
self.images = [pygame.image.load("material/images/Peashooter_{:02d}.png".format(i)).convert_alpha() for i in range(0,13)]
# 初始化数据
self.need_sun = 100
# 坚果
class WallNut(Plant):
def __init__(self, starttime):
super().__init__(starttime)
# 卡槽图片
self.pic = pygame.image.load("../pz/material/images/WallNut.gif").convert_alpha()
# 点击图像
self.click_image = pygame.image.load(("material/images/WallNut_00.png")).convert_alpha()
# 初始图像
self.image = pygame.image.load(("material/images/WallNut_00.png")).convert_alpha()
# 循环图像
self.images = [pygame.image.load("material/images/WallNut_{:02d}.png".format(i)).convert_alpha() for i in
range(0, 13)]
# 坚果被咬图像
self.crack_img = [
pygame.transform.smoothscale(pygame.image.load(("material/images/Wallnut_body.png")).convert_alpha(), # 图像读取,并缩放
(self.image.get_rect().width,self.image.get_rect().height)),
pygame.transform.smoothscale(pygame.image.load(("material/images/Wallnut_cracked1.png")).convert_alpha(),
(self.image.get_rect().width,self.image.get_rect().height)),
pygame.transform.smoothscale(pygame.image.load(("material/images/Wallnut_cracked2.png")).convert_alpha(),
(self.image.get_rect().width,self.image.get_rect().height)),]
# 初始化数据
self.need_sun = 50
self.energy = 50
def update(self,*args):
# 坚果图像动画不同,重写类
if self.energy <= 0:
# 死亡
for zoom in self.zoombies:
zoom.ismeetplant = False
self.kill()
else:
# 不同生命值,不同动画
if self.energy >= 40:
self.image = self.images[args[0]%len(self.images)]
elif 30<=self.energy < 40:
self.image = self.crack_img[0]
elif 20 <= self.energy < 30:
self.image = self.crack_img[1]
else:
self.image = self.crack_img[2]
# 被僵尸吃,扣血
for zoombie in self.zoombies:
if zoombie.isalive == True:
self.energy -= 1
Zoombie.py:
import pygame
import random
# 僵尸类
class Zombie(pygame.sprite.Sprite):
def __init__(self,starttime):
pygame.sprite.Sprite.__init__(self)
# 图片
self.image = pygame.image.load(("material/images/Zombie_0.png")).convert_alpha()
self.images = [pygame.image.load("material/images/Zombie_{}.png".format(i)).convert_alpha() for i in range(0,22)]
self.dieimages = [pygame.image.load("material/images/ZombieDie_{}.png".format(i)).convert_alpha() for i in range(0,10)]
self.attact_images = [pygame.image.load("material/images/ZombieAttack_{}.png".format(i)).convert_alpha() for i in range(0,21)]
# 位置
self.rect = self.image.get_rect()
self.rect.top = random.randrange(0,5)*100+25
self.rect.left = 900
# 初始化信息
self.speed = 2
self.energy = 6
self.dietimes = 0
self.ismeetplant = False
self.isalive = True
def update(self,*args):
# 活着
if self.energy >= 0:
# 前面有植物
if self.ismeetplant:
self.image = self.attact_images[args[0] % len(self.attact_images)]
else: # 前面没有植物
self.image = self.images[args[0] % len(self.images)]
if self.rect.left >= 100:
self.rect.left -= self.speed
# 死亡
else:
self.isalive = False
if self.dietimes < 20:
self.image = self.dieimages[self.dietimes//2]
self.dietimes += 1
else:
if self.dietimes > 35:
self.kill()
else:
self.dietimes += 1
# 旗帜僵尸
class FlagZombie(Zombie):
def __init__(self,starttime):
Zombie.__init__(self,starttime)
self.image = pygame.image.load(("material/images/FlagZombie_0.png")).convert_alpha()
self.images = [pygame.image.load("material/images/FlagZombie_{}.png".format(i)).convert_alpha() for i in range(0,12)]
self.energy = 10
Others.py:
import pygame
import random
# 太阳花
class Sun(pygame.sprite.Sprite):
def __init__(self,rect):
pygame.sprite.Sprite.__init__(self)
# 加载图片
self.image = pygame.image.load(("material/images/Sun_1.png")).convert_alpha()
self.images = [pygame.image.load("material/images/Sun_{}.png".format(i)).convert_alpha() for i in range(1, 18)]
# 位置信息
self.rect = self.images[0].get_rect()
self.rect.top = rect.top + random.randint(-50, 50)
self.rect.left = rect.left + random.randint(-50, 50)
# 更新图像
def update(self,*args):
self.image = self.images[args[0]%len(self.images)]
# 子弹
class Bullet(pygame.sprite.Sprite):
# 豌豆子弹
def __init__(self,rect,bg_size,dir=True):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(("material/images/Bullet_1.png")).convert_alpha()
self.rect = self.image.get_rect()
# 子弹的初始化位置
self.rect.top = rect.top
self.rect.left = rect.left + 25
self.width = bg_size[0]
self.speed = 7
def update(self,*args):
if self.rect.right < self.width:
self.rect.left += self.speed
else:
self.kill()
4.打包程序
"""
pyinstaller打包游戏的方法:
1.在命令窗口安装pyinstaller
pip install pyinstaller
2.查看安装的版本信息
pyinstaller -v
3.进入需要打包的文件的路径下
pyinstaller -F -w pz.py -p Plants.py -p Other.py -p Zoombie.py
备注:pyinstaller -F -w 程序入口文件 -p 程序文件 -p 程序文件
装了conda 的应运行:
conda remove pathlib
不能解决运行
# python -m pip install pathlib
解决警告问题
"""
运行pyinstaller -F -w pz.py -p Plants.py -p Other.py -p Zoombie.py 命令后目录如下:
与直接运行pz.py效果一样
最后用inno setup将exe做成安装包
正常运行
参考资料