Python项目实践之二:外星人(1)

Python项目实践之二:外星人

在本文中,我们将在游戏《外星人入侵》中添加外星人。首先,我们在屏幕上边缘附近添加一个外星人,然后生成一群外星人。我们让这群外星人向两边和下面移动,并删除被子弹击中的外星人。最后,我们将显示玩家拥有的飞船数量,并在玩家的飞船用完后结束游戏。

一、回顾项目

开发较大的项目时,进入每个开发阶段前回顾一下开发计划,搞清楚接下来要通过编写代码来完成哪些任务都是不错的主意。

1、alien_invasion.py

主文件alien_invasion.py创建一系列整个游戏都要用到的对象:
1、ai_settings:设置游戏相关的内容(游戏界面尺寸、飞船速度、子弹尺寸及速度等等)
2、screen:显示游戏相关的内容(游戏界面、飞船、子弹等)
3、ship:实例化了一个飞船
4、bullets:实例化了一个子弹的编组
5、while循环:提供了一个游戏运行的主循环,用于动态更新游戏状态

2、settings.py

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

3、game_functions.py

文件game_functions.py包含一系列函数:
1、check_keydown_events:监听键盘某个键按下时需要提供的操作
2、check_keyup_events:监听键盘某个按下的键松开后需要提供的操作
3、check_events:监听全部键盘和鼠标的行为操作
4、update_screen:实时重绘游戏界面
5、update_bullets:对子弹数量进行控制
6、fire_bullet:根据实际情况,创建并发射子弹

4、ship.py

文件ship.py包含 Ship 类,这个类包含方法 init() 、管理飞船位置的方法 update() 以及在屏幕上绘制飞船的方法 blitme() 。

5、bullet.py

文件bullet.py包含 Bullet 类,这个类包含方法 init() 、管理子弹位置的方法 update() 以及在屏幕上绘制飞船的方法 draw_bullet() 。

二、创建第一个外星人

创建一个外星人的方式与创建一个飞船的方式基本是一样的,我们需要先找到一个外星人的图片,图片最好是无背景或者背景颜色与游戏界面颜色一致的,这样可以大大提升游戏的美观和体验,把它放入到images文件夹中,如下图就是一个背景颜色与游戏界面一致的图片:
Python项目实践之二:外星人(1)

1、创建 Alien 类

alien.py:
import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    """表示单个外星人的类"""

    def __init__(self, ai_settings, screen):
        super(Alien, self).__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        # 加载外星人图像,并设置其rect属性
        self.image = pygame.image.load('images/alien.png')
        self.rect = self.image.get_rect()

        # 每个外星人最初都在屏幕左上角附近
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height

        # 存储外星人的准确位置
        self.x = float(self.rect.x)

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

解释:Alien类与Ship类基本设置都是一样的,只是位置设置不同而已,需要注意的是Alien类继承了Sprite(精灵,不是雪碧哦),和子弹一样,外星人也是多个不是一个,而Ship 只有一个。

2、创建Alien实例

在alien_invasion.py中实例化Alien:

1、在主循环外实例化Alien:

    #创建一个外星人
    alien = Alien(ai_settings, screen)

2、在主循环内显示外星人:

        #每次循环重绘屏幕
        gf.update_screen(ai_settings, screen, ship, alien, bullets)

3、让外星人出现在屏幕上

为让外星人出现在屏幕上,我们在 game_functions.py的update_screen() 中调用其方法 blitme() :

def update_screen(ai_settings, screen, ship, alien, bullets):
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)

    # 在飞船和外星人后面重绘所有子弹 
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    alien.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

三、创建一群外星人

要绘制一群外星人,需要确定一行能容纳多少个外星人以及要绘制多少行外星人。我们将首先计算外星人之间的水平间距,并创建一行外星人,再确定可用的垂直空间,并创建整群外星人。

确定一行可容纳多少个外星人:

容纳外星人宽度 = 游戏界面宽度 - 2倍的外星人宽度(两边游戏界面的空出来的宽度)

available_space_x = ai_settings.screen_width – (2 * alien_width)

容纳外星人的个数 = 容纳外星人的宽度 / 2倍的外星人宽度(一个宽度用于放置外星人,另一个宽度为外星人右边的空白区域)

number_aliens_x = available_space_x / (2 * alien_width)
创建多行外星人:

为创建一行外星人,首先在alien_invasion.py中创建一个名为 aliens 的空编组(类似于创建子弹的编组),用于存储全部外星人,再调用game_functions.py中创建外星人群的函数:
alien_invasion.py的run_game()函数中,主循环while之外添加:

	#创建一个外星人编组
	aliens = Group()
	#创建一个外星人
    # alien = Alien(ai_settings, screen) #替换为创建外星人群
    # 创建外星人群
    gf.create_fleet(ai_settings, screen, aliens)

