15 飞机大战:pygame入门、python基础串连

0 pygame模块的导入

  • import pygame导入pygame包
  • 使用pygame.init()导入pygame的所有模块。只有导入模块pygame才能使用。
  • 使用pygame.quit()卸载pygame的所有模块。游戏结束后,释放内存。

1 pygame.Rect :用于描述矩形区域的类

创建矩形对象的命令:变量 = Rect(x,y,width,height)

Rect中的size属性:用于封装对象的宽和高。

Rect的对象储存该对象的坐标元组,因此可以直接使用Rect的对象当坐标作其它方法的形参。

2 游戏设计的思路

我们把程序分成两个部分:游戏的初始化部分和游戏循环

 

在代码中如下表现:

import pygame

pygame.init()
# 游戏的初始化部分
# 绘制游戏窗口
screen =pygame.display.set_mode((480,700))
# 绘制图像
bg = pygame.image.load("./images/background.png")
hero = pygame.image.load("./images/me1.png")
# 加载图像
screen.blit(bg,(0,0))
screen.blit(hero,(0,0))
# 设置游戏时钟 # 更新图像 pygame.display.update() # 游戏循环 -> 意味着游戏的开始 while True: pass pygame.quit()

  

3 绘制游戏的主窗口:pygame.display模块

set_mode()方法:创建游戏窗口

set_mode(resolution=(0,0),flag=0,depth=0) ->Surface

  参数详解:

  • resolution即分辨率,调用此方法时不用再写resolution=。直接写分辨率元组。
  • flags参数指定屏幕的附加选项,如屏幕是否全屏等。
  • depth参数表示颜色的位数,默认自动匹配。
  • ->表示返回Surface,暂时理解为返回一个屏幕(或画板),需要使用一个变量接收这个方法。

举个例子:

screen = pygame.display.set_mode((550,550))
#创建一个550x550的黑色屏幕
#程序执行结束后,屏幕即关闭,所以,在代码最下方写一个while死循环让程序不停止可以暂时解决问题

  

4 绘制图像

窗口中你能看见的图像,都是绘制上去的,如游戏背景,游戏角色等等。

绘制图像需要三步:

1.使用pygame.image.load()加载图像的数据

2.使用游戏屏幕对象调用blit方法将图像绘制到指定位置

3.调用pygame.display.update()方法更新屏幕的显示

