(素材是从pvz2素材吧找的)
1.玩家是运动的,不是静态图片
2.玩家有3种效果,正常,发炮,爆炸
3.玩家可以切换射击模式,直线射击,单次三发,单次五发(对应不同的按键)
4.敌人(鸟),也不是静态效果,有飞行的效果
5.可以在配置文件中修改速度,鸟的数量,子弹类型(蓝,绿,铁)
#bird.py
import pygame
import os
import sys
from bullet import *
#import time
def size_change(surface,times):
position=surface.get_rect()
neww=round(position.w*times)
newh=round(position.h*times)
return pygame.transform.smoothscale(surface,(neww,newh))
def s_c(surfacelist,times):
for i in range(len(surfacelist)):
surfacelist[i]=size_change(surfacelist[i],times)
return surfacelist
def p_l(path):
we=[]
pnglist=os.listdir(path)
for pngname in pnglist:
pngpath=path+"/"+pngname
me=pygame.image.load(pngpath)
we.append(me)
return we
class Bird(pygame.sprite.Sprite):
def __init__(self,speed=5,pos=None):
pygame.sprite.Sprite.__init__(self)
#加载飞行图片,不用截取,只要缩放大小就好:
self.flylist=s_c(p_l(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\鸟\飞"),0.2)
self.order=0
self.image=self.flylist[0]
rect=self.image.get_rect()
self.rect=pygame.Rect(pos,(rect.w,rect.h))
self.speed=speed
#(上面的代码已经完整了,这部分是为了添加一个击中效果
self.spreadlist = s_c(p_l(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\鸟\展翅"), 0.2)
self.spreadorder = 0
self.spredimage=self.spreadlist[0]
self.spreadnum=len(self.spreadlist)
#展翅效果准备添加完毕)
def fly(self):
self.rect.x-=self.speed
def update(self, *args):
self.fly()
if self.order==len(self.flylist)-1:
self.order=-1
self.order+=1
self.image=self.flylist[self.order]
return self.image
def out(self):
if self.rect.x<=-200 or self.rect.x>=1324:
return True
else:
return False
#(是为了展翅效果/击中效果准备的函数
def get_final_rect(self):
return self.rect
def spread(self):
if not self.spreadorder==len(self.spreadlist)-2:
self.spreadorder+=1
self.spredimage=self.spreadlist[self.spreadorder]
return self.spredimage
def spreadover(self):
if self.spreadorder==self.spreadnum-1:
return true
else:
return False
#为了展翅/击中效果的准备函数结束)
#bullet.py
import pygame
import os
import sys
import 配置类
config=配置类.Config()
#import time
#配*
# 置**
# 区***
# 域****
# 开*****
# 始******
静态子弹名称=config.bullet_1()
#配*******
# 置*****
# 区****
# 域***
# 结**
# 束*
def size_change(surface,times):
position=surface.get_rect()
neww=round(position.w*times)
newh=round(position.h*times)
return pygame.transform.smoothscale(surface,(neww,newh))
class bullet(pygame.sprite.Sprite):
def __init__(self,p_rect=None,mode=1,p_face="r",speed=30):
#time.sleep(1)
pygame.sprite.Sprite.__init__(self)
self.image=size_change(pygame.image.load(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\静态子弹/"+静态子弹名称+".png"),config.bullet_times())
self.face=p_face
absrect=self.image.get_rect()
#确定子弹的初始位置
if self.face=="l":
self.rect=pygame.Rect((p_rect.x+76,p_rect.y+140),(absrect.w,absrect.h))
#如果是左向的话还要改变方向:
self.image = pygame.transform.flip(self.image, True, False)
else:
self.rect=pygame.Rect((p_rect.x+115,p_rect.y+140),(absrect.w,absrect.h))
#初始位置确定完毕
#为以后的移动做准备
self.x=self.rect.x
self.y=self.rect.y
self.speed=speed
self.mode=mode
def move_straight(self):
if self.face=="l":
self.rect.x-=self.speed
else:
self.rect.x+=self.speed
return self.rect
def move_up(self):
if self.face=="l":
self.rect.x-=self.speed
self.rect.y-=self.speed*0.3
else:
self.rect.x+=self.speed
self.rect.y-=self.speed*0.3
return self.rect
def move_low(self):
if self.face=="l":
self.rect.x-=self.speed
self.rect.y+=self.speed*0.3
else:
self.rect.x+=self.speed
self.rect.y+=self.speed*0.3
return self.rect
def move_upper(self):
if self.face == "l":
self.rect.x -= self.speed
self.rect.y -= self.speed * 0.5
else:
self.rect.x += self.speed
self.rect.y -= self.speed * 0.5
return self.rect
def move_lower(self):
if self.face == "l":
self.rect.x -= self.speed
self.rect.y += self.speed * 0.5
else:
self.rect.x += self.speed
self.rect.y += self.speed * 0.5
return self.rect
def update(self, *args):
if self.mode==1:
self.move_straight()
elif self.mode==2:
self.move_up()
elif self.mode==3:
self.move_low()
elif self.mode==4:
self.move_upper()
elif self.mode==5:
self.move_lower()
def get_rect(self):
if self.mode==1:
return self.move_straight()
elif self.mode==2:
return self.move_up()
elif self.mode==3:
return self.move_low()
elif self.mode==4:
return self.move_upper()
elif self.mode==5:
return self.move_lower()
def out(self):
if self.rect.x>=1024 or self.rect.x<=0 or self.rect.y>633 or self.rect.y<=0:
return True
else:
return False
#main.py
import pygame
import os
import sys
import random
from 直升机 import *
from bullet import *
from bird import *
import 配置类
config=配置类.Config()
pygame.init()
#加载屏幕
screen=pygame.display.set_mode((1024,633),flags=pygame.RESIZABLE)
#加载直升机
helicopter=Helicoptor(config.plane_speed())
#加载原始背景图片
raw_bg=pygame.image.load(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\背景\屋顶-雪.png")
#处理原始背景图片,得到背景图片
bg=pygame.transform.smoothscale(raw_bg,(1024,633))
#设定屏幕的可活动区域
screenlimit=bg.get_rect()
#得到时钟
clock=pygame.time.Clock()
#得到子弹组
bulletgroup=pygame.sprite.Group()
#得到鸟组:
birdgroup=pygame.sprite.Group()
#被子弹撞到的鸟
hited_birdgroup=pygame.sprite.Group()
#被鸟撞到的子弹
hited_bulletgroup=pygame.sprite.Group()
#添加鼠标运动的频率
tick_mousemottion=0
#添加鸟出现的频率
tick_bird=0
#添加飞机刷新的频率
tick_plane=0
while True:
#开始事件处理
for event in pygame.event.get():
#键盘处理事件
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
helicopter.move("r", screenlimit)
elif event.key == pygame.K_LEFT:
helicopter.move("l", screenlimit)
elif event.key == pygame.K_UP:
helicopter.move("u", screenlimit)
elif event.key == pygame.K_DOWN:
helicopter.move("d", screenlimit)
#射击单发子弹
elif event.key==pygame.K_d:
bulletgroup.add(helicopter.shoot(1))
#射击三发子弹
elif event.key==pygame.K_a:
bulletgroup.add(helicopter.shoot(3))
#射击五发子弹
elif event.key==pygame.K_w:
bulletgroup.add(helicopter.shoot(5))
elif event.key==pygame.K_0:
helicopter.over()
#键盘事件处理结束
#退出游戏事件处理
elif event.type==pygame.QUIT:
sys.exit(-1)
#(添加鼠标移动事件,提高游戏体验,同时增加防止卡顿计数操作
if tick_mousemottion % 60 == 0:
pygame.event.post(pygame.event.Event(pygame.MOUSEMOTION, dict=None))
tick_mousemottion += 1
if tick_mousemottion >= 15:
tick_mousemottion = 0
#添加鼠标事件结束)
#(此处刷鸟,每过一定帧数,出现一只鸟:
if tick_bird%config.bird_tick()==0:
bird_pos = [1224,random.randint(0,633)]
birdgroup.add(Bird(pos=bird_pos,speed=config.bird_speed()))
tick_bird+=1
if tick_bird>=config.bird_tick():
tick_bird=0
#刷鸟操作完成)
#(开始碰撞检测
#碰撞检测函数,先空置
#(鸟与子弹检测:
#先生成结果列表
hit_list=pygame.sprite.groupcollide(birdgroup,bulletgroup,True,True)
#完善被击中列表
for bird in hit_list:
if len(hit_list[bird])==0:
hited_birdgroup.add(bird)
hited_bulletgroup.add(hit_list[bird])
#鸟与子弹初步检测完成)
#[画布更新操作:
#要先覆盖原背景
screen.blit(bg, (0, 0))
#(未碰撞的子弹更新:
#首先把越界的子弹都删掉:
for bullet in bulletgroup:
if bullet.out():
bulletgroup.remove(bullet)
bulletgroup.update()
bulletgroup.draw(screen)
#未碰撞子弹更新完毕)
#(未被子弹达到的鸟先更新
#首先把越界的鸟都删掉
for bird in birdgroup:
if bird.out():
birdgroup.remove(bird)
birdgroup.update()
birdgroup.draw(screen)
#未被子弹打到的鸟刷新完成)
#(这里处理被击中的鸟:
for bird in hited_birdgroup:
screen.blit(bird.spread(),bird.get_final_rect())
if bird.spreadover():
hited_birdgroup.remove(bird)
#被击中的鸟处理完毕)
#(直升飞机更新,靠总帧数太慢,所以自己设置一个
if tick_bird%config.plane_tick()==0:
screen.blit(helicopter.update(), helicopter.get_rect())
tick_plane+=1
if tick_plane>=config.plane_tick():
tick_plane==0
#清除缓存
pygame.display.update()
clock.tick(config.main_tick())
#直升机.py
import pygame
import os
import sys
from bullet import *
#import time
#加*
# 载**
# 图***
# 片****
# 函*****
# 数******
# 准*******
# 备********
# 函*********
# 数**********
# 开***********
# 始************
#第一个参数传一个surface对象,第二个参数传一个缩放倍数
def raw_size_change(surface,times):
position=surface.get_rect()
neww=round(position.w*times)
newh=round(position.h*times)
return pygame.transform.smoothscale(surface,(neww,newh))
#智者千虑,必有一失
def firstprepare(surface,times):
#先把图片给截取出来
rect=surface.get_rect()
w,h=rect.w,rect.h
s1 = surface.subsurface(
pygame.Rect((round(w * 0.1603), round(h * 0.04655)), (round(w * 0.638), round(h* 0.6))))
position=s1.get_rect()
neww=round(position.w*times)
newh=round(position.h*times)
s2=pygame.transform.smoothscale(s1,(neww,newh)).convert_alpha()
return s2
#啥都不说了
def l_c(surfacelist,times):
for i in range(len(surfacelist)):
surfacelist[i]=firstprepare(surfacelist[i],times)
return surfacelist
'''把给定文件夹下的gif转化的png序列图片加载并放到一个列表中
也就是png to list,简单点起名为p_l'''
def p_l(path):
we=[]
pnglist=os.listdir(path)
for pngname in pnglist:
pngpath=path+"/"+pngname
me=pygame.image.load(pngpath)
we.append(me)
return we
#加**********
# 载********
# 图*******
# 片******
# 准*****
# 备****
# 函***
# 数**
# 结*
# 束
#子*
# 弹**
# 相***
# 关****
# 函*****
# 数******
def o_shoot(rect,face):
#time.sleep(2)
b1=bullet(p_rect=rect,p_face=face,mode=1)
return b1
def t_shoot(rect,face):
b1=bullet(p_rect=rect,p_face=face,mode=1)
b2 = bullet(p_rect=rect, p_face=face, mode=2)
b3 = bullet(p_rect=rect, p_face=face, mode=3)
return [b1,b2,b3]
def f_shoot(rect,face):
b1 = bullet(p_rect=rect, p_face=face, mode=1)
b2 = bullet(p_rect=rect, p_face=face, mode=2)
b3 = bullet(p_rect=rect, p_face=face, mode=3)
b4 = bullet(p_rect=rect, p_face=face, mode=4)
b5 = bullet(p_rect=rect, p_face=face, mode=5)
return [b1,b2,b3,b4,b5]
#子*******
# 弹*****
# 相****
# 关***
# 函**
# 数*
class Helicoptor(pygame.sprite.Sprite):
def __init__(self,speed=None):
pygame.sprite.Sprite.__init__(self)
self.times=0.64
self.normallist=l_c(p_l(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\直升飞机\正常"),self.times)
self.shootlist=l_c(p_l(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\直升飞机\发炮"),self.times*0.829)
self.blowlist=l_c(p_l(r"D:\python-related\workspace\p5-植物大战僵尸\venv\game_one\resource\直升飞机\爆炸"),self.times)
self.shownlist=self.normallist
self.status=0
#该有的属性:
self.rect=self.shownlist[0].get_rect()
#为了转向设置的面向
self.face="l"
#为了移动设置的速度:
self.speed=speed
#为了更新设置的顺序:
self.order=0
#这个也是为了跟group中的方法对接的属性
self.image=None
#为了检测状态是否更改,我还得设置个是否改变状态的变量
self.changed=False
#为了检查是否更改的第二次尝试
self.targetaStatus=0
#这里是正常的更新方法
def normalupdate(self):
if self.order==len(self.normallist)-1:
self.order=-1
self.order+=1
self.image=self.normallist[self.order]
return self.image
#这里是射击时的更新方法
"""设计是个麻烦的方法
1.射击后要恢复正常-完美解决
2.连续设计的效果-在底下的状态改变函数里解决"""
def shootupdate(self):
if self.order==len(self.shootlist)-2:
self.status=-1
self.targetaStatus=0
self.order+=1
self.image=self.shootlist[self.order]
return self.image
#这里是爆炸时的更新方法
"""只能爆炸一次"""
def blowupdate(self):
if not self.order==len(self.blowlist)-1:
self.order+=1
self.image=self.blowlist[self.order]
return self.image
"""核心难度在于更新,我的思想是不管是什么状态,他都是一个飞机,
所以就使用一个update函数,根据status参数选择具体的更新方法"""
#0-正常
#1-发炮
#2-爆炸
def update(self ):
#先判断是否改变了状态
#但状态改变,肯定要换个效果进行显示
#所以order变量就要归零
if not self.status==self.targetaStatus:
self.order=-1
#一定要改变自己的状态
self.status=self.targetaStatus
#下面进行正常的更新,不同状态的更新函数相差很大,所以我们分开写
if self.status==0:
return self.normalupdate()
elif self.status==1:
return self.shootupdate()
elif self.status==2:
return self.blowupdate()
#底下是个状态更新匹配的状态改变函数
#设计函数待完善,还有子弹的事情
def shoot(self,mode):
#time.sleep(2)
self.targetaStatus=1
self.order=-1
if mode==1:
return o_shoot(self.rect,self.face)
elif mode==3:
return t_shoot(self.rect,self.face)
elif mode==5:
return f_shoot(self.rect,self.face)
def over(self):
self.targetaStatus=2
#下面是每次必有得噩梦,移动函数,
def turn(self,list):
for i in range(len(list)):
list[i]=pygame.transform.flip(list[i],True,False)
def turnface(self):
self.turn(self.normallist)
self.turn(self.shootlist)
self.turn(self.blowlist)
def move(self, mode, limit):
x1 = limit.x-132
x2 = limit.x + limit.width+113
y1 = limit.y-120
y2 = limit.y + limit.height+10
# 向右移动,
if mode == "r":
# 首先是判断是否需要转向.
if not mode == self.face:
self.turnface()
self.face = 'r'
# 然后是边界判断
if self.rect.x + self.speed + self.rect.width <= x2:
self.rect = self.rect.move([self.speed, 0])
else:
self.rect = self.rect.move([x2 - (self.rect.x + self.rect.width), 0])
# 向左移动,
if mode == "l":
# 还是先判断是否转向
if self.face == "r":
self.turnface()
self.face = 'l'
# 然后是边界判断:
if self.rect.x - self.speed >= x1:
self.rect = self.rect.move([-self.speed, 0])
else:
self.rect = self.rect.move([-(self.rect.x - x1), 0])
# 向上运动,
if mode == 'u':
if self.rect.y - self.speed >= y1:
self.rect = self.rect.move([0, -self.speed])
else:
self.rect = self.rect.move([0, -(self.rect.y - y1)])
# 向下运动
if mode == 'd':
if self.rect.y + self.rect.height + self.speed < y2:
self.rect = self.rect.move([0, self.speed])
else:
self.rect = self.rect.move([0, y2 - (self.rect.y + self.rect.height)])
def get_rect(self):
return self.rect
#配置类.py
class Config:
def __init__(self):
self.静态子弹名称="纯蓝子弹-椭圆"
self.静态子弹缩放倍数=0.4
self.刷鸟间隔=10
self.鸟的速度=15
self.飞机速度=120
self.飞机帧数=1
self.总帧率=100
def bullet_1(self):
return self.静态子弹名称
def bird_tick(self):
return self.刷鸟间隔
def bird_speed(self):
return self.鸟的速度
def plane_speed(self):
return self.飞机速度
def main_tick(self):
return self.总帧率
def bullet_times(self):
return self.静态子弹缩放倍数
def plane_tick(self):
return self.飞机帧数
图片及相关资源的网盘位置:
盘.百度.康姆/s/19G-km50SFu9CPaTjB_J0Fw
提取码:vuml
做博文很麻烦的,尤其是那个gif录制了很多次才成功,
关注,点赞收藏鼓励一下吧