pygame实现 飞机大战-第三版-仿写版

目录

一、功能介绍:

二、原代码

(一)精灵定义部分

(二)游戏运行部分

三、代码解析

(一)游戏开始界面的实现

(二)双人单人游戏控制

(三)利用自定义事件

(四)利用精灵Sprite和精灵组Group的碰撞检测

扫描二维码关注公众号,回复: 15555061 查看本文章

(五)获取键盘控制键


在对第二版进行深入学习和研究的基础上,根据第二版的精灵Sprite和Group应用的原理的掌握,本着学习就是不断的折腾的原则,依据第二版的飞机大战自己完成了仿写版的飞机大战。不多说,先上原代码,请大家不要取笑啊!

一、功能介绍:

1、游戏开始界面,可以选择单人、双人游戏

2、可以双机作战,子弹不同

3、英雄有飞机架数限制

4、敌机有BOSS,可以发射子弹

5、有音效和音乐

6、有加子弹的道具,最多可以加到6轮子弹,英雄死后子弹清到1

二、原代码

(一)精灵定义部分

#引入库
import random
import pygame
# from pygame.locals import *

#系统常量设置
#窗口的设置
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 刷新的帧率
FRAME_PER_SEC = 60
# 创建敌机的定时器常量,自定义事件
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹时间,自定义事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
#敌机发射子弹的时间,自定义事件

#出现加子弹道具的事件
CREAT_BULLET_ADD_ENENT =pygame.USEREVENT + 2

#出现敌机发射子弹的事件
CREAT_ENEMYPLANE_FIRE_ENENT = pygame.USEREVENT + 3
#英雄同时发射的子弹的个数
NUM_BULLENT_FIRE_HERO1 = 1
NUM_BULLENT_FIRE_HERO2 = 1



#文件引用设置
image_background = "./image/background.png"
image_enemy = "./image/enemy0.png"
image_enemy1 ="./image/enemy1.png"
image_hero1 = "./image/hero1.png"
image_hero2 = "./image/hero2.png"
image_addbullet ="./image/prop_type_0.png"

image_bullet0 = "./image/bullet.png"
image_bullet1 = "./image/bullet1.png"
image_bullet2 = "./image/bullet2.png"


font_path = "font/STXINGKA.TTF"

sound_bullet = "sound/bullet.mp3"
sound_ememydown0 = "sound/enemy0_down.mp3"
sound_backround = "sound/game_music.mp3"

#精灵定义
#创建GameSprite精灵
class GameSprite(pygame.sprite.Sprite):
    """输入路径和是否为标签"""
    def __init__(self, file_name, is_label=False,content=None,size=30):
        #继承父类方法
        super().__init__()
        if not is_label:
            #为图片输入时
            self.image = pygame.image.load(file_name) #通过图像生成surface对象
            self.rect = self.image.get_rect() #生成rect对象
        else:
            #为文字输入时
            # self.myfont = pygame.font.SysFont(file_name, size)  #注意:用sysfont不支持汉字的显示,改成font后显示
            self.myfont = pygame.font.Font(file_name, size)
            self.image = self.myfont.render(content, True, (0, 0, 0))
            self.rect = self.image.get_rect()  # 生成rect对象
        #以上代码生成surface对象image和对应原rect对象
        # #返回image和rect
        # return self.image,self.rect

    #实现移动
    def update(self,x_speed=0,y_speed=0):
        self.rect.x += x_speed
        self.rect.y += y_speed

#定义子类
#
#背景类
class Background(GameSprite):  # 基于GameSprite生成精灵
    def __init__(self, is_alt=False):
        # 1.调用父类方法实现精灵的创建
        super().__init__(image_background)
        # 2.判断是否是交替图像,如果是,需要设置初始位置
        if is_alt:
            self.rect.y = -self.rect.height

    def update(self,x_speed=0,y_speed=0):
        # 1.调用父类的方法实现
        super().update(0,1)  # y方向是1,x方向是0
        # 2.判断是否飞出屏幕,如果是,需要从精灵组删除敌机
        if self.rect.y >= SCREEN_RECT.height:
            print("飞出屏幕,需要从精灵组删除。。。。")
            self.rect.y = -self.rect.height

