zoukankan      html  css  js  c++  java
  • Python 项目实践一(外星人入侵小游戏)第三篇

    今天是圣诞节,公司放假一天,趁着有空,学习了一下午,多写一篇博客吧!

    接着上节的继续学习,

    一 重构:模块game_functions

    在大型项目中,经常需要在添加新代码前重构既有代码。重构旨在简化既有代码的结构,使其更容易扩展。在本节中,我们将创建一个名为game_functions的新模块,它将存储大量让游戏《外星人入侵》运行的函数。通过创建模块game_functions,可避免alien_invasion.py太长,并使其逻辑更容易理解。

    1 函数check_events()

    将check_events()放在一个名为game_functions的模块中,在该函数主要是管理事件的功能,通过隔离事件循环,可将事件管理与游戏的其他方面(如更新屏幕)分离。通

    #game_functions.py
    import sys
    import pygame
    def check_events():
        """响应按键和鼠标事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
            sys.exit()            
    

    2 函数update_screen()

    为进一步简化run_game(),下面将更新屏幕的代码移到一个名为update_screen()的函数中,并将这个函数放在模块game_functions.py中:

    #game_functions.py
        --snip--
    def check_events():
        --snip--
    def update_screen(ai_settings, screen, ship):
        """更新屏幕上的图像,并切换到新屏幕"""
        # 每次循环时都重绘屏幕
        screen.fill(ai_settings.bg_color)
        ship.blitme()
        # 让最近绘制的屏幕可见
        pygame.display.flip()
    

    二 驾驶飞船

    下面来让玩家能够左右移动飞船:

    1 相应按键

    每当用户按键时,都将在Pygame中注册一个事件。事件都是通过方法pygame.event.get()获取的,因此在函数check_events()中,我们需要指定要检查哪些类型的事件。每次按键都被注册为一个KEYDOWN事件。

    检测到KEYDOWN事件时,我们需要检查按下的是否是特定的键。例如,如果按下的是右箭头键,我们就增大飞船的rect.centerx值,将飞船向右移动:

     #game_ functions.py
    def check_events(ship):
        """响应按键和鼠标事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
         elif event.type == pygame.KEYDOWN:
             if event.key == pygame.K_RIGHT:
                    #向右移动飞船
                 ship.rect.centerx += 1        
    

    2 允许不断移动

    玩家按住右箭头键不放时,我们希望飞船不断地向右移动,直到玩家松开为止。检测pygame.KEYUP事件,以便玩家松开右箭头键时我们能够知道这一点;然后,我们将结合使用KEYDOWN和KEYUP事件,以及一个名为moving_right的标志来实现持续移动。

    飞船不动时,标志moving_right将为False。玩家按下右箭头键时,我们将这个标志设置为True;而玩家松开时,我们将这个标志重新设置为False。代码见下面:

    3 调整飞船的速度

    当前,每次执行while循环时,飞船最多移动1像素,但我们可以在Settings类中添加属性ship_speed_factor,用于控制飞船的速度。我们将根据这个属性决定飞船在每次循环时最多移动多少距离。下面演示了如何在settings.py中添加这个新属性:

    4 限制飞船的活动范围

    当前,如果玩家按住箭头键的时间足够长,飞船将移到屏幕外面,消失得无影无踪。下面来修复这种问题,让飞船到达屏幕边缘后停止移动。为此,我们将修改Ship类的方法update():

    import pygame
    
    class Ship():
        def __init__(self, ai_settings,screen):
            """初始化飞船并设置其初始位置"""
            self.screen = screen
            self.ai_settings = ai_settings
            # 加载飞船图像并获取其外接矩形
            self.image = pygame.image.load('images/ship.bmp')
            self.rect = self.image.get_rect()
            self.screen_rect = screen.get_rect()
            # 将每艘新飞船放在屏幕底部中央
            self.rect.centerx = self.screen_rect.centerx
            self.rect.bottom = self.screen_rect.bottom
    
            #将飞船的属性center中存储小数值
            self.center=float(self.rect.centerx)
    
            #移动标志
            self.moving_right = False
            self.moving_left = False
        def update(self) :
            #根据移动标志调整飞船的位置
            if self.moving_right and self.rect.right < self.screen_rect.right :
                self.center +=self.ai_settings.ship_speed_factor
            if self.moving_left and self.rect.left > self.screen_rect.left :
                self.center -=self.ai_settings.ship_speed_factor
            self.rect.centerx = self.center
        def blitme(self):
            """在指定位置绘制飞船"""
            self.screen.blit(self.image, self.rect)
    

    三 简单回顾

    1 alien_invasion.py

    主文件alien_invasion.py创建一系列整个游戏都要用到的对象:存储在ai_settings中的设置、存储在screen中的主显示surface以及一个飞船实例。文件alien_invasion.py还包含游戏的主循环,这是一个调用check_events()、ship.update()和update_screen()的while循环。

    2 settings.py

    文件settings.py包含Settings类,这个类只包含方法__init__(),它初始化控制游戏外观和飞船速度的属性。

    3 game_functions.py

    文件game_functions.py包含一系列函数,游戏的大部分工作都是由它们完成的。函数check_events()检测相关的事件,如按键和松开,并使用辅助函数check_keydown_events()和check_keyup_events() 来处理这些事件。就目前而言, 这些函数管理飞船的移动。模块game_functions还包含函数update_screen(),它用于在每次执行主循环时都重绘屏幕。

    4 ship.py

    文件ship.py包含Ship类,这个类包含方法__init__()、管理飞船位置的方法update()以及在屏幕上绘制飞船的方法blitme()。表示飞船的图像存储在文件夹images下的文件ship.bmp中。

    四 射击子弹

    下面来添加射击功能。我们将编写玩家按空格键时发射子弹(小矩形)的代码。子弹将在屏幕中向上穿行,抵达屏幕上边缘后消失。

    1 添加子弹设置

    首先,更新settings.py,在其方法__init__()末尾存储新类Bullet所需的值:

    class Settings():
        '''存储《外星人入侵》的所有设置的类'''
    
        def __init__(self):
            '''初始化游戏的设置'''
            self.screen_width=1200
            self.screen_height=800
            self.bg_color = (230,230,230)
            self.ship_speed_factor =1.5
            #子弹的设置
            self.bullet_speed_factor = 1
            self.bullet_width =10
            self.bullet_height =15
            self.bullet_color =60,60,60
    

    2 创建Bullet类

    下面来创建存储Bullet类的文件bullet.py,Bullet类继承了我们从模块pygame.sprite中导入的Sprite类。通过使用精灵,可将游戏中相关的元素编组,进而同时操作编组中的所有元素。为创建子弹实例,需要向__init__()传递i_settings、screen和ship实例,还调用了super()来继承Sprite。我们创建了子弹的属性rect。子弹并非基于图像的,因此我们必须使用pygame.Rect()类从空白开始创建一个矩形。创建这个类的实例时,必须提供矩形左上角的x坐标和y坐标,还有矩形的宽度和高度。方法update()管理子弹的位置。发射出去后,子弹在屏幕中向上移动,这意味着y坐标将不断减小,因此为更新子弹的位置,子弹发射后,其x坐标始终不变,因此子弹将沿直线垂直地往上穿行。需要绘制子弹时,我们调用draw_bullet()。函数draw.rect()使用存储在self.color中的颜色填充表示子弹的rect占据的屏幕部分。代码如下:

    import pygame
    from pygame.sprite import Sprite
    
    class Bullet(Sprite) :
        def __init__(self,ai_settings,screen,ship) :
            # 在飞船所处的位置创建一个子弹对象
            super().__init__()
            self.screen=screen
    
            #在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
            self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
            self.rect.centerx=ship.rect.centerx
            self.rect.top = ship.rect.top
    
            #存储用小数表示子弹的位置
            self.y=float(self.rect.y)
            self.color = ai_settings.bullet_color
            self.speed_factor = ai_settings.bullet_speed_factor
    
        def update(self) :
            #向上移动子弹,更新表示子弹位置的小数值
            self.y -= self.speed_factor
            #更新表示子弹的rect的位置
            self.rect.y = self.y
    
        def draw_bullet(self) :
            #在屏幕上绘制子弹
            pygame.draw.rect(self.screen,self.color,self.rect)
    

    3 将子弹存储到编组中

    定义Bullet类和必要的设置后,就可以编写代码了,在玩家每次按空格键时都射出一发子弹。首先,我们将在alien_invasion.py中创建一个编组(group),用于存储所有有效的子弹,以便能够管理发射出去的所有子弹。这个编组将是pygame.sprite.Group类的一个实例;pygame.sprite.Group类类似于列表,但提供了有助于开发游戏的额外功能。在主循环中,我们将使用这个编组在屏幕上绘制子弹,以及更新每颗子弹的位置:

    import sys
    from settings import Settings
    from ship import Ship
    import game_functions as gf
    import pygame
    from pygame.sprite import Group
    
    def run_game():
        # 初始化游戏并建立一个屏幕对象
        pygame.init()
        # screen = pygame.display.set_mode((1200,800))
        ai_settings=Settings()
        screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
        pygame.display.set_caption("Alien Invasion")
        # 创建一艘飞船
        ship = Ship(ai_settings,screen)
    
        #创建一个用于存储子弹的group
        bullets =Group()
        
        #开始游戏的主循环
        while True:
            # 监视键盘和鼠标事件
            gf.check_events(ai_settings,screen,ship,bullets)
            ship.update()
            bullets.update()
            bullets.update()
            gf.update_screen(ai_settings,screen,ship,bullets)
    run_game()
    

      

    4 开火

    在game_functions.py中,我们需要修改check_keydown_events(),以便在玩家按空格键时发射一颗子弹。我们无需修改check_keyup_events(),因为玩家松开空格键时什么都不会发生。我们还需修改update_screen(),确保在调用flip()前在屏幕上重绘每颗子弹。下面是对game_functions.py所做的相关修改:

    import sys
    from bullet import Bullet
    import pygame
    
    def check_keydown_events(event,ai_settings,screen,ship,bullets) :
        if event.key == pygame.K_RIGHT :
            ship.moving_right =True
        elif event.key == pygame.K_LEFT :
             ship.moving_left =True
        elif event.key == pygame.K_SPACE :
            new_bullet = Bullet(ai_settings,screen,ship)
            bullets.add(new_bullet)
    
    def check_keyup_events(event,ship) :
        if event.key == pygame.K_RIGHT:
             ship.moving_right = False
        elif event.key == pygame.K_LEFT :
             ship.moving_left =False
    
    def check_events(ai_settings,screen,ship,bullets):
        #响应按键和鼠标事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT :
                sys.exit()
            elif event.type == pygame.KEYDOWN :
                check_keydown_events(event,ai_settings,screen,ship,bullets)
                #check_keydown_events(event,ship)
            elif event.type == pygame.KEYUP :
                check_keyup_events(event,ship)
    
    def update_screen(ai_settings,screen,ship,bullets) :
        """更新屏幕上的图像,并切换到新屏幕"""
        # 每次循环时都重绘屏幕
        screen.fill(ai_settings.bg_color)
        #在飞船和外星人后面重新绘制所有子弹
        for bullet in bullets.sprites() :
            bullet.draw_bullet()
        ship.blitme()
        # 让最近绘制的屏幕可见
        pygame.display.flip()
    

     先写到这里吧,不知不觉天已经黑了,太耗时了,要去做饭了,对了最后的效果如下所示(为了截图我把子弹的速度调的非常慢,所以看起来有点怪):

    昨天写的了,忘了发布了,今天发布下!

      

      

  • 相关阅读:
    饮冰三年-人工智能-linux-03 Linux文件管理(权限管理+归档+压缩)
    饮冰三年-人工智能-linux-02 初始Linux
    饮冰三年-人工智能-linux-01通过VM虚拟机安装contes系统
    测试joinablequeue
    生产者消费者模型
    队列
    优化抢票
    昨日回顾
    抢票小程序
    守护进程
  • 原文地址:https://www.cnblogs.com/ChinacloudTech/p/8110637.html
Copyright © 2011-2022 走看看