外星人入侵:使用Python开发游戏(一)——模块介绍

本文介绍了如何使用Pygame工具包开发一款2D射击游戏,玩家控制飞船消灭移动的外星人。随着游戏进程,难度和节奏逐渐提升。关键模块包括设置、飞船、外星人、子弹、统计信息和记分牌的实现,以及事件检测和响应。游戏界面设计简洁,逻辑清晰,代码复用性强。
摘要由CSDN通过智能技术生成

游戏介绍:

使用Pygame工具包开发一款2D游戏,玩家控制飞船消灭一群向下移动的外星人,每消灭一群外星人,游戏难度提高一个等级,节奏加快。

内容

本文聚焦于游戏主体模块的设计和实现,暂不考虑交互过程。

框架设计

1.安装Pygame工具包(Window系统):

conda install Pygame -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

2.模块设计

主模块:alien_invasion.py

  • 搭建游戏界面窗口
  • 循环检测并响应事件
  • 刷新游戏界面内容

辅助模块:

  • 存储整个游戏相关参数:settings.py

  • 存储游戏相关函数:game_functions.py

  • 飞船类:ship.py

  • 外星人类:alien.py

  • 子弹类:bullets.py

  • 游戏统计信息类:game_stats.py

  • 记分牌类:score_board.py

  • 按钮类:button.py

代码实现

主模块的逻辑比较简单且清晰,基本上就是-“搭界面-检测事件-响应-更新界面”。
gf.check_events()、ship.update()、gf.update_bullets()、gf.update_aliens()四个重点方法会放在交互部分介绍(game_functions.py)
alien_invasion.py

import pygame
from pygame.sprite import Group

from settings import Settings
import game_functions as gf
from ship import Ship
from bullet import Bullet
from alien import Alien
#-------------暂时不用管-----------------
from game_stats import GameStats
from button import Button
from scoreboard import Scoreboard

def run_game():
    '''初始化游戏并创建一个屏幕对象'''
    #-----------------搭建游戏界面窗口 ------------------
    #初始化pygame,设置屏幕对象
    pygame.init()#初始化背景
    ai_settings = Settings()#读取settings中的游戏设置
    screen = pygame.display.set_mode((
        ai_settings.screen_width,ai_settings.screen_height
    ))#设置游戏界面大小
	pygame.display.set_caption(ai_settings.caption_name)#显示界面标题
	
	#初始化游戏元素 	#创建一艘飞船
    ship = Ship(ai_settings,screen)
    #创建一个用于存储子弹的编组,以便能够管理所有发射出去的子弹
    bullets = Group()
    #创建一个外星人编组
    aliens = Group()
    #创建外星人群
    gf.create_fleet(ai_settings,screen,ship,aliens) 

	#-----------------循环检测并响应事件  ----------------
	while True:
		##检查用户输入并响应
		gf.check_events(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets)
        if stats.game_active:#stats.game_active标记游戏处于运行状态,本文暂未涉及,可理解为TRUE即可
        	#更新游戏元素的位置参数
            #更新飞船位置
            ship.update()
            #更新子弹位置
            gf.update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets)
            #更新外星人的位置
            gf.update_aliens(ai_settings,screen,stats,sb,ship,aliens,bullets)
        #刷新游戏界面,显示更新后的元素位置
       	#-----------------刷新游戏界面内容  ----------------       	
       	gf.update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button)

if __name__ == "__main__":      
 	#运行游戏 
    run_game()        

------------------下面先来看一下辅助模块部分--------------------
settings.py中的内容:
所有的游戏设置都存储在该文件中,包括了游戏的界面窗口属性、子弹属性、外星人和飞船的部分属性(其他属性在对应的模板类中存储),同时该某块实现了两个方法:1.对可变参数的初始化;2.对可变参数的更新

settings.py