#敌机类
class Enemy(GameSprite):
    def __init__(self,filename,bottom_speed_num=1,top_speed_num=3):
        # 1.调用父类方法,创建敌机精灵,同时指定敌机图片
        super().__init__(filename)
        # 2.指定敌机的初始随机速度
        self.speed = random.randint(bottom_speed_num, top_speed_num)

        # 3.指定敌机的初始随机位置
        self.rect.bottom = 0
        max_x = SCREEN_RECT.width - self.rect.width
        self.rect.x = random.randint(0, max_x)

        # 创建敌机子弹精灵组
        self.emeny_bullet_group = pygame.sprite.Group()

    def update(self,x_speed=0,y_speed=0):
        super().update(0,self.speed)
        # 2.判断是否飞出屏幕,如果是,需要从精灵组删除敌机
        if self.rect.y >= SCREEN_RECT.height:
            # print("飞出屏幕,需要从精灵组删除。。。。")
            self.kill()

    def enemyfire(self,file_bullet,num=1):  #修改:2022-4-13 添加num参数,并根据数量控制好子弹位置
        print("敌机发射子弹。。。")
        bullet_num = num  #单独定义同时发射的子弹数可以为后期游戏过程中改变子弹发射数作基础

        for i in range(0,bullet_num):
            # 1.创建子弹精灵
            emeny_bullet = Bullet(file_bullet,3)
            # 2.设置精灵的位置
            emeny_bullet.rect.bottom = self.rect.y + self.rect.height
            emeny_bullet.rect.centerx = self.rect.centerx - 20 * (i - (bullet_num-1)/2)
            # emeny_bullet.rect.centerx = self.rect.centerx
            print("敌机子弹的位置,top为{0};X中心为{1}".format(emeny_bullet.rect.bottom,emeny_bullet.rect.centerx))
            # 3.将精灵添加到精灵组
            self.emeny_bullet_group.add(emeny_bullet)
            # print(len(self.emeny_bullet_group)) #有精灵却不能在planegame调用??

            # return self.emeny_bullet_group
            #加入方法也有问题,返回组的话没有数据
            # print(emeny_bullet)

#英雄类
class Hero(GameSprite):
    def __init__(self,hero_image_file):
        # 1.调用父类方法,设置image speed
        super().__init__(hero_image_file)
        # 2.设置英雄的初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 80

        # 3.创建子弹的精灵组
        self.bullets = pygame.sprite.Group()

    def update(self,x_speed=0,y_speed=0):
        super().update(x_speed, y_speed)
        # # 英雄在水平方向运行
        # self.rect.x += self.speed2
        # # 英雄在垂直方向运行
        # self.rect.y -= self.speed1
        # 控制英雄不能离开屏幕
        if self.rect.x < 0:
            self.rect.x = 0
        elif self.rect.y < 0:
            self.rect.y = 0
        elif self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        elif self.rect.bottom> SCREEN_RECT.bottom:
            self.rect.bottom = SCREEN_RECT.bottom


    def fire(self,num,file_bullet):  #修改:2022-4-13 添加num参数,并根据数量控制好子弹位置
        # print("发射子弹。。。")
        bullet_num = num  #单独定义同时发射的子弹数可以为后期游戏过程中改变子弹发射数作基础

        for i in range(0,bullet_num):
            # 1.创建子弹精灵
            bullet = Bullet(file_bullet,-3)
            # 2.设置精灵的位置
            bullet.rect.bottom = self.rect.y
            bullet.rect.centerx = self.rect.centerx - 20 * (i - (bullet_num-1)/2)

            # 3.将精灵添加到精灵组
            self.bullets.add(bullet)

class Bullet(GameSprite):
    def __init__(self,filename,speed):
        # 调用父类方法,设置子弹图片,设置初始速度
        super().__init__(filename)
        self.yspeed=speed

    def update(self,x_speed=0,y_speed=0):
        # 调用父类方法,让子弹沿垂直方向飞行,
        super().update(0,self.yspeed)
        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            # kill方法把精灵从精灵组删除
            self.kill()

    def __del__(self):
        # print("子弹被销毁。。")
        pass

class Label(GameSprite):
    def __init__(self,content,x,y): # 引用时需要输入内容及相应的位置
        # 调用父类方法,设置文字字体位置
        super().__init__(font_path, True, content,30)
        #设置文字显示位置
        self.rect.x = x
        self.rect.y = y


    def update(self,x_speed=0,y_speed=0):
        # 调用父类方法,标签位置不动
        super().update(0,0)


#创建SoundSprite精灵
class SoundSprite(pygame.sprite.Sprite):
    def  __init__(self,sound_name):
        super().__init__()
        self.sound_name=sound_name

    def play(self,is_music=False):
        self.sound = pygame.mixer.Sound(self.sound_name)
        pygame.mixer.Sound.play(self.sound)
        if is_music :
            self.music=pygame.mixer.music.load(self.sound_name)
            pygame.mixer.music.play(-1)

(二)游戏运行部分

import pygame.sprite
from planesprite_new import *