game_functions.py中用于更新游戏图像的update_screen()函数:

def update_screen(ai_settings, screen, ship, aliens, bullets):
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)

    # 在飞船和外星人后面重绘所有子弹 
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    # 让最近绘制的屏幕可见
    pygame.display.flip()
创建外星人群:

主程序中调用了game_functions.py中的创建外星人群的新函数 create_fleet(),但是我们还未定义此,函数,现在来定义此函数:
game_functions.py中添加新函数 create_fleet():

def create_fleet(ai_settings, screen, aliens):
    """创建外星人群"""
    # 创建一个外星人,并计算一行可容纳多少个外星人
    # 外星人间距为外星人宽度
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    # 创建第一行外星人
    for alien_number in range(number_aliens_x):
        # 创建一个外星人并将其加入当前行
        alien = Alien(ai_settings, screen)
        alien.x = alien_width + 2 * alien_width * alien_number
        alien.rect.x = alien.x
        aliens.add(alien)

解释:
1、首先,别忘记把Alien类导入到game_functions.py中,要不然你再怎么调用alien的属性都会报错。
2、计算游戏界面每一行能放置几个外星人,由于外星人的图片素材是外部提供的,Alien类中并没有它的长宽属性,所以必须实例化一个外星人,通过rect对其确定大小,然后再计算个数。
3、通过for循环将允许创建的外星人的个数添加到外星人组中,当然,这里要明确外星人组中每个外星人在游戏界面的定位alien.x = alien_width + 2 * alien_width * alien_number(每个外星人都往右
推一个外星人的宽度)。

重构 create_fleet()

分析create_fleet()函数,我们发现函数内容结构复杂,而且不便于以后的使用,它在内部处理了一系列的问题而得到了很多结论性的结果,但是假设后面我们要使用它内部的结果,就不能直接调用了,这样非常的不方便,因此,我们要对其进行重构,方便于后面的开发。

添加新函数 get_number_aliens_x() :用于计算每行可容纳多少个外星人

def get_number_aliens_x(ai_settings, alien_width):
    """计算每行可容纳多少个外星人"""
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    return number_aliens_x

添加新函数 create_alien() :用于创建一个外星人,并设置其位置后放入外星人组

def create_alien(ai_settings, screen, aliens, alien_number):
    """创建一个外星人并将其放在当前行,添加到外星人组中"""
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    aliens.add(alien)

最后:重构 create_fleet()

def create_fleet(ai_settings, screen, aliens):
    """创建外星人群"""
    # 创建一个外星人,并计算一行可容纳多少个外星人
    # 外星人间距为外星人宽度
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
    # 创建第一行外星人
    for alien_number in range(number_aliens_x):
        # 创建一个外星人并将其加入当前行
        create_alien(ai_settings, screen, aliens, alien_number)

这样做就舒服了,以后要是别的程序还用到每行可容纳多少个外星人,直接来这里调用就可以了

添加行

目前,已经完成了添加一行外星人的目的,但是游戏设定需要添加多行外星人。接下来,我们就来计算一下,游戏界面能添加多少行外星人。

容纳外星人的高度 = 游戏界面高度 - 外星人高度(外星人与游戏界面顶部的区域)- 最初外星人群与飞船的距离(外星人高度的两倍)- 飞船的高度

available_space_y = ai_settings.screen_height – 3 * alien_height – ship_height

容纳外星人的行数 = 容纳外星人的高度 / 2倍外星人的高度(每个外星人间距1个外星人高度的距离)

number_rows = available_height_y / (2 * alien_height)

接下来,我们在game_functions.py添加新函数get_number_rows()用于获取一共可以添加多少行外星人:

def get_number_rows(ai_settings, ship_height, alien_height):
    """计算屏幕可容纳多少行外星人"""
    available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)
    number_rows = int(available_space_y / (2 * alien_height))
    return number_rows

我们修改外星人的y坐标,并在第一行外星人上方留出与外星人等高的空白区域。相邻外星人行的y坐标相差外星人高度的两倍,因此我们将外星人高度乘以2,再乘以行号。第一行的行号为0,因此第一行的垂直位置不变,而其他行都沿屏幕依次向下放置。
修改game_functions.py中的create_alien(),将创建:

def create_alien(ai_settings, screen, aliens, row_number, alien_number):
    """创建一个外星人并将其放在当前行,添加到外星人组中"""
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    aliens.add(alien)

好了,现在再把game_functions.py中的create_fleet()进行修改,把外星人群添加到游戏界面中去:

def create_fleet(ai_settings, screen, ship, aliens):
    """创建外星人群"""
    # 创建一个外星人,并计算一行可容纳多少个外星人
    # 外星人间距为外星人宽度
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)
    # 创建一组外星人
    for row_number in range(number_rows):
        for alien_number in range(number_aliens_x):
            create_alien(ai_settings, screen, aliens, row_number, alien_number)

