zoukankan      html  css  js  c++  java
  • 正则表达式

    正则表达式

    re模块

    就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

    字符匹配(普通字符,元字符):

    1 普通字符:大多数字符和字母都会和自身匹配
                  >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                          ['alvin'] 

    2 元字符:. ^ $ * + ? { } [ ] | ( )

    元字符之. ^ $ * + ? { }

     1 import re
     2  
     3 ret=re.findall('a..in','helloalvin')
     4 print(ret)#['alvin']
     5  
     6  
     7 ret=re.findall('^a...n','alvinhelloawwwn')
     8 print(ret)#['alvin']
     9  
    10  
    11 ret=re.findall('a...n$','alvinhelloawwwn')
    12 print(ret)#['awwwn']
    13  
    14  
    15 ret=re.findall('a...n$','alvinhelloawwwn')
    16 print(ret)#['awwwn']
    17  
    18  
    19 ret=re.findall('abc*','abcccc')#贪婪匹配[0,+oo]  
    20 print(ret)#['abcccc']
    21  
    22 ret=re.findall('abc+','abccc')#[1,+oo]
    23 print(ret)#['abccc']
    24  
    25 ret=re.findall('abc?','abccc')#[0,1]
    26 print(ret)#['abc']
    27  
    28  
    29 ret=re.findall('abc{1,4}','abccc')
    30 print(ret)#['abccc'] 贪婪匹配

    注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配.

    1 ret=re.findall('abc*?','abcccccc')
    2 print(ret)#['ab']

    元字符之字符集[]:

     1 #--------------------------------------------字符集[]
     2 ret=re.findall('a[bc]d','acd')
     3 print(ret)#['acd']
     4  
     5 ret=re.findall('[a-z]','acd')
     6 print(ret)#['a', 'c', 'd']
     7  
     8 ret=re.findall('[.*+]','a.cd+')
     9 print(ret)#['.', '+']
    10  
    11 #在字符集里有功能的符号: - ^ 
    12  
    13 ret=re.findall('[1-9]','45dha3')
    14 print(ret)#['4', '5', '3']
    15  
    16 ret=re.findall('[^ab]','45bdha3')
    17 print(ret)#['4', '5', 'd', 'h', '3']
    18  
    19 ret=re.findall('[d]','45bdha3')
    20 print(ret)#['4', '5', '3']

    元字符之转义符

    反斜杠后边跟元字符去除特殊功能,比如.
    反斜杠后边跟普通字符实现特殊功能,比如d

    d  匹配任何十进制数;它相当于类 [0-9]。
    D 匹配任何非数字字符;它相当于类 [^0-9]。
    s  匹配任何空白字符;它相当于类 [ fv]。
    S 匹配任何非空白字符;它相当于类 [^ fv]。
    w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
    W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
      匹配一个特殊字符边界,比如空格 ,&,#等

    ret=re.findall('I','I am LIST')
    print(ret)#[]
    ret=re.findall(r'I','I am LIST')
    print(ret)#['I']

    注意:

     1 #-----------------------------eg1:
     2 import re
     3 ret=re.findall('cl','abcle')
     4 print(ret)#[]
     5 ret=re.findall('c\l','abcle')
     6 print(ret)#[]
     7 ret=re.findall('c\\l','abcle')
     8 print(ret)#['c\l']
     9 ret=re.findall(r'c\l','abcle')
    10 print(ret)#['c\l']
    11  
    12 #-----------------------------eg2:
    13 #之所以选择是因为在ASCII表中是有意义的
    14 m = re.findall('blow', 'blow')
    15 print(m)
    16 m = re.findall(r'blow', 'blow')
    17 print(m)

    元字符之分组():

    m = re.findall(r'(ad)+', 'add')
    print(m)
     
    ret=re.search('(?P<id>d{2})/(?P<name>w{3})','23/com')
    print(ret.group())#23/com
    print(ret.group('id'))#23

    元字符之|:

    ret=re.search('(ab)|d','rabhdg8sd')
    print(ret.group())#ab

    re模块下的常用方法:

     1 import re
     2 #1
     3 re.findall('a','alvin yuan')    #返回所有满足匹配条件的结果,放在列表里
     4 #2
     5 re.search('a','alvin yuan').group()  #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
     6                                      # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
     7  
     8 #3
     9 re.match('a','abc').group()     #同search,不过尽在字符串开始处进行匹配
    10  
    11 #4
    12 ret=re.split('[ab]','abcd')     #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
    13 print(ret)#['', '', 'cd']
    14  
    15 #5
    16 ret=re.sub('d','abc','alvin5yuan6',1)
    17 print(ret)#alvinabcyuan6
    18 ret=re.subn('d','abc','alvin5yuan6')
    19 print(ret)#('alvinabcyuanabc', 2)
    20  
    21 #6
    22 obj=re.compile('d{3}')
    23 ret=obj.search('abc123eeee')
    24 print(ret.group())#123
    import re
    ret=re.finditer('d','ds3sy4784a')
    print(ret)        #<callable_iterator object at 0x10195f940>
     
    print(next(ret).group())
    print(next(ret).group())

    注意:

    import re
     
    ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
    print(ret)#['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
     
    ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
    print(ret)#['www.oldboy.com']

     注意:

    import re
    
    print(re.findall("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>"))
    print(re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>"))
    print(re.search(r"<(w+)>w+</1>","<h1>hello</h1>"))
    1 #匹配出所有的整数
    2 import re
    3 
    4 #ret=re.findall(r"d+{0}]","1-2*(60+(-40.35/5)-(-4*3))")
    5 ret=re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))")
    6 ret.remove("")
    7 
    8 print(ret)

    1、匹配标签

    import re
    
    ret = re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")
    #还可以在分组中利用?<name>的形式给分组起名字
    #获取的匹配结果可以直接用group('名字')拿到对应的值
    print(ret.group('tag_name'))  #结果 :h1
    print(ret.group())  #结果 :<h1>hello</h1>
    
    ret = re.search(r"<(w+)>w+</1>","<h1>hello</h1>")
    #如果不给组起名字,也可以用序号来找到对应的组,表示要找的内容和前面的组内容一致
    #获取的匹配结果可以直接用group(序号)拿到对应的值
    print(ret.group(1))
    print(ret.group())  #结果 :<h1>hello</h1>

    2、匹配整数

    import re
    
    ret=re.findall(r"d+","1-2*(60+(-40.35/5)-(-4*3))")
    print(ret) #['1', '2', '60', '40', '35', '5', '4', '3']
    ret=re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))")
    print(ret) #['1', '-2', '60', '', '5', '-4', '3']
    ret.remove("")
    print(ret) #['1', '-2', '60', '5', '-4', '3']

    3、小数匹配

    re.search("d+(.d+)?", '2.22+3.56+22")  # 后面括号内小数点后的部分,整体可以出现一次或者0次

    4、数字匹配

    1、 匹配一段文本中的每行的邮箱
          http://blog.csdn.net/make164492212/article/details/51656638
    
    2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;
    
       分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、
       一个月的31天:^(30|31|(1|2)[0-9])|0?[1-9]$
    
        ^([1-2][0-9]{3})-(0?[1-9]|1[0-2])-(30|31|(1|2)[0-9])|0?[1-9]$
    
    3、 匹配qq号。(腾讯QQ号从10000开始)  [1,9][0,9]{4,}
    
    4、 匹配一个浮点数。       ^(-?d+)(.d+)?$   或者  -?d+.?d*
    
    5、 匹配汉字。             ^[u4e00-u9fa5]{0,}$ 
    
    6、 匹配出所有整数

    计算器

    import re
    
    
    def cal_atom(exp):
        """
        -40/5
        """
        if "/" in exp:
            a, b = exp.split("/")
            return str(float(a)/float(b))
        elif "*" in exp:
            a, b = exp.split("*")
            return str(float(a)*float(b))
    
    
    def mul_div(exp):
        while True:
            son_exp = re.search("d+(.d+)?[/*]-?d+(.d+)?", exp)  # 匹配括号里面的乘除法,注意乘除号后面的 -?负号可能存在
            if son_exp:
                atom_exp = son_exp.group()
                res = cal_atom(atom_exp)
                exp = exp.replace(atom_exp, res)
            else:
                return exp
    
    
    def exp_format(exp):
        exp = exp.replace("++", "+")
        exp = exp.replace("+-", "-")
        exp = exp.replace("-+", "-")
        exp = exp.replace("--", "+")
        return exp
    
    
    def add_sub(exp):
        """
        计算加减法
        """
        ret = re.findall("[+-]?d+(?:.d+)?", exp)
        s = 0
        for i in ret:
            s += float(i)
        return str(s)
    
    
    @cal_time
    def remove_bracket(exp):
        while True:
            ret = re.search("([^()]+)", exp)
            if ret:
                no_bracket_exp = ret.group()
                add_sub_exp = mul_div(no_bracket_exp)  # 计算内层括号里面的值,替换回来
                add_sub_exp = exp_format(add_sub_exp)
                res = add_sub(add_sub_exp)
                exp = exp.replace(no_bracket_exp, res)
            else:
                break
        # 所有的括号里面的值算法之后,在按照乘除法,替换符号,加减法的顺序,计算得到最终结果
        exp = mul_div(exp)
        exp = exp_format(exp)
        exp = add_sub(exp)
        return exp
    
    
    s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
    s = s.replace(" ", "")
    print(remove_bracket(s))
    计算器

    在线测试工具 http://tool.chinaz.com/regex/

     
     
     

    ——————————————————————————————————

    另附小游戏

    python 200行代码完成打飞机

    早就知道pygame模块,就是没怎么深入研究过,恰逢这周未没事干,一时兴起,花了几个小时写了个打飞机程序。

    很有意思,跟大家分享下。

    先看一下项目结构

    """
    PlayPlane/
    |-- bin/
    |   |-- main.py         程序运行主体程序
    |-- config/
    |   |-- settings.py     程序配置(例如: 游戏背景音乐的加载等)
    |-- material            程序素材放置(打飞机游戏素材放置)
        |-- ...
    |-- src/                程序主体模块存放
    |   |-- __init__.py 
    |   |-- bullet.py       我方飞机发射子弹实现代码存放
    |   |-- enemy.py        敌方飞机实现代码存放
    |   |-- plane.py        我方飞机实现代码存放
    |-- manage.py           程序启动文件
    |-- README.md           
    """
    

    再晒下项目成果图

    实现步骤

    一、首先在 config/settings.py 中进行以下功能的实现

    • 游戏初始化
    • 游戏混音器初始化
    • 背景音乐初始化
    • 我方飞机挂了音乐
    • 敌方飞机挂了音乐
    • 子弹发射音乐
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import pygame
    
    pygame.init()  # 游戏初始化
    pygame.mixer.init()  # 混音器初始化
    
    # 游戏背景音乐
    pygame.mixer.music.load("material/sound/game_music.wav")
    pygame.mixer.music.set_volume(0.2)
    
    # 子弹发射音乐
    bullet_sound = pygame.mixer.Sound("material/sound/bullet.wav")
    bullet_sound.set_volume(0.2)
    
    # 我方飞机挂了的音乐
    me_down_sound = pygame.mixer.Sound("material/sound/game_over.wav")
    me_down_sound.set_volume(0.2)
    
    # 敌方飞机挂了的音乐
    enemy1_down_sound = pygame.mixer.Sound("material/sound/enemy1_down.wav")
    enemy1_down_sound.set_volume(0.2)
    
    config/settings.py
    

    注:游戏素材滑动到文章底部点击链接即可下载  

    二、小试牛刀

    飞机和子弹都是可移动的,那么怎么实现让它们动起来呢(我方飞机可以玩家进行操控,敌机就是随机性的出现,子弹暂由我方飞机发射)。

    在Pygame中,所有移动对象都可看做是一个精灵(sprite),精灵之间能够进行相互的交互通信,例如如何让碰撞检测更加精准等等。

    那么先让我们先在屏幕上制作一个游戏板,根据 settings.py 配置,并让它有声音播放,首先我们在 bin/main.py 中这么写:

      我们可以直接运行它,那么我们会看到以下画面,并且还会有激情的声音吆!!!但是我们要将文件配置为绝对路径才可以运行,因为刚刚在settings中的加载的音乐文件为相对路径。

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import sys
    
    from config.settings import *
    
    
    bg_size = 480, 852  # 初始化游戏背景大小(宽, 高)
    screen = pygame.display.set_mode(bg_size)  # 设置背景对话框
    pygame.display.set_caption("飞机大战")  # 设置标题
    
    background = pygame.image.load(os.path.join(BASE_DIR, "material/image/background.png"))  # 加载背景图片,并设置为不透明
    
    
    def main():
        pygame.mixer.music.play(loops=-1)  # loops 对应的值为 -1 则音乐会无限循环播放
    
        while True:
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 响应用户的操作(一定要有响应的用户操作)
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    
    if __name__ == '__main__':
        main()
    

      

    接下来呢,我们将要制作我方飞机,敌方飞机和子弹如何让它们展示在游戏画板上,继而让它们变得可移动起来,请看代码实现方案...

    从游戏画板上添加飞机,首先我们应怎样在屏幕上输出飞机???

    上述讲过,pygame中的 sprite(精灵)可使一张图片或者一个静态物体动起来,那么制作飞机需要考虑并做些什么呢?

    1. 飞机的初始位置
    2. 通过按键 上下左右 来调控飞机的位置移动
    3. 飞机只能呆在制作的游戏画板中
    4. 飞机的速度
    5. 飞机死亡的加载
    6. 设定一个状态标识飞机的存活
    7. 让飞机具有动态的喷气式效果

    那么如何实现以上的功能呢?接下来结合上述的示例代码我们先将我方飞机绘制到画板上方,并且我们通过按键 J 判定我方飞机的存活状态为死亡,绘制飞机的死亡画面并重置飞机

    """
        创建飞机
        在pygame中, 所有可移动的对象均叫可看作一个精灵(sprite)
        该类并实现了碰撞方法 spritecollide
    
        我方飞机和敌方飞机指定掩膜属性以及生存状态标志位 添加 self.mask 属性(可以实现更精准的碰撞效果)
    """
    
    # 倒入精灵模块, 使飞机可以动起来
    import pygame
    
    
    class OurPlane(pygame.sprite.Sprite):
    
        def __init__(self, bg_size):
            super(OurPlane, self).__init__()
            # 确定我方飞机背景图(有俩张,可以让它们不停的切换,形成动态效果)
            self.image_one = pygame.image.load("material/image/hero1.png")
            self.image_two = pygame.image.load("material/image/hero2.png")
            # 获取我方飞机的位置
            self.rect = self.image_one.get_rect()
            # 本地化背景图片的尺寸
            self.width, self.height = bg_size[0], bg_size[1]
            # 获取飞机图像的掩膜用以更加精确的碰撞检测
            self.mask = pygame.mask.from_surface(self.image_one)
            # 定义飞机初始化位置,底部预留60像素
            self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            # 设置飞机移动速度
            self.speed = 10
            # 设置飞机存活状态(True为存活, False为死亡)
            self.active = True
            # 加载飞机损毁图片
            self.destroy_images = []
            self.destroy_images.extend(
                [
                    pygame.image.load("material/image/hero_blowup_n1.png"),
                    pygame.image.load("material/image/hero_blowup_n2.png"),
                    pygame.image.load("material/image/hero_blowup_n3.png"),
                    pygame.image.load("material/image/hero_blowup_n4.png")
                ]
            )
    
        def move_up(self):
            """
            飞机向上移动的操作函数,其余移动函数方法类似
            """
            if self.rect.top > 0:  # 如果飞机尚未移动出背景区域
                self.rect.top -= self.speed
            else:  # 若即将移动出背景区域,则及时纠正为背景边缘位置
                self.rect.top = 0
    
        def move_down(self):
            """
            飞机向下移动
            """
            if self.rect.bottom < self.height - 60:
                self.rect.top += self.speed
            else:
                self.rect.bottom = self.height - 60
    
        def move_left(self):
            """
            飞机向左移动
            """
            if self.rect.left > 0:
                self.rect.left -= self.speed
            else:
                self.rect.left = 0
    
        def move_right(self):
            """
            飞机向右移动
            """
            if self.rect.right < self.
                self.rect.right += self.speed
            else:
                self.rect.right = self.width
    
        def reset(self):
            # 初始化飞机(飞机挂了, 初始化到初始位置)
            self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            # 重置飞机的存活状态
            self.active = True
    

      

    上面的代码写了一个 我们的飞机 (OurPlane) 类,它初始化了一些属性以及 上下左右 移动的方法和重置方法,接下来将要运用它展示到游戏画板上面

    由于飞机是一直存在的,接下我们主程序 main 下面的死循环中这样写

    def main():
        pygame.mixer.music.play(loops=-1)  # loops 对应的值为 -1 则音乐会无限循环播放
    
        our_plane = OurPlane(bg_size)  # 初始化
        switch_image = False  # 定义飞机的切图效果标识
    
        while True:
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 飞机状态是存活
            if our_plane.active:
    
                if switch_image:
                    screen.blit(our_plane.image_one, our_plane.rect)
                else:
                    screen.blit(our_plane.image_two, our_plane.rect)
    
                switch_image = not switch_image  # 让切图状态不停的变换
            else:
                pass
    
            # 响应用户的操作(一定要有响应的用户操作)
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    
    if __name__ == '__main__':
        main()
    1.在屏幕上绘制飞机
    def main():
        pygame.mixer.music.play(loops=-1)  # loops 对应的值为 -1 则音乐会无限循环播放
    
        our_plane = OurPlane(bg_size)  # 初始化
        switch_image = False  # 定义飞机的切图效果标识
    
        while True:
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 飞机状态是存活
            if our_plane.active:
    
                if switch_image:
                    screen.blit(our_plane.image_one, our_plane.rect)
                else:
                    screen.blit(our_plane.image_two, our_plane.rect)
    
                switch_image = not switch_image  # 让切图状态不停的变换
            else:
                pass
    
            # 获得用户所有的键盘输入序列(如果用户通过键盘发出“向上”的指令,其他类似)
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_w] or key_pressed[K_UP]:
                our_plane.move_up()
            if key_pressed[K_s] or key_pressed[K_DOWN]:
                our_plane.move_down()
            if key_pressed[K_a] or key_pressed[K_LEFT]:
                our_plane.move_left()
            if key_pressed[K_d] or key_pressed[K_RIGHT]:
                our_plane.move_right()
    
            # 响应用户的操作(一定要有响应的用户操作)
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    
    if __name__ == '__main__':
        main()
    2.让飞机上下左右动起来
    def main():
        pygame.mixer.music.play(loops=-1)  # loops 对应的值为 -1 则音乐会无限循环播放
    
        our_plane = OurPlane(bg_size)  # 初始化
        switch_image = False  # 定义飞机的切图效果标识
    
        our_plane_destroy_index = 0
    
        while True:
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 飞机状态是存活(如果按键 为 J, 让飞机死亡并绘制爆炸效果)
            if our_plane.active:
    
                if switch_image:
                    screen.blit(our_plane.image_one, our_plane.rect)
                else:
                    screen.blit(our_plane.image_two, our_plane.rect)
    
                switch_image = not switch_image  # 让切图状态不停的变换
            else:
                """
                飞机死亡也是进行按顺序的图片切换, 那么在死循环之外定义索引
                """
                me_destroy_index = (our_plane_destroy_index + 1) % 4
                if me_destroy_index == 1:
                    me_down_sound.play()  # 爆炸声音效果
                    our_plane.reset()  # 初始化飞机
                if our_plane_destroy_index >= len(our_plane.destroy_images):
                    our_plane_destroy_index = 0
                else:
                    screen.blit(our_plane.destroy_images[our_plane_destroy_index], our_plane.rect)
    
                our_plane_destroy_index += 1
    
            # 获得用户所有的键盘输入序列(如果用户通过键盘发出“向上”的指令,其他类似)
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_w] or key_pressed[K_UP]:
                our_plane.move_up()
            if key_pressed[K_s] or key_pressed[K_DOWN]:
                our_plane.move_down()
            if key_pressed[K_a] or key_pressed[K_LEFT]:
                our_plane.move_left()
            if key_pressed[K_d] or key_pressed[K_RIGHT]:
                our_plane.move_right()
    
            # 按键为 j 飞机更改存活标识
            if key_pressed[K_j]:
                our_plane.active = False
    
            # 响应用户的操作(一定要有响应的用户操作)
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    3.按键为 j 绘制飞机的死亡状态

    那么上述的功能都已经实现了,接下来就开始真正的"打飞机"

    三、接下来可以制作我方飞机,敌方战机,子弹等,这些功能均在 src/ 目录下实现

    • 我方飞机根据按键上下左右进行移动,初始化位置,喷气式图片加载切换及重置效果等
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    """
        创建飞机
        在pygame中, 所有可移动的对象均叫可看作一个精灵(sprite)
        该类并实现了碰撞方法 spritecollide
    
        我方飞机和敌方飞机指定掩膜属性以及生存状态标志位 添加 self.mask 属性(可以实现更精准的碰撞效果)
    """
    
    # 倒入精灵模块, 使飞机可以动起来
    import pygame
    
    
    class OurPlane(pygame.sprite.Sprite):
    
        def __init__(self, bg_size):
            super(OurPlane, self).__init__()
            # 确定我方飞机背景图
            self.image_one = pygame.image.load("material/image/hero1.png")
            self.image_two = pygame.image.load("material/image/hero2.png")
            # 获取我方飞机的位置
            self.rect = self.image_one.get_rect()
            # 本地化背景图片的尺寸
            self.width, self.height = bg_size[0], bg_size[1]
            # 获取飞机图像的掩膜用以更加精确的碰撞检测
            self.mask = pygame.mask.from_surface(self.image_one)
            # 定义飞机初始化位置,底部预留60像素
            self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            # 设置飞机移动速度
            self.speed = 10
            # 设置飞机存活状态(True为存活, False为死亡)
            self.active = True
            # 加载飞机损毁图片
            self.destroy_images = []
            self.destroy_images.extend(
                [
                    pygame.image.load("material/image/hero_blowup_n1.png"),
                    pygame.image.load("material/image/hero_blowup_n2.png"),
                    pygame.image.load("material/image/hero_blowup_n3.png"),
                    pygame.image.load("material/image/hero_blowup_n4.png")
                ]
            )
    
        def move_up(self):
            """
            飞机向上移动的操作函数,其余移动函数方法类似
            """
            if self.rect.top > 0:  # 如果飞机尚未移动出背景区域
                self.rect.top -= self.speed
            else:  # 若即将移动出背景区域,则及时纠正为背景边缘位置
                self.rect.top = 0
    
        def move_down(self):
            if self.rect.bottom < self.height - 60:
                self.rect.top += self.speed
            else:
                self.rect.bottom = self.height - 60
    
        def move_left(self):
            if self.rect.left > 0:
                self.rect.left -= self.speed
            else:
                self.rect.left = 0
    
        def move_right(self):
            if self.rect.right < self.
                self.rect.right += self.speed
            else:
                self.rect.right = self.width
    
        def reset(self):
            # 初始化飞机(飞机挂了, 初始化到初始位置)
            self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            self.active = True
    
    src/plane.py
    src/plane.py
    • 敌方飞机随机移动出现及重置(制作出我方飞机之后,敌机和子弹其实都是大同小异的)
    • #! /usr/bin/env python
      # -*- coding: utf-8 -*-
      
      """
          定义敌机
      """
      
      from random import randint
      
      import pygame
      
      
      class SmallEnemy(pygame.sprite.Sprite):
          """
          定义小飞机敌人
          """
          def __init__(self, bg_size):
              super(SmallEnemy, self).__init__()
              self.image = pygame.image.load("material/image/enemy1.png")
              self.rect = self.image.get_rect()
              self.width, self.height = bg_size[0], bg_size[1]
              self.mask = pygame.mask.from_surface(self.image)  # 获取飞机图像的掩膜用以更加精确的碰撞检测
              self.speed = 2
              # 定义敌机出现的位置, 保证敌机不会在程序已开始就立即出现
              self.rect.left, self.rect.top = (
                  randint(0, self.width - self.rect.width),  randint(-5 * self.rect.height, -5),
              )
              self.active = True
              # 加载飞机损毁图片
              self.destroy_images = []
              self.destroy_images.extend(
                  [
                      pygame.image.load("material/image/enemy1_down1.png"),
                      pygame.image.load("material/image/enemy1_down2.png"),
                      pygame.image.load("material/image/enemy1_down3.png"),
                      pygame.image.load("material/image/enemy1_down4.png")
                  ]
              )
      
          def move(self):
              """
              定义敌机的移动函数
              :return:
              """
              if self.rect.top < self.height:
                  self.rect.top += self.speed
              else:
                  self.reset()
      
          def reset(self):
              """
              当敌机向下移动出屏幕时, 以及敌机死亡
              :return:
              """
              self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width), randint(-5 * self.rect.height, 0))
              self.active = True
      src/enemy.py
    • 子弹按照我方飞机正中上方发射及频率调控,重置
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    """
        子弹的实现
    """
    
    import pygame
    
    
    class Bullet(pygame.sprite.Sprite):
    
        def __init__(self, position):
            super(Bullet, self).__init__()
            self.image = pygame.image.load("material/image/bullet1.png")
            self.rect = self.image.get_rect()
            self.rect.left, self.rect.top = position
            self.speed = 30
            self.active = True
            self.mask = pygame.mask.from_surface(self.image)
    
        def move(self):
            """
            子弹移动, 超出屏幕范围, 则设置死亡
            :return:
            """
            if self.rect.top < 0:
                self.active = False
            else:
                self.rect.top -= self.speed
    
        def reset(self, position):
            """
            复位函数
            :param position:
            :return:
            """
            self.rect.left, self.rect.top = position
            self.active = True
    
    src/bullet.py
    src/bullet.py

    在上面的内容中,使用面向对象的形式制作了游戏中可移动的对象并继承 pygame.sprite.Sprite 

    四、然后在 bin/main.py 中进行主体功能的实现

    • 初始化背景图及大小
    • 我方飞机移动及发射子弹
    • 敌方飞机移动
    • 我方飞机和敌方飞机碰撞检测
    • 键盘按键监测效果
    • 我方飞机和敌方飞机挂了效果绘制
    import sys
    
    from pygame.locals import *
    
    from config.settings import *
    from src.plane import OurPlane
    from src.enemy import SmallEnemy
    from src.bullet import Bullet
    
    
    bg_size = 480, 852  # 初始化游戏背景大小(宽, 高)
    screen = pygame.display.set_mode(bg_size)  # 设置背景对话框
    pygame.display.set_caption("飞机大战")  # 设置标题
    
    background = pygame.image.load("material/image/background.png")  # 加载背景图片,并设置为不透明
    
    # 获取我方飞机
    our_plane = OurPlane(bg_size)
    
    
    def add_small_enemies(group1, group2, num):
        """
        添加小型敌机
        指定个敌机对象添加到精灵组(sprite.group)
        参数group1、group2是两个精灵组类型的形参,用以存储多个精灵对象(敌机)。
        需要注意的一点是group既然是特定的精灵组结构体,在向其内部添加精灵对象时需要调用其对应的成员函数add()
        :return:
        """
        for i in range(num):
            small_enemy = SmallEnemy(bg_size)
            group1.add(small_enemy)
            group2.add(small_enemy)
    
    
    def main():
        # 响应音乐
        pygame.mixer.music.play(-1)  # loops 接收该参数, -1 表示无限循环(默认循环播放一次)
        running = True
        switch_image = False  # 切换飞机的标识位(使飞机具有喷气式效果)
        delay = 60  # 对一些效果进行延迟, 效果更好一些
    
        enemies = pygame.sprite.Group()  # 生成敌方飞机组(一种精灵组用以存储所有敌机精灵)
        small_enemies = pygame.sprite.Group()  # 敌方小型飞机组(不同型号敌机创建不同的精灵组来存储)
    
        add_small_enemies(small_enemies, enemies, 4)  # 生成若干敌方小型飞机
    
        # 定义子弹, 各种敌机和我方敌机的毁坏图像索引
        bullet_index = 0
        e1_destroy_index = 0
        me_destroy_index = 0
    
        # 定义子弹实例化个数
        bullet1 = []
        bullet_num = 6
        for i in range(bullet_num):
            bullet1.append(Bullet(our_plane.rect.midtop))
    
        while running:
    
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 微信的飞机貌似是喷气式的, 那么这个就涉及到一个帧数的问题
            clock = pygame.time.Clock()
            clock.tick(60)
    
            # 绘制我方飞机的两种不同的形式
            if not delay % 3:
                switch_image = not switch_image
    
            for each in small_enemies:
                if each.active:
                    # 随机循环输出小飞机敌机
                    for e in small_enemies:
                        e.move()
                        screen.blit(e.image, e.rect)
                else:
                    if e1_destroy_index == 0:
                        enemy1_down_sound.play()
                    screen.blit(each.destroy_images[e1_destroy_index], each.rect)
                    e1_destroy_index = (e1_destroy_index + 1) % 4
                    if e1_destroy_index == 0:
                        each.reset()
    
            # 当我方飞机存活状态, 正常展示
            if our_plane.active:
                if switch_image:
                    screen.blit(our_plane.image_one, our_plane.rect)
                else:
                    screen.blit(our_plane.image_two, our_plane.rect)
    
                # 飞机存活的状态下才可以发射子弹
                if not (delay % 10):  # 每十帧发射一颗移动的子弹
                    bullet_sound.play()
                    bullets = bullet1
                    bullets[bullet_index].reset(our_plane.rect.midtop)
                    bullet_index = (bullet_index + 1) % bullet_num
    
                for b in bullets:
                    if b.active:  # 只有激活的子弹才可能击中敌机
                        b.move()
                        screen.blit(b.image, b.rect)
                        enemies_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask)
                        if enemies_hit:  # 如果子弹击中飞机
                            b.active = False  # 子弹损毁
                            for e in enemies_hit:
                                e.active = False  # 小型敌机损毁
    
            # 毁坏状态绘制爆炸的场面
            else:
                if not (delay % 3):
                    screen.blit(our_plane.destroy_images[me_destroy_index], our_plane.rect)
                    me_destroy_index = (me_destroy_index + 1) % 4
                    if me_destroy_index == 0:
                        me_down_sound.play()
                        our_plane.reset()
    
            # 调用 pygame 实现的碰撞方法 spritecollide (我方飞机如果和敌机碰撞, 更改飞机的存活属性)
            enemies_down = pygame.sprite.spritecollide(our_plane, enemies, False, pygame.sprite.collide_mask)
            if enemies_down:
                our_plane.active = False
                for row in enemies:
                    row.active = False
    
            # 响应用户的操作
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            if delay == 0:
                delay = 60
            delay -= 1
    
            # 获得用户所有的键盘输入序列(如果用户通过键盘发出“向上”的指令,其他类似)
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_w] or key_pressed[K_UP]:
                our_plane.move_up()
            if key_pressed[K_s] or key_pressed[K_DOWN]:
                our_plane.move_down()
            if key_pressed[K_a] or key_pressed[K_LEFT]:
                our_plane.move_left()
            if key_pressed[K_d] or key_pressed[K_RIGHT]:
                our_plane.move_right()
    
            # 绘制图像并输出到屏幕上面
            pygame.display.flip()
    bin/main.py

    五、畅汗淋漓,一气呵成打飞机

    from bin.main import main
    
    
    if __name__ == '__main__':
        """
        环境: python3 + pygame
        running 起来就可以打飞机了O(∩_∩)O~.
        """
        main()
    

      

    最终效果!

    https://www.cnblogs.com/pupilheart/diary/2018/11/21/9998016.html

    稍后,素材会上传到博主GitHub上

  • 相关阅读:
    phalapi框架where条件查询
    yii2学习网站
    改变yii2 $form最外层div样式
    PHP库(数据抓取)
    yii框架场景的用法
    Yii框架数据查询
    更改控制台编码格式
    打开yii2控制台命令
    过滤器实现登录拦截
    SSM整合
  • 原文地址:https://www.cnblogs.com/pupilheart/p/9113777.html
Copyright © 2011-2022 走看看