class PlaneGame(object):
    """飞机大战主游戏"""
    # 用于计分的变量
    Score = 0
    #英雄是否死亡
    death_of_hero1 = True
    death_of_hero2 = True
    #游戏是否开始
    begin_game = False

    #游戏是否暂停
    pause_game = False

    #英雄的同时发的子弹数
    NUM_HERO_01 = 1
    NUM_HERO_02 = 1

    #英雄的飞机数
    NUM_PLANE_HERO1 = 100
    NUM_PLANE_HERO2 = 10

    #敌机1的数量
    NUM_ENEMY = 0
    #大飞机是否出现
    has_bigenemy = False

    ENEMYLIFE_TOP = 100 # 大飞机的寿命数
    bigenemylife = ENEMYLIFE_TOP





    def __init__(self):

        print("游戏初始化")
        pygame.init()
        pygame.mixer.init() #初始化声音

        pygame.display.set_caption("飞机大战")
        #加载游戏开始界面
        while not self.begin_game:
            self.__creat_select_scence()

        # 1.创建游戏的窗口
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        # 2.创建游戏的时钟
        self.clock = pygame.time.Clock()
        # 3.调用私有方法,精灵和精灵组的创建
        self.__create_sprites()
        # 4.设置定时器事件  创建敌机
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)
        pygame.time.set_timer(CREAT_BULLET_ADD_ENENT,50000)
        pygame.time.set_timer(CREAT_ENEMYPLANE_FIRE_ENENT,3000)

        # 5.播放背景乐
        music = SoundSprite(sound_backround)
        music.play(True)

    def __create_sprites(self):

        #创建背景及背景组
        bg1 = Background()
        bg2 = Background(True)
        self.back_group = pygame.sprite.Group(bg1, bg2)
        # 创建敌机的精灵组
        self.enemy_group = pygame.sprite.Group()
        #创建大飞机的敌机组
        self.bigenemy_group = pygame.sprite.Group()

        #创建加子弹的精灵组
        self.addbullet_group = pygame.sprite.Group()
        # 创建英雄精灵和精灵组
        self.hero_group=pygame.sprite.Group()
        #必须先创建,否则后面使用会报错!
        self.hero1 = Hero(image_hero1)
        self.hero2 = Hero(image_hero2)

        #根据选择的玩家情况进行加组
        if not self.death_of_hero1:
            self.hero_group.add(self.hero1)

        if not self.death_of_hero2:
            self.hero_group.add(self.hero2)
        #此处不能判断.因为此处均为False,因此都不会生成,这里正常加组和生成,后面update控制是否输出即可
        # 由于这里加了判断,所以导致后面hero1和hero2没有定义,并且不能加组,但出现单机时第二架飞机还出现的问题!
        #将self.__creat_select_scence()放置到加载前面,并且
        #最后总结,将加载放在前面,而此处需要生成两个英雄,但是根据需要进行加组即可,后面判断显示情况即可
        # self.hero_group = pygame.sprite.Group(self.hero,self.hero2)
        #创建文本显示精灵及精灵组,代码在此处不实时更新,转移到更新处
        # self.label_score =Label("分数:"+ str(self.Score),0,0)
        # self.label_group=pygame.sprite.Group(self.label_score)
        #2020-4-16日实现文本标签的添加,并显示
    def __creat_select_scence(self):
        
        # 1-1.创建选择界面,后添加的
        label_single = Label("单人游戏", 80, 200)
        label_single.rect.right = 240 - 40
        label_double = Label("双人游戏", 280, 200)
        label_double.rect.left = 240 + 40
        label_tip = Label("提示,按空格键暂停游戏", 240, 500)
        label_tip.rect.centerx = 240
        self.screen1 = pygame.display.set_mode(SCREEN_RECT.size)
        self.screen1.fill(color=pygame.Color(255,255,255))
        # print("运行到加组位置")
        #判断输入,
        for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                print("游戏结束,退出程序!!")
                PlaneGame.__game_over()
        mouse_position = pygame.mouse.get_pos() #获得鼠标位置
        mouse_x = mouse_position[0]
        mouse_y = mouse_position[1]
        mouse_pressed = pygame.mouse.get_pressed()#获得鼠标按键
        is_leftbutton = mouse_pressed[0]
        #判断鼠标是否在标签上,是否点击
        if (mouse_x > label_single.rect.x) and (mouse_x < (label_single.rect.x + label_single.rect.width)) and (
                mouse_y > label_single.rect.y) and (mouse_y < (label_single.rect.y + label_single.rect.height)):
            self.lable_single = Label("单人游戏", 80, 200)
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = True
                self.begin_game = True
        if (mouse_x > label_double.rect.x) and (mouse_x < (label_double.rect.x + label_double.rect.width)) and (
                mouse_y > label_double.rect.y) and (mouse_y < (label_double.rect.y + label_double.rect.height)):
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = False
                self.begin_game = True

        self.begin_group = pygame.sprite.Group(label_single, label_double,  label_tip)
        # 加载开始菜单label组

        self.begin_group.draw(self.screen1)

        pygame.display.update()

    def start_game(self):
        print("游戏开始")


        while self.begin_game:
            # 1.设置刷新帧率
            self.clock.tick(FRAME_PER_SEC)

            # 2.事件监听
            self.__event_handler()

            if not self.pause_game:  #空格键决定,每次都对布尔值取反!
                # 3.碰撞检测
                self.__check_collide()

                # 4.更新/绘制精灵组
                self.__update_sprites()

                # 5.更新显示
                pygame.display.update()

    def __event_handler(self):
        # if self.begin_game:
        for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                print("游戏结束,退出程序!!")
                PlaneGame.__game_over()
            elif event.type == CREATE_ENEMY_EVENT:
                 # print("敌机出场。。。")
                # 创建敌机精灵
                self.enemy = Enemy(image_enemy,2,3)
                self.enemy_group.add(self.enemy)

                self.NUM_ENEMY += 1
                if self.NUM_ENEMY %50 == 0:
                    #TODO 修改飞机敌机出现的频次
                    self.bigenemy =Enemy(image_enemy1,1,1)
                    #TODO 加入大敌机,能发射子弹,生命力为10,1
                    # #创建大敌机子弹
                    self.bigenemy.enemyfire(image_bullet0,4)
                    self.has_bigenemy = True
                    self.bigenemylife = self.ENEMYLIFE_TOP
                    #加入大敌机组
                    self.bigenemy_group.add(self.bigenemy)


            elif event.type == HERO_FIRE_EVENT:
                if not self.death_of_hero1:
                    self.hero1.fire(self.NUM_HERO_01,image_bullet1)
                if not self.death_of_hero2:
                    self.hero2.fire(self.NUM_HERO_02,image_bullet2)
            # 没有子弹,要找到原因,原因是没有将产生子弹并加入刷新
            #产生加子弹的道具事件
            elif event.type == CREAT_BULLET_ADD_ENENT:
                #利用敌机的精灵,产生加子弹的道具
                self.addbullet = Enemy(image_addbullet)
                self.addbullet_group.add(self.addbullet)

            elif event.type == CREAT_ENEMYPLANE_FIRE_ENENT:
                if self.has_bigenemy:
                    self.bigenemy.enemyfire(image_bullet0, 4)
                    # self.bigenemy.enemyfire(image_bullet0, 6)
                    # self.bigenemy.enemyfire(image_bullet0, 8)

        # 使用键盘提供的方法获取键盘按键
        keys_pressed = pygame.key.get_pressed()
            # 判断元祖中对应的按键索引值

            #hero控制键设置
        if keys_pressed[pygame.K_RIGHT]:
                # print("向右移动。。。")
            self.hero1.update(3,0)
        elif keys_pressed[pygame.K_LEFT]:
            self.hero1.update(-3,0)
        else:
            self.hero1.update(0,0)

        if keys_pressed[pygame.K_UP]:

            self.hero1.update(0,-3)
        elif keys_pressed[pygame.K_DOWN]:
            self.hero1.update(0,3)
        else:
            self.hero1.update(0,0)

        if keys_pressed[pygame.K_d]:
                # print("向右移动。。。")
            self.hero2.update(3,0)
        elif keys_pressed[pygame.K_a]:
            self.hero2.update(-3,0)
        else:
            self.hero2.update(0,0)

            # hero2控制键设置
        if keys_pressed[pygame.K_w]:

            self.hero2.update(0,-3)
        elif keys_pressed[pygame.K_s]:
                self.hero2.update(0,3)
        else:
            self.hero2.update(0,0)

        if keys_pressed[pygame.K_SPACE]:
            self.pause_game = not self.pause_game

    def __check_collide(self):
        # 1.子弹摧毁敌机
        self.sound_enemydown = SoundSprite(sound_ememydown0)
        #英雄1击中飞机
        shooted1=pygame.sprite.groupcollide(self.hero1.bullets, self.enemy_group, True, True)
        if len(shooted1) > 0:
            self.Score += len(shooted1)*100
            self.sound_enemydown.play()
            #将Score定义为playgame的类变量后,避免了相互之间引用,从而直接获得分数进行使用,过程中的调用设为全局变量的方法不好!
            # print(self.Score)
        shooted2 = pygame.sprite.groupcollide(self.hero2.bullets, self.enemy_group, True, True)
        if len(shooted2) > 0:
            self.Score += len(shooted2) * 100
            self.sound_enemydown.play()

        # 2.敌机撞毁英雄
        enemies1 = pygame.sprite.spritecollide(self.hero1, self.enemy_group, True)
        enemies2 = pygame.sprite.spritecollide(self.hero2, self.enemy_group, True)
        if len(enemies1) > 0:
            self.NUM_PLANE_HERO1-=1
            self.NUM_HERO_01 = 1
            if self.NUM_PLANE_HERO1 == 0:
                self.death_of_hero1 = True
                self.hero1.kill()

        if len(enemies2) > 0:
            self.NUM_PLANE_HERO2 -= 1
            self.NUM_HERO_02 = 1

            if self.NUM_PLANE_HERO2 == 0:
                self.death_of_hero2 = True
                self.hero2.kill()

        if self.death_of_hero1 and self.death_of_hero2:
             # 结束游戏
            PlaneGame.__game_over()

        #英雄战机听得到子弹增加道具
        #英雄1吃到道具
        eatted1 = pygame.sprite.spritecollide(self.hero1, self.addbullet_group, False)
        if len(eatted1)  > 0:
            #最多加到5个子弹
            if  self.NUM_HERO_01 <= 5:
                self.NUM_HERO_01 += 1
                self.addbullet_group.empty()
        # 英雄2吃到道具
        eatted2 = pygame.sprite.spritecollide(self.hero2, self.addbullet_group, False)
        if len(eatted2) > 0:
            if self.NUM_HERO_02 <=5:
                self.NUM_HERO_02 += 1
                self.addbullet_group.empty()
        #大敌机碰撞英雄

        #如果有大敌机,子弹互消,碰撞英雄
        if self.has_bigenemy:
            #子弹互消
            pygame.sprite.groupcollide(self.hero1.bullets, self.bigenemy.emeny_bullet_group, True, True)
            pygame.sprite.groupcollide(self.hero2.bullets, self.bigenemy.emeny_bullet_group, True, True)
            #英雄撞击大飞机
            enemies3 = pygame.sprite.spritecollide(self.hero1, self.bigenemy_group, True)
            enemies4 = pygame.sprite.spritecollide(self.hero2, self.bigenemy_group, True)
            #英雄子弹击中大飞机
            #TODO
            shooted3 = pygame.sprite.groupcollide(self.bigenemy_group, self.hero1.bullets, False,True)
            shooted4 = pygame.sprite.groupcollide(self.bigenemy_group, self.hero2.bullets, False,True)

            if len(shooted3)>0 or len(shooted4)>0:
                print("英雄子弹击中数为{0},大敌机的生命还有{1}".format(len(shooted3), self.bigenemylife))
                self.bigenemylife -=1
                if self.bigenemylife == 0 :
                    self.bigenemy.kill()
                    self.has_bigenemy = False
                    self.Score += len(shooted1) * 1000


            #英雄碰到大飞机子弹
            enemies5 = pygame.sprite.spritecollide(self.hero1, self.bigenemy.emeny_bullet_group, True)
            enemies6 = pygame.sprite.spritecollide(self.hero2, self.bigenemy.emeny_bullet_group, True)
            if len(enemies3)>0 or len(enemies5) >0:
                self.NUM_PLANE_HERO1 -= 1
                if self.NUM_PLANE_HERO1 == 0:
                    self.death_of_hero1 = True
                    self.hero1.kill()
            if len(enemies4)>0 or len(enemies6) >0:
                self.NUM_PLANE_HERO2 -= 1
                if self.NUM_PLANE_HERO1 == 0:
                    self.death_of_hero1 = True
                    self.hero1.kill()

    def __update_sprites(self):
        #背景组刷新
        self.back_group.update()
        self.back_group.draw(self.screen)

        #小敌机组更新
        self.enemy_group.update()
        self.enemy_group.draw(self.screen)

        #大敌机组更新
        self.bigenemy_group.update()
        self.bigenemy_group.draw(self.screen)

        #加子弹道具组更新
        self.addbullet_group.update()
        self.addbullet_group.draw(self.screen)

        #英雄组更新
        self.hero_group.update()
        self.hero_group.draw(self.screen)

        #英雄子弹组更新
        if not self.death_of_hero1:
            self.hero1.bullets.update()
            self.hero1.bullets.draw(self.screen)
        if not self.death_of_hero2:
            self.hero2.bullets.update()
            self.hero2.bullets.draw(self.screen)

        #大敌机子弹组更新
        if self.has_bigenemy:
            self.bigenemy.emeny_bullet_group.update()
            self.bigenemy.emeny_bullet_group.draw(self.screen)

        # for enemy in self.enemy_group:
        #     enemy.emeny_bullet_group.update(y_speed=3)
        #     enemy.emeny_bullet_group.draw(self.screen)


        #一开始在一起进行了定义和加组,但是由于不能循环刷新,所以分数不变化,只好改到此处
        self.label_score = Label("分数:" + str(self.Score), 0, 0)
        self.label_group = pygame.sprite.Group(self.label_score)

        #显示英雄飞机数
        self.labe_number_of_hero1 = Label("英雄1飞机数:"+str(self.NUM_PLANE_HERO1),0,0)
        self.labe_number_of_hero1.rect.bottomright = [480,700]
        if not self.death_of_hero1:
            self.label_group.add(self.labe_number_of_hero1)

        self.labe_number_of_hero2 = Label("英雄2飞机数:" + str(self.NUM_PLANE_HERO2), 0, 0)
        self.labe_number_of_hero2.rect.bottomleft = [0, 700]
        if not self.death_of_hero2:
            self.label_group.add(self.labe_number_of_hero2)



        self.label_group.update()
        self.label_group.draw(self.screen)

        # self.enemy_bullet_group.update()
        # self.emeny_bullet_group.draw(self.screen)





    # 下面的是静态方法
    @staticmethod
    def __game_over():
        print("游戏结束啦!!!")
        pygame.quit()
        exit()


