PYTHON入门级游戏开发:宇宙飞船游戏两万字详析

手讲解超详细python入门游戏项目‘打外星飞船’手把(一)

由于内容比较多,这里会分为五篇文章来讲解,从页面的创建、飞船控制、射击、外星人创建、射杀外星人五片来展开。

做一个窗口和设置响应用户

import sys

import pygame
''' '''
""" 我们先创建一个新的文件,保存的名字就叫做主函数吧,main.py。首先我们应该导入两个模块sys和pygame,pygame是用来开发游戏所需要的功能的,sys是我们退出的时候,我们需要用到的 """"
 
from settings import Settings
#这个是我们在后面创建一个settings用来管理设置,后年会补充
class AlienInvasion:
    """我们先创建一个类,用它来管理游戏资源和行为的类。"""

    def __init__(self):
        """这个我们开始游戏的主循环"""
        pygame.init()
        #在这个类中,我们先定义一个函数,调用函数pygame.init()初始化背景设置,让他能够正常的工作

        self.settings = Settings()

        self.screen = pygame.display.set_mode(
            (self.settings.screen_width, self.settings.screen_height))
            #在主程序文件中打入settings类调用pygames in it(),创建一个settings实力并付给self.settings,这个时候我们把它的属性宽度和高度复给主函数



        pygame.display.set_caption("Alien Invasion")


    def run_game(self):
        """开始游戏的主循环了,在这个循环中,我们不断的进行一个循环,并且管理屏幕更新的代码。比如说按键或移动鼠标的时候就是要响应一次,作为一次响应事件,就是一个循环。
 """
        while True:
            
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
            #在循环中,如果我们检测到了退出的指令,我们就用       sys.exit()来退出
         
            self.screen.fill(self.settings.bg_color)
           #调用方法fill(),用这种背景色填充屏幕。方法fill()用于处理surface只接受一个实参一种颜色

            pygame.display.flip()
# 让最近绘制的屏幕可见,在这里我们通过不断的循环都会绘制一个空的屏幕,并且插去就的屏幕,所以让新的屏幕可见就行,成了动画
if __name__ == '__main__':
    # 创建游戏实例,并且开始运行游戏

    ai = AlienInvasion()
    ai.run_game()

这里重新建立一个文件,可以命名为settings.py

class Settings:
    """我们开始编写一个名为settings的模块,在这个模块中,所有的设置都储存在这里,以免在代码中到处添加设置。创建另外一个文件,命名为settings.py。
"""

    def __init__(self):
        """这里我们建立一个函数"""
        # 如果只是一个默认的屏幕,就太没有意思了,在现在我们把屏幕的颜色改成白色
颜色是由RGB指定的,比如说25500表示红色;02550表示绿色;这里我们把背景色设为白色

        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)

这里重新建立一个文件,可以命名为ship.py。我们在这里会先创立一ship的模块.,我们用这个模块来管理飞船的大部分行为。

import pygame
 
 
class Ship:
    """管理飞船的类"""
 
    def __init__(self, ai_game):
        """初始化飞船并且初始化的他的位置"""
        self.screen = ai_game.screen
        #在定义这个类之前,我要导入模块pygame
在一处的话,将屏幕付给了sheep的一个属性,方便这个类的所有方法后面的轻松访问

        
        self.screen_rect = ai_game.screen.get_rect()

        # 加载飞船图像
        self.image = pygame.image.load('images/ship.bmp')
        #在这里我们需要把飞船的图像添加进去,一般来说,图像的格式都是JPGGIF多一点在这里我们用的是bmp的格式. 我把飞船的图片放在下面,注意在你建立文档的时候,一定要把图片放在一个名为images的文件夹下,并且我其他项目是同一个文件夹。


        self.rect = self.image.get_rect()

       
        self.rect.midbottom = self.screen_rect.midbottom
        #我们都把它放在屏幕底部的中央因为这里我们要把非常放在底部的中央,所以我们应该用的属性叫做 midbottom


    def blitme(self):
        
        self.screen.blit(self.image, self.rect)
        #现在我们要把这个飞船的图像调用出来,括号里面的是非常的位置

这个是我们要导入的图片
在这里插入图片描述

这个是我们最终建立好的游戏界面
在这里插入图片描述

手把手讲解超详细python入门游戏项目‘打外星飞船’(二)

上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动、射击子弹,但是在此之前我们还有一个非常重要的部分–重构。

重构