class Settings():
    '''存储《外星人入侵》的所有设置的类'''

    def __init__(self):
        '''初始化游戏的设置'''
        #静态设置---游戏设置分为两组
        #游戏界面设置
        self.screen_width = 1200#宽
        self.screen_height = 600#高
        self.bg_color = (220,220,220)#背景色
        self.caption_name = 'Alien Invasion'

        #飞船的设置
        # self.ship_speed_factor = 1.5
        self.ship_limit = 3#可用飞船数

        #子弹设置
        # self.bullet_speed_factor = 1
        self.bullet_width = 3#子弹宽
        self.bullet_height = 15#子弹高
        self.bullet_color = (60,60,60)#子弹颜色
        self.bullets_allowed = 5#允许在界面中显示的子弹数量,限制用户发射子弹数量

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

        #游戏过程中的动态设置
        #以什么样的速度加快游戏节奏
        self.speed_up_scale = 1.1
        #击杀外星人点数的提高速度
        self.score_scale = 1.5
      
        self.initialize_dynamic_setting()#一些随游戏变动的参数的初始化
        
    def initialize_dynamic_setting(self):
        '''初始化随游戏进行而变化的设置'''
        self.ship_speed_factor = 1.5#飞船移动初始速度
        self.bullet_speed_factor = 3#子弹移动初始速度
        self.alien_speed_factor = 1 #外星人移动初始速度

        self.fleet_direction = 1#外星人移动方向标记,+1向右移动,-1向左移动
        #每个外星人被击杀计分
        self.alien_points = 50
          
    def increase_speed(self):
        '''难度提升:提高速度的设置和外星人点数'''
        self.ship_speed_factor *= self.speed_up_scale#飞船移动速度
        self.bullet_speed_factor *= self.speed_up_scale#子弹移动速度
        self.alien_speed_factor *= self.speed_up_scale #外星人移动速度
        self.alien_points = int(self.alien_points * self.score_scale)#难度提升,外星人点数得分也增加

接下来看一下飞船类ship.py的实现:
内容-加载飞船图像,返回关于飞船的pygame.Rect对象,包含了绘制飞船的方法,移动方向的调整和飞船位置的重置。
ship.py

import pygame
from pygame.sprite import Sprite

class Ship(Sprite):
    '''飞船类,用于管理飞船的大部分行为'''

    def __init__(self,ai_settings,screen):
        '''初始化飞船并设置其初始位置'''
        super().__init__()
        self.screen = screen#要绘制的屏幕
        self.ai_settings = ai_settings#Settings类的实例

        #加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images\ship.bmp')#返回飞船的surface
        self.rect = self.image.get_rect()#得到飞船图片的矩形 rect对象
        self.screen_rect = screen.get_rect()#得到屏幕的矩形
        
        #将飞船放在屏幕底部中间
        #!!!坐标值:界面窗口的左上角为(0,0),向右、下都是坐标值都是逐渐增大
        self.rect.centerx = self.screen_rect.centerx#屏幕矩形的中间坐标值
        self.rect.bottom = self.screen_rect.bottom#屏幕底部的坐标值

        #在飞船的属性center中存储小数
        self.center = float(self.rect.centerx)#rect.centerx只能存储整数
        self.bottom = float(self.rect.bottom)
        #移动标志,True表示向相应的方向移动
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False

    def blitme(self):
        '''在指定的位置绘制飞船'''
        self.screen.blit(self.image,self.rect)#在屏幕上绘制内容,参数为:绘制的内容+位置参数

    def update(self):
        '''根据移动标志调整飞船位置'''
        if self.moving_right and self.rect.right < self.screen_rect.right:#检查是否超出屏幕范围(右边界)
            # self.rect.centerx +=1
            self.center += self.ai_settings.ship_speed_factor
        # elif self.moving_left:#这里不用elif: 若用elif则右移始终处于优先事件,在按住左键不动时按右键仍然可以右移动,但反过来就不能左移!!!重要!!!
        if self.moving_left and self.rect.left > 0:  #此时两个左右按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(左边界)
            # self.rect.centerx -=1
            self.center -= self.ai_settings.ship_speed_factor
        
        if self.moving_up and self.bottom > self.rect.height:  #此时上下两个按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(上边界)
            # self.rect.centerx -=1
            self.bottom -= self.ai_settings.ship_speed_factor
        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:  #此时两个按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(下边界)
            # self.rect.centerx -=1
            self.bottom += self.ai_settings.ship_speed_factor
        
        #根据self.center,bottom 跟新rect对象的坐标值
        self.rect.centerx = self.center
        self.rect.bottom = self.bottom
    
    def center_ship(self):
        '''把飞船放到屏幕底部中间'''
        self.rect.centerx = self.screen_rect.centerx#屏幕矩形的中间坐标值
        self.rect.bottom = self.screen_rect.bottom#屏幕底部的坐标值
        #移动的累计值也要清零!
        self.center = float(self.rect.centerx)#rect.centerx只能存储整数
        self.bottom = float(self.rect.bottom)

