Python实战之小飞机--代码

import  pygame
import  time
from Sprite_class import *
class PlaneGame(object):
    """飞机大战主游戏"""
    def __init__(self):
        print("游戏初始化")
        #1. 创建游戏的窗口
        self.screen=pygame.display.set_mode(SCREEN_RECT.size)# 这里面要求传递一个元组,SCREEN_RECT.size 刚好就是得到元组
        #2. 创建游戏的时钟
        self.clock =pygame.time.Clock()
        #3. 调用私有方法,精灵和精灵组的创建
        self.__creat_sprites()#这个方法不能在while True 里面调用
        #::设置定时器事件--创建敌机  1s出一架飞机
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 500)

        pygame.time.set_timer(HERO_FIRE_EVENT,500)
    def __creat_sprites(self):
        #私有方法 以__开头
        # 创建背景精灵 和精灵组
        bg1 = Background()
        bg2 = Background(is_alt=True)
        bg2.rect.y=-bg2.rect.height
        self.back_group = pygame.sprite.Group(bg1,bg2)
        #创建敌机 精灵组
        self.enemy_group = pygame.sprite.Group()

        #创建英雄的精灵和精灵组
        self.hero = Hero()  #需要把英雄精灵  变成属性  因为要在其他地方调用
        self.hero_group =pygame.sprite.Group(self.hero)

        # 在这个方法中 创建精灵和精灵组
        # 让精灵组调用update 和draw()方法
    def start_game(self):
        print("游戏开始.....")

        while True:

            # 1.设置刷新帧率
            self.clock.tick(FRAME_PER_SEC)
            # 2.事件监听
            self.__event_handler()
            # 3.碰撞检测
            self.__check_collide()
            # 4.更新/绘制精灵组
            self.__update_sprites()
            # 5.更新显示
            pygame.display.update()


    def __event_handler(self):
        # 判断是否退出游戏
        for event in pygame.event.get():#遍历列表
            if event.type==pygame.QUIT:
                 PlaneGame.__game_over()  #静态方法使用类名调用
            elif event.type ==CREATE_ENEMY_EVENT:
                # print("敌机出场...")
                #创建敌机精灵
                enemy_sprites =Enemy()
                self.enemy_group.add(enemy_sprites)
            #通过 监听事件的方式  这种方式不可以 按键盘 一直触发
            # elif event.type==pygame.KEYDOWN and event.key ==pygame.K_RIGHT:
            #     print("向右移动...")
        #使用键盘提供的方法 获取 键盘按键: 可以按一次,一直触发
              # 这个时要被遍历的开火 事件!!!
            if event.type == HERO_FIRE_EVENT:
                self.hero.fire()



        # 返回一个 按键元组
        keys_pressed = pygame.key.get_pressed()
        #怎么使用这个元组? 判断元组中 对应按键的索引值

        if keys_pressed[pygame.K_RIGHT]:
            # print("向右移动")
            self.hero.rect.x+=5
        elif keys_pressed[pygame.K_LEFT]:
            # print("向左移动")
            self.hero.rect.x-=5
        elif keys_pressed[pygame.K_UP]:
             # print("向前移动")
             self.hero.rect.y-=5
        elif keys_pressed[pygame.K_DOWN]:
             # print("向后移动")
             self.hero.rect.y+=5



    def __check_collide(self):
        #1 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets,self.enemy_group,True,True)
        #2 敌机撞毁英雄
        enemies =pygame.sprite.spritecollide(self.hero,self.enemy_group,True)
        #判断 enemies 列表是否有内容,有内容的话就 把英雄干掉
        if len(enemies):
            time.sleep(2)
            print("英雄牺牲")
            self.hero.kill()
            time.sleep(1)
            PlaneGame.__game_over()
    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.hero_group.update()
        self.hero_group.draw(self.screen)
        #
        self.hero.bullets.update()
        self.hero.bullets.draw(self.screen)
    def __update_screen(self):
        pass
    @staticmethod #静态方法  不需要传参
    def __game_over():
        print("游戏结束")
        pygame.quit()
        exit()

if __name__ == '__main__':
    #编写在主程序中直接执行的
    pygame.init()
   #创建游戏对象
    game =PlaneGame()
   #开始游戏
    game.start_game()



"""
使用常量 都代替固定的数值
   1 常量--- 不变化的量
   2 变量--- 可以变化的量
   
 应用场景:
    1--在开发时,可能会需要使用固定的数值,例如屏幕的高度是700
    2--在这个时候,简易不要直接使用固定数值,而应该使用常量
    3--在开发时,为了保证代码的可维护性,尽量不要使用魔法数字
    
 常量的定义:
    1-- 定义常量和定义变量的语法完全一样,都是使用赋值语句
    2-- 常量的命名应该所有字母都是用大写,单词与单词之间使用下划线连接
        提示:PYthon中并没有真正意义的常量,只是通告命名的约定---所有字母都大写的就是常量。开发时不要轻易修改
"""

#:2 游戏精灵库代码:

#导入随机模块
import  random
import pygame