if __name__ == '__main__':
    # 创建游戏对象
    game = PlaneGame()
    # 启动游戏
    game.start_game()

三、代码解析

(一)游戏开始界面的实现

1、生成label_single、label_double、label_tip精灵和开始界面的Surface对象

2、判断事件,获得鼠标和退出事件,判断是否在精灵范围内和是否点击左键

3、加组和显示

代码如下:

 def __creat_select_scence(self):
        
        # 1-1.创建选择界面,后添加的
        label_single = Label("单人游戏", 80, 200)
        label_single.rect.right = 240 - 40
        label_double = Label("双人游戏", 280, 200)
        label_double.rect.left = 240 + 40
        label_tip = Label("提示,按空格键暂停游戏", 240, 500)
        label_tip.rect.centerx = 240
        self.screen1 = pygame.display.set_mode(SCREEN_RECT.size)
        self.screen1.fill(color=pygame.Color(255,255,255))
        # print("运行到加组位置")
        #判断输入,
        for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                print("游戏结束,退出程序!!")
                PlaneGame.__game_over()
        mouse_position = pygame.mouse.get_pos() #获得鼠标位置
        mouse_x = mouse_position[0]
        mouse_y = mouse_position[1]
        mouse_pressed = pygame.mouse.get_pressed()#获得鼠标按键
        is_leftbutton = mouse_pressed[0]
        #判断鼠标是否在标签上,是否点击
        if (mouse_x > label_single.rect.x) and (mouse_x < (label_single.rect.x + label_single.rect.width)) and (
                mouse_y > label_single.rect.y) and (mouse_y < (label_single.rect.y + label_single.rect.height)):
            self.lable_single = Label("单人游戏", 80, 200)
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = True
                self.begin_game = True
        if (mouse_x > label_double.rect.x) and (mouse_x < (label_double.rect.x + label_double.rect.width)) and (
                mouse_y > label_double.rect.y) and (mouse_y < (label_double.rect.y + label_double.rect.height)):
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = False
                self.begin_game = True

        self.begin_group = pygame.sprite.Group(label_single, label_double,  label_tip)
        # 加载开始菜单label组

        self.begin_group.draw(self.screen1)

        pygame.display.update()