然后是关于外星人alien.py的类:
内容:初始化加载外星人图像,返回关于外星人的pygame.Rect对象,包含了绘制外星人,检测是否达到屏幕边界,更新外星人坐标三个方法。
alien.py

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    '''表示单个外星人的类'''
    
    def __init__(self,ai_settings,screen):
        '''初始化外星人并设置其起始位置'''
        super().__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        #加载外星人图像,并设置其rect属性
        self.image = pygame.image.load(r'images\alien.bmp')#r消除转义功能
        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)
    
    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

    def update(self):
        '''向左/右移动外星人'''
        # self.x += self.ai_settings.alien_speed_factor
        self.x += (self.ai_settings.alien_speed_factor*self.ai_settings.fleet_direction)#fleet_direction表示移动的方向+1向右,-1向左
        self.rect.x = self.x

关于子弹bullets.py的类:
内容——初始化一个子弹对象并设置其位置,,包含位置更新和绘制子弹两个方法
bullets.py

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    '''一个对飞船发射的子弹进行管理的类'''

    def __init__(self,ai_settings,screen,ship):
        '''在飞船所处的位置创建一个子弹对象'''
        super().__init__()#继承Sprite,可将游戏中相关元素编组,进而同时对所有的编组元素进行操作
        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#飞船中间的x坐标
        self.rect.top = ship.rect.top#飞船上边界y坐标

        #用小数存储子弹的位置 子弹运动过程中X坐标值不会改变,y会不断减小
        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
        self.rect.y = self.y #更新子弹的位置

    def draw_bullet(self):
        '''在屏幕上绘制子弹'''
        pygame.draw.rect(self.screen,self.color,self.rect)

游戏统计信息类game_stats.py:
内容——记录可用的飞船数量,游戏得分,和累计的游戏最高得分
game_stats.py

# from settings import Settings
class GameStats():
    '''跟踪游戏中的统计信息'''

    def __init__(self,ai_settings):
        ''''初始化统计信息'''
        self.ai_settings = ai_settings
        self.reset_stats()
        # self.game_active = True#标记游戏是否要结束
        self.game_active = False#先设置为非活跃状态,由用点击开始游戏
        #在任何情况下都不应重置最高得分
        # self.high_score = 0#记录游戏最高得分,不会随游戏重置而更新
        #从记录中读取游戏最高分
        try:
            with open('recode_high_score.txt','r') as f:
                content = f.readline().strip()
                if content:
                    self.high_score = int(content)
                else:
                    self.high_score = 0
        except FileNotFoundError:
            self.high_score = 0
        
    def reset_stats(self):
        '''初始化再游戏运行期间可能变化的统计信息'''
        self.ships_left = self.ai_settings.ship_limit#可用的飞船数目,初始为3
        self.score = 0#记录游戏得分
        self.level = 1

记分牌类scoreboard.py:
内容——用于在屏幕中显示当前得分,游戏最高分,等级,剩余飞船数。主要包含了 self.prep_score()、self.prep_high_score()、self.prep_level()、self.prep_ships()四个将文本/数据渲染成图像的方法,然后可以用show_score()进行图像绘制。
scoreboard.py

import pygame.font#用于在屏幕上显示文本
from pygame.sprite import Group

from ship import Ship