在大型项目中,经常需要添加新代码重构旧的代码,简单来说就把一些代码整理成函数,用函数之前的代码就变成了一句函数。这里我们就需要把之前的run_game()拆分成两个辅助方法,基本上辅助方法要以单个下划线打头。
我们直接回顾上此的代码

   def run_game(self):
      
        while True:
  #这里把管理事件的代码移动到这两个函数里面了,代码在下面
            self._check_events()
            self._update_screen()

    def _check_events(self):
#这个是之前按键和鼠标的代码
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

    def _update_screen(self):
    #更新图像,切换到新屏幕
        self.screen.fill(self.settings.bg_color)
        self.ship.blitme()

        pygame.display.flip()

飞船的控制

这里我开始把按键链接到电脑,每一次按下一个按键,pygame上都会注册一个事件,这里每次按下都会注册一个KEYDOWN事件,如果检测到这个事件就会移动

def _check_events(self):
     
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                      sys.exit()
            elif event.type == pygame.KEYDOWN: #检测到了按键被按下      
               if event.type == pygame.K_RIGHT:#按下的键是右键
                    self.ship.rect.x +=1#这里的距离+1,即右边移
  

左右持续移动

        # 添加左右的移动的标志,立flag是好个方法,简化代码过程
        self.moving_right = False
        self.moving_left = False

但检测到左右移动键按下后,flag变成1

      if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
         elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                 self.ship.moving_right = False

这个时候我们在主运行加入移动函数,update()

    def run_game(self):
        """Start the main loop for the game."""
        while True:
            self._check_events()
            self.ship.update()#控制移动
            self._update_screen()

下面这个就是移动函数

    def update(self):
       if self.moving_right:
          self.ship.rect.x +=1#右移动加一
       if self.moving_left:
          self.ship.rect.x -=1#左移动减一
              

调整数独、限制活动范围
这里我们就整体展现下ship加工部分了。

import pygame
 
class Ship:
 
    def __init__(self, ai_game):
        self.screen = ai_game.screen


        self.settings = ai_game.settings#这里添加一个settings属性,等会要在update用


        self.screen_rect = ai_game.screen.get_rect()        
        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()    
        self.rect.midbottom = self.screen_rect.midbottom

#这里有个方法是储存小数值,因为飞船移动的是像素,所以这里要要把位置赋给能够储存小数值的变量
        self.x = float(self.rect.x)

        # 移动的flag
        self.moving_right = False
        self.moving_left = False

    def update(self):
    
       
        if self.moving_right and self.rect.right < self.screen_rect.right:
        #飞船未飞出右边的边缘
            self.x += self.settings.ship_speed
            #移动的速度会不断地加一个像素的大小,注意:主函数中已经设置了速度为self.ship_speed=1.5
        if self.moving_left and self.rect.left > 0:
        #如果飞船未飞出左侧,左侧是0
            self.x -= self.settings.ship_speed
        #根据self.x更新rect对象
        self.rect.x = self.x

再次重构
因为一句添加了不少内容,所以

    def _check_events(self):
        """Respond to keypresses and mouse events."""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)#添加说明
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)

    def _check_keydown_events(self, event):
    #这是刚才的语句,写进了这个句子
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = True
        
    def _check_keyup_events(self, event):
    #同样的
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = False
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = False

按Q键退出

    def _check_keydown_events(self, event):
        """Respond to keypresses."""
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = True

#这里我们设置的按键Q退出,接受到Q键反应接受后执行sys模块的退出指令
        elif event.key == pygame.K_q:
            sys.exit()

全屏运行

    def __init__(self):
        """Initialize the game, and create game resources."""
        pygame.init()
        self.settings = Settings()
        #游戏开始时传入的是(00)以及参数pygame.FULLSCREEN,这个指令是覆盖整个屏幕
        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        #这里使用屏幕的高和宽更新数据
        self.settings.screen_width = self.screen.get_rect().width
        self.settings.screen_height = self.screen.get_rect().height

手把手讲解超详细python入门游戏项目‘打外星飞船’(三)

第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解。因为有很多代码在前面都已经打过注释 了,这次我们就只在新加的代码旁边打注释了

任务三:按空格键的时候发射子弹,一个屏幕上最多发射三颗子弹,子弹向上飞行,到屏幕后消失

主文件()

import sys

import pygame

from settings import Settings
from ship import Ship
#这里我们创建了管理子弹的类,要引入主文件使用
from bullet import Bullet

