Python实践 外星人入侵

继续之前的代码继续照着书敲,并且做一些简单记录。

使用Pygame包开发2D游戏

pip install pygame 在wu开头的虚拟环境里

Pygame可用于管理图形、动画和声音

常用模块及实例(CSDN博客

游戏描述

玩家控制一艘最初出现在屏幕底部中央的飞船,用箭头键左右移动飞船,可以使用空格键进行射击。游戏开始时,一群外星人在屏幕向下移动。玩家任务是射杀这些外星人。将所有外星人消灭后,将会出现新的外星人,他们移动速度更快,只要有外星人撞到了玩家飞船或着到达屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后游戏结束。

开始项目

游戏囊括在函数run_game()中,注意python的缩进机制

pygame.init()初始化游戏背景设置

screen = pygame.display.set_mode()创建一个显示窗口,游戏中的所有图形元素都将在其中绘制

对象screen是一个surface,在Pygame中,surface是屏幕的一部分,用于显示游戏元素。在这个游戏中每个元素(飞船or外星人)都是一个surface

创建设置类 settings.py

引用书中所言:

“每次给游戏添加新功能时,通常也将引入一些新设置。编写一个settings的模块,其中包含一个名为Settings的类,用于将所有设置存储在一个地方,以免在代码中到处添加设置。这样,我们就能传递一个设置对象,而不是众多不同的设置。另外,这让函数调用更简单,且在项目增大时修改游戏的外观更容易:要修改游戏,只需要修改settings.py中的一些值,而无需查找散布在文件中的不同设置。

这样的分层处理,好好体会!

1
2
3
4
5
6
7
8
9
class Settings():
    """存储《外星人入侵》的所有设置的类"""

    def __init__(self):
        """初始化游戏的设置"""
        #   屏幕设置
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230,230,230)

创建Ship类

负责管理飞船的大部分行为,这是初始版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Ship():

    def __init__(self, screen):
        """初始化飞船并设置其初始位置"""
        self.screen = screen

        #   加载飞船图像并获取其》外接矩形《
        self.image = pygame.image.load('images/ship.png')
        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

    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect) 

重构思想:重构模块game_functions

引用书中的话,积累项目经验吧

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

“鉴于我们一开始只想用一个文件,因此没有立刻引入模块game_functions。这让你能够了解实际的开发过程:一开始将代码编写得尽可能简单,并在项目越来越复杂得时候进行重构。”

两个函数,易于扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
def check_events():
    """响应按键和鼠标事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

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

驾驶飞船

下面让玩家能够左右移动飞船。开始处理游戏动态方面。

响应按键事件

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

飞船的属性都由Ship类控制,因此在这个类添加一个名为moving_right的属性和一个名为update()的方法。方法检查标moving_riht的状态,如果这个状态为True,就调整飞船的位置。每当需要调整飞船的位置时,我们都调用这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Ship():

    def __init__(self, screen):
        """初始化飞船并设置其初始位置"""
        self.screen = screen

        #   加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images/ship.png')
        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

        # 移动标志
        self.moving_right = False
        self.moving_left = False


    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)


    def update(self):
        """根据移动标志调整飞船的位置"""
        if self.moving_right:
            self.rect.centerx += 1
        if self.moving_left:
            self.rect.centerx -= 1

键盘事件监听,因为用elif代码块,是因为每个事件都只与一个键相关联;如果玩家同时按下了左右箭头键,将检测到两个不同的事件。不会触发后边的语句,如果玩家同时按住左右两个键那么飞船将纹丝不动。

==============隔了两天继续写2019/7/1/===================

调整飞船速度及范围

在python中有显隐式转换吗?有的

一个int型变量self.center被赋值一个float型变量self.rect.centerx之后,只保存整数部分。

1
2
3
self.center = float(self.rect.centerx)
...
self.rect.centerx = self.center

==============隔了两部电影 /6 hours late/ ======== 自己不努力,就不要抱怨世界对你不公平 ================================================

重构check_functions()函数

随着游戏开发的进行,函数check_functions()将会越来越来长,我们将其部分代码放在两个函数中:一个处理‘按键’事件,一个处理‘松开’事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def check_events(ship):
    """响应按键和鼠标事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        # 按键
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event,ship)
          
        # 松开
        elif event.type == pygame.KEYUP:
            check_keyup_events(event,ship)
           

小结

觉得一边看书一边敲代码一边写这些,感觉效率很低。我准备调整方式,先对照书完成程序,出现的问题在书上体现,然后总结后再整理成博客。