细节:

  • load()方法,括号中写图像的路径:如:./images/1.png。load()方法需要一个变量来接收,通常命名为图片的名称。如:background = pygame.image.load("./images/1.png") (注:点表示当前文件所在的目录,文件路径要用字符串形式
  • blit()方法,括号中的参数为:图像名(即接收load方法的变量),位置(左上角为0,0,右x正,下y正)
  • update()方法必须有,不然不会显示

5 pygame.time模块及设置游戏时钟

time模块能提供一些关于时间的工具,其中Clock类用来作为游戏的时钟对象。

时钟对象包含很多方法,如后续要使用到的刷新频率(绘制频率)方法tick()。

创建一个时钟对象:

clock = pygame.time.Clock()

  

6 刷新频率方法:tick()

此方法为Clock类下的一个方法,用来设置绘制刷新的频率。

用法如:

clock.tick(60) #60表示60帧/s

  

7 简单的图像移动实现及残影问题解决

使图像移动的思路

  • 新建一个矩形框对象(使用pygame.Rect),使它的初始位置等于代表的图片的初始位置,它的宽高为代表的图片的宽高。
  • 在某种条件下(如每循环一次,如用户按下某个键),使得矩形框的坐标发生变化,而矩形框对象代表的图片按照变化后的坐标绘制图像,即实现了图片的移动。

残影的问题及解决方法

  • 如果仅绘制..飞机不绘制背景图的话,飞机就会留下残影,解决方法是,每次绘制都必须绘制背景,且背景优先绘制(代码写前面)。

简单移动示例

  • 随着while循环的不断执行,让飞机的矩形框对象的座标不断发生改变。
  •  while True:
        clock.tick(60) #60表示60帧/s 
        # 主角飞机矩形框移动
        hero_rect.y -= 1 #hero_rect对象为飞机的矩形框对象
        if hero_rect.y <= -126: 
            hero_rect.y=700
        # 绘制
        screen.blit(bg,(0,0)) #先画背景!
        screen.blit(hero,hero_rect) #再画飞机。here_rect对象储存矩形框的位置元组
        # 更新显示
        pygame.display.update()
    

      

8 事件的概念及监听的概念

事件

  • 事件即用户对游戏做的操作,如鼠标点击、按下键盘、关闭游戏等。

监听

  • 监听用来精准判断用户做的事件。只有捕捉到用户做的事件,才能对其作出响应。

监听代码(捕获事件)

  • 可以通过以下代码获得当前用户所做的所有操作的事件列表(用户可以同时做很多事件)
event_list = pygame.event.get()

  使用print方法输出事件列表查看事件

event_list = pygame.event.get()
    if len(event_list) > 0:#没有事件时不输出
        print(event_list)

  获取一段事件列表如下

[<Event(5-MouseButtonDown {'pos': (391, 607), 'window': None, 'button': 1})>]
[<Event(6-MouseButtonUp {'pos': (391, 607), 'window': None, 'button': 1})>]
[<Event(4-MouseMotion {'rel': (0, 2), 'pos': (391, 609), 'buttons': (0, 0, 0), 'window': None})>]

  

9 处理捕获到的事件(响应)

思路

  • 捕获的是一个事件列表,我们使用for遍历,当遍历到的内容有我们想要的内容时,做出我们想要指定的操作。
  • 如:遍历到Quit事件(点击红叉关闭窗口),我们就要写一个关闭游戏的代码(不写关不了)。

事件类型

示例:Quit事件的处理

  • 使用循环遍历事件列表
  • 当列表中有Quit事件时
  • 执行exit()方法退出程序
  •     for event in event_list:
            if event.type == pygame.QUIT:
                exit() #退出程序
    

 

10 精灵及精灵组

传统游戏设计思路的局限性

  • 使用传统的游戏设计思路,需要程序要对每张图像针对很多事件作不同的操作,代码量大,不美观。

精灵及精灵组横空出世

  • pygame下的模块sprite及它的两个类Sprite、Group
  • pygame.sprite.Sprite 精灵类,我们可以把精灵看做角色
  • pygame.sprite.Group  而精灵组就是角色组

 

11 新的游戏思路

planeGame为游戏的入口,它要设置一系列的属性和方法。

 

 

12 精灵详解

我们可以把精灵看做角色,而精灵组看作角色组。

使用精灵来统一定义某个角色类如:己方飞机类,敌方飞机类,boss类等。

为了规范,python精灵要专门占据一个python文件

精灵类需要派生子类,也就是说精灵类并不是一个具体的角色类,它派生的子类才是。

示例,派生英雄子类:

思路:

  • 使用init方法传入两个变量,图片地址和初始速度,初始速度默认值为1。
  • 使用load方法加载图像
  • 使用get_rect方法获得图像对象的矩形框,如:self.rect = self.image.get_rect() 其中image为加载后的image变量。
  • 通过update方法调整矩形的位置

13 滚动背景的方法

 

 

思路

  • 使用两张背景图,在两张背景向下移动的过程中,当第1张图完全移出屏幕后,立即将第一张图的坐标改为初始位置1。当第二张图完全移出屏幕时,立即将第二张图的坐标位置改为位置1。如此循环即可。

 

14 添加敌机与定时器set_timer()

定时器

  • set_timer(eventid, milliseconds) -> None

  参数说明:第一个参数eventid通常基于常量pygame.USEREVENT来指定

  • USEREVENT是一个整数,再增加的事件可以使用USEREVENT+ 1来指定,以此类推

定义并监听创建敌机的定时器事件

  • pygame的定时器使用套路非常固定
  • 1.定义定时器变量 eventid
  • 2.在初始化方法中,调用set_timer方法设置定时器事件
  • 3.在游戏循环中,监听定时器事件

15 Rect类bottom属性、

bottom=y + height

当把bottom设置为0时,飞机的y就为负的height,飞机就会从屏幕外一个飞机height的距离飞进来。

16 销毁精灵 kill()方法

即使消除不需要的对象可以释放内存。

kill()方法可以将精灵从所有组中销毁

17 我方飞机(英雄)及

初始化方法

  • 指定英雄图片
  • 初始速度=0
  • 指定英雄初始位置
  • 定义bullets子弹精灵组保存子弹

重写update方法

  • 英雄需要水平移动
  • 保证不能移出屏幕

增加bullets属性,记录所有子弹精灵

增加fire方法,用于发射子弹

18 获取键盘事件方法pygame.key.get_pressed()及英雄移动

此方法返回键盘的元组,每个键盘都有一个值,当键盘没有被触发时,值为0,当键盘被按下时,值为1

       # 方法一:此方法按下键盘只触发一次操作
            if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:#KEYDDOWN表示事件类型为按下键盘,K_RIGHT表示右键
                print("按下右键")
            # 方法二:使用键盘元组来判断是否按键,解决按下只被执行一次的问题
            keys_pressed = pygame.key.get_pressed()
            # 判断元组中对应的按键索引值是否为1(1为按下)
            if keys_pressed[pygame.K_RIGHT]:
                print("向右移动..")

 

19 子弹事件

先写一个英雄开火的方法

    def fire(self):
        print("发射子弹")#先不用具体写

  

子弹每隔500ms就会从英雄发出,所以需要用到事件,同创造敌机事件类似,首先:创造子弹事件。

创造子弹事件常量:

HERO_FIRE_EVENT = pygame.USEREVENT + 1 #我也不知道为啥具体,总之因为创造敌机事件使用了USEREVENT
所以这里要+1

  

设置定时器-子弹事件

 pygame.time.set_timer(HERO_FIRE_EVENT,500)

  

在监听器中监听事件

            elif event.type == HERO_FIRE_EVENT:
                self.hero.fire()#监听到则执行英雄的fire方法

  

20 定义子弹类

因为子弹也是对象,对于物体,要写一个独立的类。

  • 子弹从英雄的正上方向上发射
  • 子弹超出屏幕则销毁

20 绘制子弹

和背景、英雄、敌机一样,要显示在屏幕,就要绘制出来。

创建子弹精灵组

在监听器中监听子弹事件,如果监听到,则在fire方法中新建子弹对象,并加入子弹精灵组。

子弹精灵组update、draw

21 精灵组碰撞销毁方法groupcollide

pygame的精灵模块提供了一个精灵组碰撞方法,非常好用。

groupcollide(group1,group2,dokill1,dokill2,collided = None)-->Sprite_dict

  第一个及第二个参数为:要检测碰撞的两个精灵组,第三个第四个参数时布尔型,True就表示碰撞后代表的精灵组被销毁,第五个我不知道。

碰撞检测方法卸载主程序的__check_collide中

22 精灵与精灵组的碰撞销毁方法spritecollide

精灵与精灵组的碰撞销毁

pygame.sprite.spritecollide(sprite,group,dokill,collided=None)->Sprite_list

  第一个参数为精灵

  第二个参数为精灵组

  当dokill为True时,精灵与精灵组发生碰撞,死掉的是精灵组的成员。当False,谁都不会死

  方法的返回值Sprite_list为精灵组,如果发生碰撞返回精灵组。

  要想精灵死,需要利用这个方法的返回值:

 enemys = pygame.sprite.spritecollide(self.hero,self.enemy_group,False)
        #让英雄死
        if len(enemys) > 0:
            self.hero.kill()

  

  

 

posted @ 2019-10-24 22:06  Scorpicat  阅读(369)  评论(0编辑  收藏  举报