语法提示:

①mouse_position = pygame.mouse.get_pos() #获得鼠标位置

pygame.mouse.get_pos() 获取鼠标光标的位置。

get_pos() -> (x, y)

返回鼠标光标的坐标 (x, y)。这个坐标以窗口左上角为基准点。光标位置可以被定位于窗口之外,但是通常被强制性限制在屏幕内。

代码:mouse_x = mouse_position[0]
           mouse_y = mouse_position[1]

则是获得鼠标的x,y值

②  mouse_pressed = pygame.mouse.get_pressed()#获得鼠标按键
        is_leftbutton = mouse_pressed[0]

pygame.mouse.get_pressed()
获取鼠标按键的情况(是否被按下)。

get_pressed() -> (button1, button2, button3)

返回一个由布尔值组成的列表,代表所有鼠标按键被按下的情况。True 意味着在调用此方法时该鼠标按键正被按下。

注1:获取所有的鼠标事件最好是使用 pygame.event.wait() 方法或者 pygame.event.get() 方法,然后检查确认所有事件是 MOUSEBUTTONDOWN、MOUSEBUTTONUP 或者 MOUSEMOTION。

注2:在使用此方法前记住要先调用 pygame.event.get() 方法,否则此方法将不会工作。

注3:(button1, button2, button3),一般是左键、中键、右键,根据系统不同有时也有差别。