class AlienInvasion:

    def __init__(self):
        pygame.init()
        self.settings = Settings()

        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        self.settings.screen_width = self.screen.get_rect().width
        self.settings.screen_height = self.screen.get_rect().height
        pygame.display.set_caption("Alien Invasion")

        self.ship = Ship(self)
        #这里创建用于储存子弹控制的编组
        self.bullets = pygame.sprite.Group()

    def run_game(self):
        while True:
            self._check_events()
            self.ship.update()
            #把子弹的函数加入主文件
            self._update_bullets()
            self._update_screen()

    def _check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            #这里是键盘按到空格键会返回KEYDOWN,此时调用开火函数
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)

    def _check_keydown_events(self, event):
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = True
        elif event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_SPACE:
            self._fire_bullet()

    def _check_keyup_events(self, event):
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = False
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = False

    def _fire_bullet(self):
         #这是一个判断语句,如果子弹数小于三,我们就可以执行下面的函数
        if len(self.bullets) < self.settings.bullets_allowed:
            #创建一个子弹新的bullet,把它加入到编组bullet储存
            new_bullet = Bullet(self)
            self.bullets.add(new_bullet)

    def _update_bullets(self):
        # 更新子弹的位置函数
        self.bullets.update()

        #不断循环删除子弹,子弹这里是他的y轴超出了屏幕,我们就删除
        for bullet in self.bullets.copy():
            if bullet.rect.bottom <= 0:
                 self.bullets.remove(bullet)

    def _update_screen(self):
        self.screen.fill(self.settings.bg_color)
        self.ship.blitme()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()

        pygame.display.flip()


if __name__ == '__main__':
    ai = AlienInvasion()
    ai.run_game()

子弹的控制类

import pygame
from pygame.sprite import Sprite
 
class Bullet(Sprite):
    """创建一个管理子弹的类"""

    def __init__(self, ai_game):
        """在飞船的当前所在的位置创建出一个子弹的图像"""
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.color = self.settings.bullet_color

        # 现在原点处创建一颗子弹,同时子弹的宽高在设置类的参数里引入
        self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
            self.settings.bullet_height)
        #子弹的初始位置设置成了飞船的初始位置
        self.rect.midtop = ai_game.ship.rect.midtop
        
        # 用float储存这个位置
        self.y = float(self.rect.y)

    def update(self):
        """子弹向上飞"""
        # 每一次子弹向上移动,y轴在不断地自减
        self.y -= self.settings.bullet_speed
        # 把最新的位置给子弹
        self.rect.y = self.y

    def draw_bullet(self):
        """画出子弹,参数是用self里面储存的参数填充的"""
        pygame.draw.rect(self.screen, self.color, self.rect)

设置类文件

class Settings:
    def __init__(self):
        # Screen settings
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)

        # Ship settings
        self.ship_speed = 1.5

        # 这里在设置子弹的一系列的参数,等会直接调用这个类
        self.bullet_speed = 1.0
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60, 60, 60)
        #最大的子弹数为3
        self.bullets_allowed = 3

飞船的参数设置文件

import pygame
 
class Ship:
 
    def __init__(self, ai_game):
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.screen_rect = ai_game.screen.get_rect()

        # Load the ship image and get its rect.
        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()

        # Start each new ship at the bottom center of the screen.
        self.rect.midbottom = self.screen_rect.midbottom

        # Store a decimal value for the ship's horizontal position.
        self.x = float(self.rect.x)

        # Movement flags
        self.moving_right = False
        self.moving_left = False

    def update(self):
        # Update the ship's x value, not the rect.
        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.x += self.settings.ship_speed
        if self.moving_left and self.rect.left > 0:
            self.x -= self.settings.ship_speed

        # Update rect object from self.x.
        self.rect.x = self.x

    def blitme(self):
        self.screen.blit(self.image, self.rect)

手把手讲解超详细python入门游戏项目‘打外星飞船’(四)

在经过创立屏幕、飞船移动和设置子弹,我们这里开始设置外形人的创建和移动。我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两边移动,这里继承了上面四个文件外我们还多键一个文件来管理外星人的类,也就是五个文件。这里后三个文件没有太大的变化,我们主要调整了前两个文件

主文件

import sys

import pygame

from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien


