文章目录

  • 创建外星人
  • 创建一群外星人
  • 重构create_fleet()


创建外星人

python基本项目结构 python项目总结_重绘


我们将使用这个位图来作为外星人

下面我们来编写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.bmp')
        self. rect = self.image.get_rect()
        
        # 每个外星人初始都在屏幕左上角附近
        self.rect.x = self.rect.width
        self.rect.y = self.height
        
        # 存储外星人的准确位置
        self.x = float(self.rect.x)
        
    def blitme(self):
        """在指定位置绘制外星人"""
        self.screen.blit(self.image, self.rect)

除位置不同外,这个类的大部分代码都与Ship类相似。每个外星人最初都位于屏幕左上角附近,我们将每个外星人的左边距都设置为外星人的宽度,并将上边距设置为外星人的高度。

同时我们要在alien_invasion.py中创建一个Alien类:

import pygame
from settings import Settings
from ship import Ship
from aline import Alien
import game_functions as gf
from pygame.sprite import Group
def run_game():
    # 初始化游戏并创建一个屏幕对象,设置和pygame
    pygame.init()
    # setting类
    ai_settings = Settings()

    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Aline Invasion")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)

    # 创建一个用于存储子弹的编组
    bullets = Group()


    # 创建一个外星人
    alien = Alien(ai_settings, screen)
    
    # 游戏主循环
    while True:
        gf.check_events(ai_settings, screen, ship, bullets)
        ship.update()
        bullets.update()
        gf.update_screen(ai_settings, screen, ship, alien, bullets)
run_game()

python基本项目结构 python项目总结_重绘_02


同时要注意到我们修改了gf函数的传参,所以我们继续去game_functions.py文件中修改函数update_screen

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()

python基本项目结构 python项目总结_pygame_03

创建一群外星人

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

为确定一行可容纳多少个外星人,我们来看看可用的水平空间有多大。屏幕宽度存储在ai_settings.screen_width中,但需要在屏幕两边都留下一定的边距,把它设置为外星人的宽度。

由于有两个边距,因此可用于放置外星人的水平空间为屏幕宽度减去外星人宽度的两倍:

available_space_x = ai_settings.screen_width – (2 * alien_width)

我们还需要在外星人之间留出一定的空间,即外星人宽度。因此,显示一个外星人所需的水平空间为外星人宽度的两倍:一个宽度用于放置外星人,另一个宽度为外星人右边的空白区域。
为确定一行可容纳多少个外星人,我们将可用空间除以外星人宽度的两倍:

number_aliens_x = available_space_x / (2 * alien_width)

我们将在创建外星人群时使用这些公式。
为创建一行外星人,首先在alien_invasion.py中创建一个名为aliens的空编组,用于存储全部外星人,再调用game_functions.py中创建外星人群的函数:

我们更改了之前外星人的代码:

import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
    # 初始化游戏并创建一个屏幕对象,设置和pygame
    pygame.init()
    # setting类
    ai_settings = Settings()

    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Aline Invasion")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)

    # 创建一个用于存储子弹的编组
    bullets = Group()
    # 创建一个用于存储外星人的编组
    aliens = Group()
    # 创建外星人群
    gf.creat_fleet(ai_settings, screen, aliens)

    # 游戏主循环
    while True:
        gf.check_events(ai_settings, screen, ship, bullets)
        ship.update()
        bullets.update()
        gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()

由于我们不再在alien_invasion.py中直接创建外星人,因此无需在这个文件中导入Alien类。

我们创建了一个空编组,用于储存所有的外星人。接下来调用稍后编写的函数creat_fleet(),接着我们修改了update_screen()的调用,让它传递的参数中包括外星人编组

接着我们修改update_screen()
game_functions.py

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()

对编组调用draw()时,Pygame自动绘制编组的每个元素,绘制位置由元素的属性rect决定。在这里,aliens.draw(screen)在屏幕上绘制编组中的每个外星人。

下面我们来创建外星人群,我们把新函数create_fleet()放在在game_functions.py的末尾。注意我们要导入Alien类,需要在文件game_functions.py开头添加相应的import语句:

def create_fleet(ai_settngs, screen, aliens):
    """创建外星人群"""
    # 创建一个外星人,并计算一行可容纳多少个外星人
    # 外星人间距为外星人宽度
    alien = Alien(ai_settngs, screen)
    alien_width = alien.rect.width
    available_space_x = ai_settngs.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_settngs, screen)
        alien.x = alien_width + 2 * alien_width * alien_number
        alien.rect.x = alien.x
        aliens.add(alien)

这些代码大都在前面详细介绍过。为放置外星人,我们需要知道外星人的宽度和高度,因此在执行计算前,我们先创建一个外星人。这个外星人不是外星人群的成员,因此没有将它加入到编组aliens中。我们从外星人的rect属性中获取外星人宽度,并将这个值存储到alien_width中,以免反复访问属性rect。我们计算可用于放置外星人的水平空间,以及其中可容纳多少个外星人。

接下来,我们编写了一个循环,它从零数到要创建的外星人数。在这个循环的主体中,我们创建一个新的外星人,并通过设置x坐标将其加入当前行。将每个外星人都往右推一个外星人的宽度。接下来,我们将外星人宽度乘以2,得到每个外星人占据的空间(其中包括其右边的空白区域),再据此计算当前外星人在当前行的位置。最后,我们将每个新创建的外星人都添加到编组aliens中。

python基本项目结构 python项目总结_python基本项目结构_04


现在的运行结果如上图所示。

重构create_fleet()

倘若我们创建了外星人群,也许应该让create_fleet()保持原样,但鉴于创建外星人的工作还未完成,我们稍微清理一下这个函数。下面是create_fleet()和两个新函数,get_number_aliens_x()create_alien()

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

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)

def create_fleet(ai_settings, screen, aliens):
    """创建外星人群"""
    # 创建一个外星人,并计算一行可容纳多少个外星人
    # 外星人间距为外星人宽度
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    number_aliens_x = get_number_aliens_x(ai_settings, alien_width)

    # 创建第一行外星人
    for alien_number in range(number_aliens_x):# 创建一个外星人并将其加入当前行
        create_alien(ai_settings, screen, aliens, alien_number)

函数get_number_aliens_x()的代码都来自create_fleet(),且未做任何修改。函数create_alien()的代码也都来自create_fleet(),且未做任何修改,只是使用刚创建的外星人来获取外星人宽度。

通过这样的重构,添加新行进而创建整群外星人将更容易。

后续内容详见下节博客。