(二)双人单人游戏控制

1、设定布尔值

#英雄是否死亡
death_of_hero1 = True
death_of_hero2 = True

2、根据选择,设定值 

#判断鼠标是否在标签上,是否点击
        if (mouse_x > label_single.rect.x) and (mouse_x < (label_single.rect.x + label_single.rect.width)) and (
                mouse_y > label_single.rect.y) and (mouse_y < (label_single.rect.y + label_single.rect.height)):
            self.lable_single = Label("单人游戏", 80, 200)
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = True
                self.begin_game = True
        if (mouse_x > label_double.rect.x) and (mouse_x < (label_double.rect.x + label_double.rect.width)) and (
                mouse_y > label_double.rect.y) and (mouse_y < (label_double.rect.y + label_double.rect.height)):
            if is_leftbutton:
                self.death_of_hero1 = False
                self.death_of_hero2 = False
                self.begin_game = True

3、根据选定情况,进行选择加组

#必须先创建,否则后面使用会报错!
        self.hero1 = Hero(image_hero1)
        self.hero2 = Hero(image_hero2)

        #根据选择的玩家情况进行加组
        if not self.death_of_hero1:
            self.hero_group.add(self.hero1)

        if not self.death_of_hero2:
            self.hero_group.add(self.hero2)

此处应当注意,必须将英雄都创建,如果判断后生成,会造成报错。

(三)利用自定义事件

1、创建自定义事件常量