class AlienInvasion:


    def __init__(self):

        pygame.init()
        self.settings = Settings()

        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        self.settings.screen_width = self.screen.get_rect().width
        self.settings.screen_height = self.screen.get_rect().height
        pygame.display.set_caption("Alien Invasion")

        self.ship = Ship(self)
        self.bullets = pygame.sprite.Group()
        self.aliens = pygame.sprite.Group()
        self._creat_fleet()

    def run_game(self):

        while True:
            self._check_events()
            self.ship.update()
            self._update_bullets()
            #这里多加了外星人的运动函数
            self._update_aliens()
            self._update_screen()

    def _check_events(self):

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)

    def _check_keydown_events(self, event):

        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = True
        elif event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_SPACE:
            self._fire_bullet()

    def _check_keyup_events(self, event):
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = False
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = False

    def _fire_bullet(self):

        if len(self.bullets) < self.settings.bullets_allowed:
            new_bullet = Bullet(self)
            self.bullets.add(new_bullet)

    def _update_bullets(self):
     

        self.bullets.update()


        for bullet in self.bullets.copy():
            if bullet.rect.bottom <= 0:
                 self.bullets.remove(bullet)

    def _update_aliens(self):
        """
        判断外星人有没有到边,到了就调整位置
        """
        self._check_fleet_edges()
        self.aliens.update()

    def _create_fleet(self):
        """用来创建外星人"""
        # 计算出一行可以容纳多少外星人
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        available_space_x = self.settings.screen_width - (2 * alien_width)
        number_aliens_x = available_space_x // (2 * alien_width)
        
        #计算出一列可以容纳多少外星人
        ship_height = self.ship.rect.height
        available_space_y = (self.settings.screen_height -
                                (3 * alien_height) - ship_height)
        number_rows = available_space_y // (2 * alien_height)
        
        # 这里用了一个嵌套循环,外部是列,内部是行,创建多个外形人
        for row_number in range(number_rows):
            for alien_number in range(number_aliens_x):
                self._create_alien(alien_number, row_number)

    def _create_alien(self, alien_number, row_number):
        """创建一个外星人,放在一行里面"""
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        #总宽度是所有外星人的宽度加间隔,间隔也取外星人的宽度乘上总行数
        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
        self.aliens.add(alien)

    def _check_fleet_edges(self):
        """这里判断外星人到底屏幕底部没有"""
        for alien in self.aliens.sprites():
        #遍历每个外星人
            if alien.check_edges():
                self._change_fleet_direction()
                #如果到了就退出循环
                break
            
    def _change_fleet_direction(self):
        """将外星人下移加左右飘"""
        for alien in self.aliens.sprites():
            alien.rect.y += self.settings.fleet_drop_speed
        self.settings.fleet_direction *= -1

    def _update_screen(self):
        self.screen.fill(self.settings.bg_color)
        self.ship.blitme()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()
        self.aliens.draw(self.screen)

        pygame.display.flip()


if __name__ == '__main__':
    # Make a game instance, and run the game.
    ai = AlienInvasion()
    ai.run_game()

外星人控制

import pygame
from pygame.sprite import Sprite
 