解释:
1、number_aliens_x:每行最多可以放多少个外星人
2、number_rows:游戏界面一共可以放多少行外星人
3、通过双层for循环实现外星人群体布局

最后,修改alien_invasion.py主程序中“# 创建外星人群”的代码(需要添加一个ship参数,因为计算行数的时候用到了飞船的高度):

gf.create_fleet(ai_settings, screen, ship, aliens)

四、移动外星人群

需求:外星人撞到屏幕边缘后下移一定的距离,再沿相反的方向移动。

1、向右移动外星人

首先,在settings.py中的__init__方法中添加一个控制外星人速度的设置,绑定到对象本身:

		# 外星人设置
        self.alien_speed_factor = 1

然后,使用这个设置来创建 alien.py 中的 update()方法,表示向右移动外星人 :

    def update(self):
        """向右移动外星人"""
        self.x += self.ai_settings.alien_speed_factor
        self.rect.x = self.x

接下来,在game_functions.py末尾添加新函数 update_aliens(),表示更新外星人的位置 :

def update_aliens(aliens):
    """更新外星人群中所有外星人的位置"""
    aliens.update()

最后,在主程序的主循环中添加game_functions.py的调用即可:

		#调用外星人群移动显示的函数
        gf.update_aliens(aliens)

2、创建表示外星人移动方向的设置

目前,已经实现外星人群整体向右移动,直至全部移出游戏界面,接下来,我们需要实现外星人群移动到游戏界面边界后向下移动,然后再反向移动的功能。

在settings.py中的外星人设置添加向下移动的速度属性和移动方向的判断标准:

# 外星人设置
        self.alien_speed_factor = 1
        self.fleet_drop_speed = 10  #表示向下移动的速度
        # fleet_direction为1表示向右移,为-1表示向左移
        self.fleet_direction = 1

3、检查外星人是否撞到了屏幕边缘

现在需要编写一个方法来检查是否有外星人撞到了屏幕边缘,还需修改 alien.py 中的 update() ,以让每个外星人都沿正确的方向移动。

首先,在alien.py中添加一个判断外星人是否撞到了屏幕边缘的函数check_edges():

    def check_edges(self):
        """如果外星人位于屏幕边缘,就返回True"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True

其次,修改修改 alien.py 中的 update() :

    def update(self):
        """向左或向右移动外星人"""
        self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction)
        self.rect.x = self.x

解释:self.x(当前外星人的位置) = self.x + self.ai_settings.alien_speed_factor(移动速度)* self.ai_settings.fleet_directio(移动方向)

4、向下移动外星人群并改变移动方向

有外星人到达屏幕边缘时,需要将整群外星人下移,并改变它们的移动方向。下面我们就对game_functions.py做修改,因为我们要在这里检查是否有外星人到达了左边缘或右边缘,game_functions.py是为游戏提供逻辑处理的函数库。

首先,要对外星人碰撞到屏幕边界实现转向向下的功能,所以在game_functions.py中添加一个change_fleet_direction函数:

def change_fleet_direction(ai_settings, aliens):
    """将整群外星人下移,并改变它们的方向"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
        ai_settings.fleet_direction *= -1

其次,要对外星人碰撞到屏幕边缘采取相应措施,因此,在game_functions.py中添加一个check_fleet_edges()函数:

def check_fleet_edges(ai_settings, aliens):
    """有外星人到达边缘时采取相应的措施"""
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settings, aliens)
            break

最后,就是要修改game_functions.py中用于更新外星人群位置的update_aliens()函数,使外星人群能正确的显示自己在屏幕的位置:

def update_aliens(ai_settings, aliens):
    """检查是否有外星人位于屏幕边缘,并更新整群外星人的位置"""
    check_fleet_edges(ai_settings, aliens)
    aliens.update()

我们修改了函数 update_aliens() ,在其中通过调用 check_fleet_edges() 来确定是否有外星人位于屏幕边缘。现在,函数 update_aliens() 包含形参 ai_settings ,因此我们在主程序alien_invasion.py调用它时也要指定与ai_settings 对应的实参:

		#调用外星人群的函数
        # gf.update_aliens(aliens)
        gf.update_aliens(ai_settings, aliens)

如果你现在运行这个游戏,外星人群将在屏幕上来回移动,并在抵达屏幕边缘后向下移动。现在可以开始射杀外星人,检查是否有外星人撞到飞船,或抵达了屏幕底端。

这是一篇读书笔记,如有不妥之处,请各位指正!!!

上一篇:Python实现飞机大战(搞怪)游戏!这是你没见过的全新版本!


下一篇:字典