# 创建敌机的定时器常量,自定义事件
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹时间,自定义事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
#出现加子弹道具的事件
CREAT_BULLET_ADD_ENENT =pygame.USEREVENT + 2
#出现敌机发射子弹的事件
CREAT_ENEMYPLANE_FIRE_ENENT = pygame.USEREVENT + 3

pygame.USEREVENT,相关内容参考我以前的文章,这里不再多说。

2、设置定时器事件,设定产生间隔

 # 4.设置定时器事件
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
        pygame.time.set_timer(HERO_FIRE_EVENT, 500)
        pygame.time.set_timer(CREAT_BULLET_ADD_ENENT,50000)
        pygame.time.set_timer(CREAT_ENEMYPLANE_FIRE_ENENT,3000)

pygame.time.set_timer()
功能:在事件队列上重复创建事件

属性:

set_timer(eventid, milliseconds) -> None
set_timer(eventid, milliseconds, once) -> None
将事件类型设置为每隔给定的毫秒出现在事件队列中。第一个事件在经过一定时间后才会出现。
每个事件类型都可以附加一个单独的计时器。最好使用 pygame.USEREVENT 和 pygame.NUMEVENTS的值。
若要禁用事件的计时器,请将毫秒参数设置为0。
如果once参数为True,则只发送计时器一次。

3、监听事件,作出相应处理

        for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                print("游戏结束,退出程序!!")
                PlaneGame.__game_over()
            elif event.type == CREATE_ENEMY_EVENT:
                 # print("敌机出场。。。")
                # 创建敌机精灵
                self.enemy = Enemy(image_enemy,2,3)
                self.enemy_group.add(self.enemy)

                self.NUM_ENEMY += 1
                if self.NUM_ENEMY %50 == 0:
                    #TODO 修改飞机敌机出现的频次
                    self.bigenemy =Enemy(image_enemy1,1,1)
                    #TODO 加入大敌机,能发射子弹,生命力为10,1
                    # #创建大敌机子弹
                    self.bigenemy.enemyfire(image_bullet0,4)
                    self.has_bigenemy = True
                    self.bigenemylife = self.ENEMYLIFE_TOP
                    #加入大敌机组
                    self.bigenemy_group.add(self.bigenemy)


            elif event.type == HERO_FIRE_EVENT:
                if not self.death_of_hero1:
                    self.hero1.fire(self.NUM_HERO_01,image_bullet1)
                if not self.death_of_hero2:
                    self.hero2.fire(self.NUM_HERO_02,image_bullet2)
            #产生加子弹的道具事件
            elif event.type == CREAT_BULLET_ADD_ENENT:
                #利用敌机的精灵,产生加子弹的道具
                self.addbullet = Enemy(image_addbullet)
                self.addbullet_group.add(self.addbullet)

            elif event.type == CREAT_ENEMYPLANE_FIRE_ENENT:
                if self.has_bigenemy:
                    self.bigenemy.enemyfire(image_bullet0, 4)
                   

(四)利用精灵Sprite和精灵组Group的碰撞检测

1、利用两种碰撞模式,一种是组与组的碰撞,一种是个体与组的碰撞,语法的用法上一篇文章介绍过了,这里不多说。

2、主要检测以下几个碰撞:

(1)英雄子弹与敌机

(2)英雄与敌机

(3)英雄与加子弹道具

(4)英雄子弹与大敌机子弹

(5)英雄子弹与大敌机