class Alien(Sprite):
    """管理的外星人的类"""

    def __init__(self, ai_game):
        """初始化外星人并设置他们初始位置"""
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.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.rect.height

        # 记录下外星人的位置
        self.x = float(self.rect.x)

    def check_edges(self):
       #判断是否超过屏幕
        """看看飞船有没有超过屏幕,如果屏幕大于右边的屏幕的数后者小于零是超越屏幕的左边"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <= 0:
            return True

    def update(self):
        """这里用乘积的办法,每次就是用所在的x坐标减去方向*1or-1"""
        self.x += (self.settings.alien_speed *
                        self.settings.fleet_direction)
        self.rect.x = self.x

子弹管理类

import pygame
from pygame.sprite import Sprite
 
class Bullet(Sprite):

    def __init__(self, ai_game):

        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.color = self.settings.bullet_color

        self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
            self.settings.bullet_height)
        self.rect.midtop = ai_game.ship.rect.midtop

        self.y = float(self.rect.y)

    def update(self):
        # Update the decimal position of the bullet.
        self.y -= self.settings.bullet_speed
        # Update the rect position.
        self.rect.y = self.y

    def draw_bullet(self):
        pygame.draw.rect(self.screen, self.color, self.rect)

总设置参数

class Settings:
    """这个类用于储存一些参数"""

    def __init__(self):
        # 屏幕参数
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)

        # 飞船参数
        self.ship_speed = 1.5

        # 子弹参数
        self.bullet_speed = 1.0
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60, 60, 60)
        self.bullets_allowed = 3

        # 外星人左右移动的速度1,向下移动的速度10
        self.alien_speed = 1.0
        self.fleet_drop_speed = 10
        # 这里其实是在设置每次外形人飞船的位置,1为右移一位,-1为左移
        self.fleet_direction = 1

飞船设置

import pygame
 
class Ship:
    """飞船参数"""
 
    def __init__(self, ai_game):

        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.screen_rect = ai_game.screen.get_rect()


        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()
        self.rect.midbottom = self.screen_rect.midbottom

        self.x = float(self.rect.x)

        self.moving_right = False
        self.moving_left = False

    def update(self):


        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.x += self.settings.ship_speed
        if self.moving_left and self.rect.left > 0:
            self.x -= self.settings.ship_speed


        self.rect.x = self.x

    def blitme(self):

        self.screen.blit(self.image, self.rect)

手把手讲解超详细python入门游戏项目‘打外星飞船’(五)

这是最后一个项目了,前面我们讲了整个游戏页面的控制、飞船、子弹、外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文件一共有六个:主函数、飞船、外星飞船、子弹、设置参数、跟踪游戏统计信息六个文件。在这里我们要实现的任务是:子弹碰到外形飞船是让飞船消失,同时飞船碰到外星人飞船或者外星人飞船碰到屏幕低端结束游戏。

主函数

import sys
from time import sleep

import pygame

from settings import Settings
#我们需要创建一个文件去储存游戏统计信息,这里引入主函数
from game_stats import GameStats
from ship import Ship
from bullet import Bullet
from alien import Alien


class AlienInvasion:
    """控制游戏所有类和函数的类"""

    def __init__(self):
        """初始化游戏并且调用相关的函数资源"""
        pygame.init()
        self.settings = Settings()

        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        self.settings.screen_width = self.screen.get_rect().width
        self.settings.screen_height = self.screen.get_rect().height
        pygame.display.set_caption("Alien Invasion")

        #创建一个用于储存游戏并且统计信息的实例
        self.stats = GameStats(self)

        self.ship = Ship(self)
        self.bullets = pygame.sprite.Group()
        self.aliens = pygame.sprite.Group()

        self._create_fleet()

    def run_game(self):
        """我们开始了游戏的主循环"""
        while True:
            self._check_events()

            if self.stats.game_active:
                self.ship.update()
                self._update_bullets()
                self._update_aliens()

            self._update_screen()

    def _check_events(self):
        """这个是读取键盘和鼠标指令的函数"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)

    def _check_keydown_events(self, event):
        """接收键盘上左右移动等指令"""
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = True
        elif event.key == pygame.K_q:
            sys.exit()
        elif event.key == pygame.K_SPACE:
            self._fire_bullet()

    def _check_keyup_events(self, event):
        """释放键盘指令"""
        if event.key == pygame.K_RIGHT:
            self.ship.moving_right = False
        elif event.key == pygame.K_LEFT:
            self.ship.moving_left = False

    def _fire_bullet(self):
        """创键一个新的子弹并把他加入子弹组"""
        if len(self.bullets) < self.settings.bullets_allowed:
            new_bullet = Bullet(self)
            self.bullets.add(new_bullet)

    def _update_bullets(self):
        """变换子弹的位置并且删除旧的子弹"""
        #变换位置
        self.bullets.update()

        # 删除旧的子弹
        for bullet in self.bullets.copy():
            if bullet.rect.bottom <= 0:
                 self.bullets.remove(bullet)

        self._check_bullet_alien_collisions()

    def _check_bullet_alien_collisions(self):
        """响应子弹和外星人碰撞,删除碰撞的两者的函数"""
        # 检查是否有子弹击中外星人,有就删除子弹和外星人
        collisions = pygame.sprite.groupcollide(
                self.bullets, self.aliens, True, True)

        if not self.aliens:
            # 删除现有的子弹并创建一群外星人
            self.bullets.empty()
            self._create_fleet()

    def _update_aliens(self):
        """
       判断是否是已经到了边缘,同时更新飞船的位置
        """
        self._check_fleet_edges()
        self.aliens.update()

        # 检查是否飞船和外星人飞船是否相碰
        if pygame.sprite.spritecollideany(self.ship, self.aliens):
            self._ship_hit()

        #检查外星人飞船是否到了底部
        self._check_aliens_bottom()

    def _check_aliens_bottom(self):
        """Check if any aliens have reached the bottom of the screen."""
        screen_rect = self.screen.get_rect()
        for alien in self.aliens.sprites():
            if alien.rect.bottom >= screen_rect.bottom:
                # Treat this the same as if the ship got hit.
                self._ship_hit()
                break

    def _ship_hit(self):
        """响应飞船被外星人撞到时候"""
        if self.stats.ships_left > 0:
            # Decrement ships_left.
            self.stats.ships_left -= 1
            
            # 清除所有的子弹和外星人
            self.aliens.empty()
            self.bullets.empty()
            
            # 创建新的飞船,把他放到屏幕中央开始游戏
            self._create_fleet()
            self.ship.center_ship()
            
            # 暂停一会,让玩家可以看到飞船碰撞
            sleep(0.5)
        else:
            self.stats.game_active = False

    def _create_fleet(self):
        # 计算行列的外星人可以容纳多少个,并创建数行数列的外星人
        
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        available_space_x = self.settings.screen_width - (2 * alien_width)
        number_aliens_x = available_space_x // (2 * alien_width)
        
       
        ship_height = self.ship.rect.height
        available_space_y = (self.settings.screen_height -
                                (3 * alien_height) - ship_height)
        number_rows = available_space_y // (2 * alien_height)
        
        # 创建外星人的移动
        for row_number in range(number_rows):
            for alien_number in range(number_aliens_x):
                self._create_alien(alien_number, row_number)

    def _create_alien(self, alien_number, row_number):
        """创建一群外星人飞船"""
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        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
        self.aliens.add(alien)

    def _check_fleet_edges(self):
        """如果有任何飞船到达边缘要及时反应"""
        for alien in self.aliens.sprites():
            if alien.check_edges():
                self._change_fleet_direction()
                break
            
    def _change_fleet_direction(self):
        """让外星人飞船左右移动"""
        for alien in self.aliens.sprites():
            alien.rect.y += self.settings.fleet_drop_speed
        self.settings.fleet_direction *= -1

    def _update_screen(self):
        """更新屏幕上的图片"""
        self.screen.fill(self.settings.bg_color)
        self.ship.blitme()
        for bullet in self.bullets.sprites():
            bullet.draw_bullet()
        self.aliens.draw(self.screen)

        pygame.display.flip()