"""
导入模块的顺序:
1 官方标准模块导入
2 第三方模块导入
3 应用程序模块导入
"""
pygame.init()
SCREEN_RECT=pygame.Rect(0,0,480,700)
FRAME_PER_SEC = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT #
# 英雄发射子弹的事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
class GameSprite(pygame.sprite.Sprite):
     def __init__(self,image_name,speed=1):
        #调用父类的初始化方法
          super().__init__()  # 子类的父类不是 object  不主动调用,就没有办法享用到父类的 初始化代码
        #定义对象的属性
          self.image=pygame.image.load(image_name)
          self.rect = self.image.get_rect() # 返回图像大小,且x,y
          self.speed = speed
     def update(self):
         # 在屏幕的垂直方向上移动    改变其y值
         self.rect.y += self.speed

class Background(GameSprite):
    """游戏背景精灵"""
    def __init__(self,is_alt=False):
    #     #1.调用父类方法实现精灵的创建(image/rect/speed)
         super().__init__("./images/background.png")
    #     #2.判断是否交替图像,如果是,需要设置初始位置
         if is_alt:
            self.rect.y=-self.rect.height
    def update(self):
         # 1. 调用父类的方法实现
         super().update()
         # 2. 判断是否移出屏幕,(背景轮动)如果移除屏幕,将图像设置到屏幕的上方
         if self.rect.y>=SCREEN_RECT.height:
             self.rect.y=-self.rect.height

class Enemy(GameSprite):
    """敌机精灵"""
    def __init__(self):
        #1.调用父类方法,创建敌机精灵,同时指定敌机图片
        super().__init__("./images/enemy1.png")
        #2.指定敌机的初始随机速度  1-3
        self.speed= random.randint(3,6) # 随机数的最小值,随机数的最大值
        #3.指定敌机的初始随机位置
        self.rect.bottom= 0
        self.rect.x=random.randint(0,480-self.rect.width)
        pass
        """
        使用pygame.Rect 提供的bottom属性,在指定敌机初始位置时,会比较方便
         bottom =y +height
         y=bottom-height
        """
    def update(self):
        #1.调用父类方法,(游戏精灵父类中实现了垂直飞行)  保持垂直方向的飞行
        super().update()
        #2.判断是否飞出屏幕,如果废除,需要从精灵组中删除敌机
        if self.rect.y >=SCREEN_RECT.height:
            # print("飞出屏幕,需要从精灵组删除....")
            #kill 方法可以将精灵从所有精灵组中移出,精灵就会被自动销毁
            self.kill()


        """
        移出屏幕销毁敌机:
          从敌机组删除,否则会造成内存浪费
        检测敌机被销毁
         __del__ 内置方法 会在对象被  销毁 前调用,  在开发中,可以用于 判断对象是否被销毁
         def __del__(self):
         
         销毁敌机的方法
         kill() 方法, 删除某个精灵  从所有组,内存
        """
    def __del__(self):
        # print("敌机挂了 %s "% self.rect)
        pass
class Hero(GameSprite):
    """
    英雄需求:
    1 英雄初始位置   屏幕 水平中间位置, 距离屏幕底部 120px
    2 英雄每隔0.5s 发射一次子弹,每次连发三枚子弹
    3 英雄默认不会移动,需要通过左/右 方向键,控制英雄在水平方向移动

    子弹需求:
     1:子弹从英雄的正上方发射 沿直线 向上方飞行
     2:飞出屏幕后,需要从 精灵组中 删除
    """
    def __init__(self):
        super().__init__("./images/me1.png")
        self.speed = 0
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 120
        #创建子弹精灵组
        self.bullets =pygame.sprite.Group()
    def update(self):
        #英雄在水平方向移动:
        self.rect.x +=self.speed
        self.rect.y +=self.speed
        #控制英雄不能离开屏幕
        if self.rect.x<=0 :
            self.rect.x=0
        if self.rect.x>SCREEN_RECT.width-self.rect.width:
            self.rect.x=SCREEN_RECT.width-self.rect.width

        if self.rect.y<=0:
            self.rect.y=0
        if self.rect.y>=SCREEN_RECT.height-self.rect.height:
            self.rect.y=SCREEN_RECT.height-self.rect.height

    def fire(self):
     # print("发射子弹...")
     #一次发射三枚子弹
     for i in (0,1,2):
        #1.创建子弹精灵
        bullet = Bullets()
        #2 设置精灵的位置
        bullet.rect.bottom=self.rect.y-i*bullet.rect.height
        bullet.rect.centerx=self.rect.centerx
        #3 将精灵添加到精灵组
        self.bullets.add(bullet)



class Bullets(GameSprite):
    """子弹精灵"""
    def __init__(self):
        super().__init__("./images/bullet1.png",-3)
        #调用父类方法,设置子弹图片,设置初始速度

    def update(self):
        super().update()
        #判断子弹是否飞出屏幕
        if self.rect.bottom<0:
            #表示子弹已经飞出了屏幕
            self.kill()
    def __del__(self):
        pass
        # print("子弹被销毁")
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值