class Scoreboard():
    '''显示得分信息得类'''
    def __init__(self,ai_settings,screen,stats):
        '''初始化按钮的属性'''
        self.screen = screen
        self.screen_rect = screen.get_rect()

        self.ai_settings = ai_settings
        self.stats = stats
        #设置得分信息得字体设置
        self.text_color = (50,50,50)
        self.font = pygame.font.SysFont(None,48)

        #创建初始得分图像
        self.prep_score()#将要显示的文本渲染成图片来显示
        self.prep_high_score()
        self.prep_level()
        self.prep_ships()#创建飞船图像

    def prep_score(self):
        '''将得分转换为一副渲染的图像'''
        # score_str = str(self.stats.score)
        #将得分圆整
        rounded_score = int(round(self.stats.score,-1))#round(number,-1)使得number圆整到最近得10得整数倍
        score_str = "score:{:,}".format(rounded_score)#使用千位分隔符输出1,000,000
        self.score_image = self.font.render(score_str,True,self.text_color,self.ai_settings.bg_color)

        #将得分放置在屏幕右上角
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = 20

    def prep_high_score(self):
        '''将最高分渲染为图像'''
        high_score = int(round(self.stats.high_score,-1))#round(number,-1)使得number圆整到最近得10得整数倍
        high_score_str = "High_score:{:,}".format(high_score)#使用千位分隔符输出1,000,000
        self.high_score_image = self.font.render(high_score_str,True,self.text_color,self.ai_settings.bg_color)

        #将最高得分放置在屏幕顶部中间
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.centerx = self.screen_rect.centerx
        self.high_score_rect.top = self.score_rect.top

    def prep_level(self):
        '''将等级渲染为图像'''
        self.level_image = self.font.render('Level:'+str(self.stats.level),True,self.text_color,self.ai_settings.bg_color)

        #将最高得分放置在屏幕顶部中间
        self.level_image_rect = self.high_score_image.get_rect()
        self.level_image_rect.right = self.score_rect.right
        self.level_image_rect.top = self.score_rect.bottom + 10
    
    def prep_ships(self):
        '''将飞船数目转化为飞船图像'''
        self.ships = Group()

        for ship_number in range(self.stats.ships_left):
            ship = Ship(self.ai_settings,self.screen)
            ship.rect.x = 10 +ship_number*ship.rect.width
            ship.rect.y = 10
            self.ships.add(ship)

    def show_score(self):
        '''在屏幕上显示得分'''
        self.screen.blit(self.score_image,self.score_rect)
        self.screen.blit(self.high_score_image,self.high_score_rect)
        self.screen.blit(self.level_image,self.level_image_rect)
        self.ships.draw(self.screen)#绘制编组中得每一艘飞船

按钮类button.py:
内容——初始化按钮对象,将要显示的文本渲染成图像prep_msg()并可调用draw_button()方法进行绘制。
button.py

import pygame.font#将文本渲染到屏幕上。

class Button():
    '''按钮类'''

    def __init__(self,ai_settings,screen,msg):
        '''初始化按钮的属性'''
        self.screen = screen
        self.screen_rect = screen.get_rect()

        #设置按钮的尺寸和其他属性
        self.width,self.height = 200,50
        self.button_color = (0,255,0)
        self.text_color = (255,255,255)
        self.font = pygame.font.SysFont(None,48)

        #创建按钮对象,并使其居中
        self.rect = pygame.Rect(0,0,self.width,self.height)
        self.rect.center = self.screen_rect.center

        #按钮的标签只需创建一次
        self.prep_msg(msg)#将要显示的文本渲染成图片来显示
    
    def prep_msg(self,msg):
        '''将msg渲染成图像,并使其在按钮上居中'''
        self.msg_image = self.font.render(msg,True,self.text_color,self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center
    
    def draw_button(self):
        '''绘制按钮和文本'''
        self.screen.fill(self.button_color,self.rect)#绘制按钮矩形
        self.screen.blit(self.msg_image,self.msg_image_rect)#绘制文本图像

项目小结:
1.尽量将要设置的参数存放到一个地方去,如setting.py,以便于修改和维护;
2.先实现逻辑,再不断对代码重构,实现代码复用。尽量让一个函数只做一件事;
3.函数的命名要能突出其作用/功能。

附上一个游戏界面截图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值