打鸟小游戏-附代码及素材

(素材是从pvz2素材吧找的)

亮点:

1.玩家是运动的,不是静态图片

2.玩家有3种效果,正常,发炮,爆炸

3.玩家可以切换射击模式,直线射击,单次三发,单次五发(对应不同的按键)

4.敌人(鸟),也不是静态效果,有飞行的效果

5.可以在配置文件中修改速度,鸟的数量,子弹类型(蓝,绿,铁)

移动效果:

射击效果:

 

代码说明:

首先是文件结构:

打鸟小游戏-附代码及素材_第1张图片 

下面是具体代码(从bird.py开始按顺序):

#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录制了很多次才成功,

关注,点赞收藏鼓励一下吧

 

你可能感兴趣的:(#,走出控制台)