if __name__ == '__main__':
    # Make a game instance, and run the game.
    ai = AlienInvasion()
    ai.run_game()

外星人文件

import pygame
from pygame.sprite import Sprite
 
class Alien(Sprite):
    """外星人移动管里类"""

    def __init__(self, ai_game):
        """初始化外星人并把放置他们的位置"""
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings

        #下载图片
        self.image = pygame.image.load('images/alien.bmp')
        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 check_edges(self):
        """返回flag如果飞船到达边缘"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <= 0:
            return True

    def update(self):
        """向左或者向右移动飞船"""
        self.x += (self.settings.alien_speed *
                        self.settings.fleet_direction)
        self.rect.x = self.x

子弹文件

import pygame
from pygame.sprite import Sprite
 
class Bullet(Sprite):
    """管理子弹的类"""

    def __init__(self, ai_game):
        """在飞船的位置创建一个子弹"""
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.color = self.settings.bullet_color

        # 现在原点创建一个矩形然后移动到飞船头部
        self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
            self.settings.bullet_height)
        self.rect.midtop = ai_game.ship.rect.midtop
        
        # 储存子弹
        self.y = float(self.rect.y)

    def update(self):
        """子弹超过屏幕后移除子弹"""
        # Update the decimal position of the bullet.
        self.y -= self.settings.bullet_speed
        # Update the rect position.
        self.rect.y = self.y

    def draw_bullet(self):
        """在屏幕上画出子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)

参数设置类文件

class Settings:
    """设置一系列参数"""

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

        # 飞船的速度等参数
        self.ship_speed = 1.5
        self.ship_limit = 3

        # 子弹的设置
        self.bullet_speed = 1.5
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60, 60, 60)
        self.bullets_allowed = 3

        # 外星人飞船的设置
        self.alien_speed = 1.0
        self.fleet_drop_speed = 10
        # fleet_direction of 1 represents right; -1 represents left.
        self.fleet_direction = 1

飞船文件

import pygame
 
class Ship:
    """管理飞船的类"""
 
    def __init__(self, ai_game):
        """初始化飞船并且调动他的位置."""
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.screen_rect = ai_game.screen.get_rect()

        # 调用飞船图片并且储存他的位置
        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()

        # 每个飞船都在屏幕的中央出现
        self.rect.midbottom = self.screen_rect.midbottom

      
        self.x = float(self.rect.x)

        # 移动flag
        self.moving_right = False
        self.moving_left = False

    def update(self):
        """移动飞船根据flag"""
        # Update the ship's x value, not the rect.
        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.x += self.settings.ship_speed
        if self.moving_left and self.rect.left > 0:
            self.x -= self.settings.ship_speed

        # 储存飞船目前的位置
        self.rect.x = self.x

    def blitme(self):
        """在目前位置画出飞船"""
        self.screen.blit(self.image, self.rect)

    def center_ship(self):
        """把飞船放在屏幕中央"""
        self.rect.midbottom = self.screen_rect.midbottom
        self.x = float(self.rect.x)