具体代码如下:

    def __check_collide(self):
        # 1.子弹摧毁敌机
        self.sound_enemydown = SoundSprite(sound_ememydown0)
        #英雄1击中飞机
        shooted1=pygame.sprite.groupcollide(self.hero1.bullets, self.enemy_group, True, True)
        if len(shooted1) > 0:
            self.Score += len(shooted1)*100
            self.sound_enemydown.play()
        shooted2 = pygame.sprite.groupcollide(self.hero2.bullets, self.enemy_group, True, True)
        if len(shooted2) > 0:
            self.Score += len(shooted2) * 100
            self.sound_enemydown.play()

        # 2.敌机撞毁英雄
        enemies1 = pygame.sprite.spritecollide(self.hero1, self.enemy_group, True)
        enemies2 = pygame.sprite.spritecollide(self.hero2, self.enemy_group, True)
        if len(enemies1) > 0:
            self.NUM_PLANE_HERO1-=1
            self.NUM_HERO_01 = 1
            if self.NUM_PLANE_HERO1 == 0:
                self.death_of_hero1 = True
                self.hero1.kill()

        if len(enemies2) > 0:
            self.NUM_PLANE_HERO2 -= 1
            self.NUM_HERO_02 = 1

            if self.NUM_PLANE_HERO2 == 0:
                self.death_of_hero2 = True
                self.hero2.kill()

        if self.death_of_hero1 and self.death_of_hero2:
             # 结束游戏
            PlaneGame.__game_over()

        #英雄战机听得到子弹增加道具
        #英雄1吃到道具
        eatted1 = pygame.sprite.spritecollide(self.hero1, self.addbullet_group, False)
        if len(eatted1)  > 0:
            #最多加到5个子弹
            if  self.NUM_HERO_01 <= 5:
                self.NUM_HERO_01 += 1
                self.addbullet_group.empty()
        # 英雄2吃到道具
        eatted2 = pygame.sprite.spritecollide(self.hero2, self.addbullet_group, False)
        if len(eatted2) > 0:
            if self.NUM_HERO_02 <=5:
                self.NUM_HERO_02 += 1
                self.addbullet_group.empty()
        #大敌机碰撞英雄

        #如果有大敌机,子弹互消,碰撞英雄
        if self.has_bigenemy:
            #子弹互消
            pygame.sprite.groupcollide(self.hero1.bullets, self.bigenemy.emeny_bullet_group, True, True)
            pygame.sprite.groupcollide(self.hero2.bullets, self.bigenemy.emeny_bullet_group, True, True)
            #英雄撞击大飞机
            enemies3 = pygame.sprite.spritecollide(self.hero1, self.bigenemy_group, True)
            enemies4 = pygame.sprite.spritecollide(self.hero2, self.bigenemy_group, True)
            #英雄子弹击中大飞机
            #TODO
            shooted3 = pygame.sprite.groupcollide(self.bigenemy_group, self.hero1.bullets, False,True)
            shooted4 = pygame.sprite.groupcollide(self.bigenemy_group, self.hero2.bullets, False,True)

            if len(shooted3)>0 or len(shooted4)>0:
                self.bigenemylife -=1
                if self.bigenemylife == 0 :
                    self.bigenemy.kill()
                    self.has_bigenemy = False
                    self.Score += len(shooted1) * 1000


            #英雄碰到大飞机子弹
            enemies5 = pygame.sprite.spritecollide(self.hero1, self.bigenemy.emeny_bullet_group, True)
            enemies6 = pygame.sprite.spritecollide(self.hero2, self.bigenemy.emeny_bullet_group, True)
            if len(enemies3)>0 or len(enemies5) >0:
                self.NUM_PLANE_HERO1 -= 1
                if self.NUM_PLANE_HERO1 == 0:
                    self.death_of_hero1 = True
                    self.hero1.kill()
            if len(enemies4)>0 or len(enemies6) >0:
                self.NUM_PLANE_HERO2 -= 1
                if self.NUM_PLANE_HERO1 == 0:
                    self.death_of_hero1 = True
                    self.hero1.kill()

(五)获取键盘控制键

1、获取键值

2、根据需要设置键值对应的代码

# 使用键盘提供的方法获取键盘按键
        keys_pressed = pygame.key.get_pressed()
            # 判断元祖中对应的按键索引值

            #hero控制键设置
        if keys_pressed[pygame.K_RIGHT]:
                # print("向右移动。。。")
            self.hero1.update(3,0)
        elif keys_pressed[pygame.K_LEFT]:
            self.hero1.update(-3,0)
        else:
            self.hero1.update(0,0)

        if keys_pressed[pygame.K_UP]:

            self.hero1.update(0,-3)
        elif keys_pressed[pygame.K_DOWN]:
            self.hero1.update(0,3)
        else:
            self.hero1.update(0,0)

        if keys_pressed[pygame.K_d]:
                # print("向右移动。。。")
            self.hero2.update(3,0)
        elif keys_pressed[pygame.K_a]:
            self.hero2.update(-3,0)
        else:
            self.hero2.update(0,0)

            # hero2控制键设置
        if keys_pressed[pygame.K_w]:

            self.hero2.update(0,-3)
        elif keys_pressed[pygame.K_s]:
                self.hero2.update(0,3)
        else:
            self.hero2.update(0,0)

        if keys_pressed[pygame.K_SPACE]:
            self.pause_game = not self.pause_game

代码注释:

代码中呈现了两种捕获键盘的方式:

第一种:在pygame中使用pygame.event.get()方法捕获键盘事件,使用这个方式捕获的键盘事件必须要是按下再弹起才算一次。

 for event in pygame.event.get():
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                print("游戏结束,退出程序!!")
                PlaneGame.__game_over()


第二种:在pygame中可以使用pygame.key.get_pressed()来返回所有按键元组,通过判断键盘常量,可以在元组中判断出那个键被按下,如果被按下则元组中就会存在这个按键信息。通过这样的方式也可以捕获到键盘的事件,并且不需要按下再弹起的操作,一按下就会有响应,灵活性比较高。

示例代码:

keys_pressed = pygame.key.get_pressed()
            # 判断元祖中对应的按键索引值

            #hero控制键设置
        if keys_pressed[pygame.K_RIGHT]:
                # print("向右移动。。。")
            self.hero1.update(3,0)
        elif keys_pressed[pygame.K_LEFT]:
            self.hero1.update(-3,0)

其他的相关知识,己在前面的文章介绍过,如果有疑问,可以查找以前的文章。想与本人议论可以留言,我们共同进步。

猜你喜欢

转载自blog.csdn.net/sygoodman/article/details/124403291
今日推荐