跟踪游戏统计文件

class GameStats:
    """跟踪游戏统计信息"""
    
    def __init__(self, ai_game):
        """初始化游戏信息"""
        self.settings = ai_game.settings
        self.reset_stats()

        #游戏启动处于活动状态
        self.game_active = True
        
    def reset_stats(self):
        """初始化在游戏运行期间可能变化的统计信息"""
        self.ships_left = self.settings.ship_limit

这个是最后的配置的外星人和飞船图片
请添加图片描述
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/272644.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32逆变器方案

输入电压&#xff1a; 额定输入电压&#xff1a;DC110V 输入电压范围&#xff1a;DC77-137.5V 额定输出参数 电压&#xff1a;200V5%&#xff08;200VAC~240VAC 可调&#xff09; 频率&#xff1a; 42Hz0.5Hz&#xff08;35-50 可调&#xff09; 额定输出容量&#xff1a;1…

CentOS7搭建Elasticsearch与Kibana服务

1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里先创建一个网络&#xff1a; docker network create es-net 1.2拉取elasticsearch镜像 docker pull elasticsearch:7.11.1 1.3.运行 运行docker命令&#xff0c;部…

致远互联FE协作办公平台 editflow_manager.jsp SQL注入漏洞

漏洞描述 致远互联FE协作办公平台是一款为企业提供全方位协同办公解决方案的产品。它集成了多个功能模块&#xff0c;旨在帮助企业实现高效的团队协作、信息共享和文档管理。致远互联FE协作办公平台editflow_manager存在sql注入漏洞&#xff0c;攻击者可以获得敏感信息。 资产…

Vue框架引入Element-Ui

首先已经创建好了 Vue 框架&#xff0c;安装好了 node.js。 没有完成的可按照此博客搭建&#xff1a;搭建Vue项目 之后打开终端&#xff0c;使用命令。 1、命令引入 npm i element-ui -S2、package.json 查看版本 在 package.json 文件里可查看下载好的依赖版本。 3、在 ma…

Selenium自动化测试-设置元素等待

selenium中有三种时间等待&#xff1a; 强制等待&#xff1a;sleep 隐式等待&#xff1a;implicitly_wait 显示等待&#xff1a;WebDriverWait 1.sleep 让程序暂停运行一定时间&#xff0c;等待时间到达后继续运行。 使用sleep&#xff0c;需先导入time模块&#xff0c;im…

002、使用 Cargo 创建新项目,打印 Hello World

1. Cargo 简介 Cargo 是 Rust 的构建系统和包管理工具&#xff0c;比如构建代码、下载依赖的库、构建这些库等等。在安装 Rust 时&#xff0c;Cargo也会一起安装。 2. 创建新项目的具体步骤 步骤1&#xff1a; 我们在桌面新建一个文件夹&#xff0c;用于存放后面练习用的代码文…

vector的erase()方法遍历删除元素迭代器失效问题、及删除最后一个元素迭代器失效问题)

1.删除指定范围的元素 vector删除元素之pop_back(),erase(),remove() 向量容器vector的成员函数pop_back()可以删除最后一个元素. 而函数erase()可以删除由一个iterator指出的元素&#xff0c;也可以删除一个指定范围的元素。 还可以采用通用算法remove()来删除vector容器中的…

数字电子技术 一天速成

文章目录 一、数制与编码1. 数制转换2. BCD编码 二、逻辑代数1. 常见逻辑运算及逻辑门 三、化简逻辑表达式1. 卡诺图 求 表达式2. 表达式 画 卡诺图3. 卡诺图 化简 表达式4. 公式法 化简 表达式 ⭐⭐5. 表达式 求 反函数6. 卡诺图 求 反函数 四、组合逻辑电路的分析和设计1. 逻…

Mysql(5日志备份恢复)

一.日志管理 MySQL 的日志默认保存位置为 /usr/local/mysql/data 先看下mysql的日志文件有无&#xff1a; 修改配置文件添加&#xff1a;错误日志&#xff0c;用来记录当MySQL启动、停止或运行时发生的错误信息&#xff0c;默认已开启 修改配置文件添加&#xff1a;通用查…

.json文件转为.dll文件后还能读取吗?

(只是修改了后缀名而已&#xff0c;做一个伪装&#xff09; 测试&#xff1a; QFile file(QApplication::applicationDirPath() "/config.dll");qDebug()<<QApplication::applicationDirPath() "/config.dll";if (file.open(QIODevice::ReadOnly))…

设计模式--抽象工厂模式

实验4&#xff1a;抽象工厂模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解抽象工厂模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用抽象工厂模式解决实际问题。 [实验任务]&#xff1a;人与肤色 使用抽象…

Netty—Reactor线程模型详解

文章目录 前言线程模型基本介绍线程模型分类Reactor线程模型介绍Netty线程模型&#xff1a; 传统阻塞IO的缺点Reactor线程模型单Reactor单线程模式单Reactor多线程模式主从Reactor多线程Reactor 模式小结 Netty 线程模型案例说明&#xff1a;Netty核心组件简介ChannelPipeline与…

服务运营 | 年终回顾:服务运营为您服务

文章作者&#xff1a;李舒湉&#xff0c;蔡君洋, Guo&#xff0c;陈盈鑫&#xff0c;王畅 编者按 在服务运营板块成立的第一年&#xff0c;给大家带来我们这一年中原创文章的年终回顾。迈向2024&#xff0c;服务运营继续为您服务 在服务运营板块成立的第一年&#xff0c;明确板…

预测块划分与亚像素精度:提升视频编码与图像处理的效率

在视频编码和图像处理中&#xff0c;预测块划分与亚像素精度是两项关键技术。本文将介绍预测块划分和亚像素精度的基本原理&#xff0c;探讨其在提高视频编码效率和图像处理精度方面的应用。 1. 预测块划分的基本原理 预测块划分是视频编码中的一项关键技术&#xff0c;它将图…

KCTF-Web-签到题

题目环境&#xff1a; 一道签到题 没有必要想那么麻烦 刚开始我以为是SQL注入 F12查源代码 在底部发现base64编码 进行base64解码ZmxhZ3t3ZTFjME1FX3RvXzB1Ul9jb050RVNUfQecho "ZmxhZ3t3ZTFjME1FX3RvXzB1Ul9jb050RVNUfQ" | base64 -d得到flag&#xff1a;flag{we1c0M…

spring状态机

1、概述 Spring State Machine 是一个用于处理状态机逻辑的框架&#xff0c;它提供了一种简洁的方法来定义状 态、转换以及在状态变更时触发的动作。 概念 状态 &#xff08; State &#xff09; &#xff1a;一个状态机至少要包含两个状态。例如自动门的例子&#xff0c;有 …

用芯片SIC8833可开发电子秤方案

SIC8833作为一款高性能的电子秤方案芯片&#xff0c;这款芯片是一个带24bitADC的8位RISC MCU&#xff0c;内置8k16位OTP程序存储器。具体24位双向I/O口的特性&#xff0c;广泛应用于电子衡器和精密测量及控制系统&#xff0c;能满足用户的不同需求和应用场景。 以下是电子秤方案…

盘古信息IMS-MOM制造运营管理系统,构建生产现场管理信息系统的最佳选择

在当今高度竞争的制造行业中&#xff0c;高效的生产管理是企业成功的关键。盘古信息IMS-MOM制造运营管理系统作为一款领先的管理系统其关键特性为制造企业构建生产现场管理信息系统提供了强大的优势。IMS-MOM不仅仅是一个软件系统&#xff0c;更是一种技术和管理手段的结合&…

【SQL经典题目】连续日期判断、同时在线人数、会话划分、间隔日期连续、日期交叉

【1.查询至少连续3天下单的用户】 思路1&#xff08;使用lead&#xff09;&#xff1a; distinct user_id,create_date去重&#xff0c;确保每个用户每天只有一条访问记录lead(create_date,2,‘9999-12-31’) over(partition by user_id order by create_date)根据用户分区&am…

力扣刷题记录(19)LeetCode:279、139

279. 完全平方数 这题和上篇文章的题类似&#xff0c;直接上代码 class Solution { public:int numSquares(int n) {vector<int> dp(n1,INT_MAX);dp[0]0;//j表示背包容量&#xff0c;dp[j]表示和为n的完全平方数的最少数量for(int i0;i*i<n;i){for(int ji*i;j<n;j…
最新文章