最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

练习项目20:使用python制作游戏(中)

Python教程 小楼一夜听春语 4030浏览 0评论

上一篇教程,我们通过实现一个敌机由上至下的循环过程,初步了解了pygame这个模块的使用。

接下来,我们进行第二阶段,真正的实现一个通过鼠标控制的小游戏。

因为内容量相对前面的教程来说比较大,我们把第二阶段再分成两个部分来实现。

  • 第一部分:实现配置文件和游戏对象模块;
  • 第二部分:实现游戏主程序部分。

一、配置文件(config.ini)

在配置文件中,我们需要作如下配置:

  • 游戏图片:图片的名称
  • 游戏窗口:宽、高、背景色(红\蓝\绿)、边缘填充、是否全屏、字体尺寸
  • 游戏速度:落下速度(敌方)、移动速度(己方)、速度增量(敌方)
  • 游戏关卡:敌机数量
  • 飞机实体:顶部、侧边

说明:飞机实体设置,是用于对己方飞机rect特性尺寸的调整,详见Plane类的代码。

配置文件内容:

[Image]
plane = images/plane.png
enemy = images/enemy.png
welcome = images/welcome.png

[Screen]
width = 360
height = 640
red = 255
blue = 255
green = 255
margin = 5
full_screen = 0
font_size = 24

[Speed]
drop_speed = 1
move_speed = 2
speed_increase = 1

[Level]
pre_level = 5

[Plane_padding]
top = 15
side = 15

二、游戏对象模块(objects.py)

1、导入模块并解析配置文件

在这个模块的开始,我们需要先导入需要使用的其它模块,并且对配置文件进行解析,方便在游戏对象类中使用配置数据。

示例代码:

import configparser  # 导入配置文件解析模块
import pygame
from random import randrange

file = 'config.ini'  # 配置文件路径
config = configparser.ConfigParser()  # 创建解析器对象
config.read(file, encoding='UTF-8')  # 读取并解析配置文件

2、创建抽象类

在游戏对象模块中,我们只需要创建Enemy(敌方飞机)和Plane(己方飞机)两个游戏对象类。

不过,在这两个类中,会有很多相同的代码。

我们可以把这些代码抽取出来,单独写成一个类。

示例代码:

class GameSprite(pygame.sprite.Sprite):  # 定义游戏对象的抽象类
    def __init__(self, image):  # 定义构造方法(需要添加图片参数)
        pygame.sprite.Sprite.__init__(self)  # 重载超类的构造方法
        self.image = pygame.image.load(image).convert_alpha()  # 创建image特性存储Surface对象
        self.rect = self.image.get_rect()  # 通过image创建rect特性
        screen = pygame.display.get_surface()  # 获取屏幕外观
        shrink = -config.getint('Screen', 'margin')  # 获取配置文件数值
        self.area = screen.get_rect().inflate(shrink, shrink)  # 获取屏幕外观填充后的区域(飞机的活动区域)

3、创建敌方飞机对象类

敌方飞机我们要考虑以下内容,包括:

  • 加载后的初始位置;
  • 每次移出屏幕下方后重置的位置;
  • 每一帧刷新后位置(受速度影响);
  • 每一帧刷新时,判断敌方飞机是否从完全移出屏幕下边缘。

示例代码:

class Enemy(GameSprite):  # 定义敌方飞机对象类
    def __init__(self, speed):  # 定义构造方法(需要添加速度参数)
        GameSprite.__init__(self, config.get('Image', 'enemy'))  # 重载超类构造方法(参数中传入图片)
        self.speed = speed  # 为敌方飞机设置速度特性
        self.reset()  # 重置敌方飞机位置

    def reset(self): # 定义重置位置的方法
        x = randrange(self.area.left, self.area.right) # 从活动范围中获取x轴的随机位置
        self.rect.midbottom = x, 0 # 设置游戏对象底部中心位置

    def update(self): # 定义刷新位置的方法
        self.rect.top += self.speed # 设置每帧向下移动的距离
        self.landed = self.rect.top >= self.area.bottom # 获取敌机是否已从屏幕下方完全移出

4、创建己方飞机对象类

己方飞机我们要考虑以下内容,包括:

  • 垂直方向的初始位置;
  • 水平方向可移动范围;
  • 每一帧刷新后的位置(受鼠标指针位置和屏幕可活动区域影响);
  • 触碰到敌方飞机的处理。

示例代码:

class Plane(GameSprite):  # 定义己方飞机对象类
    def __init__(self):  # 定义构造方法
        GameSprite.__init__(self, config.get('Image', 'plane'))  # 重载超类构造方法(参数中传入图片)
        self.rect.bottom = self.area.bottom  # 设置游戏对象垂直方向底部初始位置在屏幕底部
        self.pad_top = config.getint('Plane_padding', 'top')  # 获取配置文件中游戏对象顶部填充数值
        self.pad_side = config.getint('Plane_padding', 'side')  # 获取配置文件中游戏对象两侧填充数值

    def update(self):  # 定义刷新位置的方法
        self.rect.centerx = pygame.mouse.get_pos()[0]  # 设置游戏对象水平中心位置为鼠标指针的x轴位置
        self.rect = self.rect.clamp(self.area)  # 设置游戏对象水平方向可活动区域为屏幕外观填充后的区域

    def touches(self, other):  # 设置触碰到其它游戏对象的方法
        bounds = self.rect.inflate(-self.pad_side, -self.pad_top)  # 获取游戏对象填充后的边界范围(顶部与两侧)
        bounds.bottom = self.rect.bottom  # 设置边界范围的底部为游戏对象的底部
        return bounds.colliderect(other.rect)  # 返回游戏对象边界是否触碰到其它游戏对象

在完成以上内容之后,我们就可以着手主程序模块的编写了。

在编写之前,我们先预先了解一下整个程序的结构。

我们已经完成了整个程序左侧的部分,在下一篇教程中,我们一起完成右侧的部分。

在这里,我们先对右侧部分内容做一些整体上的理解,这样在编写代码的时候才能有一个清晰的逻辑。

1、State类。

在游戏中有两个状态,我们来看一下状态的类型和产生,分别是:

  • 暂停状态:进入游戏、进入关卡以及游戏结束时。
  • 运行状态:游戏进行时。

2、Level类。

这个类是运行状态,主要是对关卡的处理,包括控制游戏的速度、创建游戏对象、判断游戏结束或者进入下一关以及关卡屏幕的显示方案等。

3、Paused类。

在游戏中会有多个暂停状态,包括:

  • 打开游戏时;
  • 显示信息时;
  • 游戏过关时;
  • 游戏结束时。

每一个暂停的状态,都可以点击继续,都要显示背景颜色、图片以及文字。

所以,我们在Paused类中将多个暂停状态共有的内容进行抽象处理。

4、Paused类的子类。

Paused类的子类包含以下几个:

  • Infol类:游戏信息
  • StartUp类:打开游戏
  • LevelCleared类:游戏过关
  • GameOver类:游戏结束

这些子类只需要定义显示的图片以及文字内容,或者其它独有的功能。

5、Game类。

进行游戏初始化以及定义游戏运行的方法。

综上所述,在游戏主程序模块中,代码的结构如下所示。

示例代码:(planegame.py)

import pygame, sys
from pygame.locals import *
import objects  # 导入游戏对象模块
import configparser

file = 'config.ini'
config = configparser.ConfigParser()
config.read(file, encoding='UTF-8')

class State:
    """泛型游戏状态类,可以处理事件和屏幕显示。"""

    def handle(self, event):
        """处理退出事件。"""
        pass

    def paused_display(self, screen):
        """暂停时显示。"""
        pass

    def display(self, screen):
        """关卡中显示。"""
        pass

class Level(State):
    """游戏等级,用于计算共有多少敌机落下,移动游戏对象以及其他与游戏相关的逻辑任务。"""

    def __init__(self, number=1):
        """初始化关卡的等级和游戏对象。"""
        pass

    def update(self, game):
        """关卡运行,并进行游戏结束或通过关卡的处理。"""
        pass

    def display(self, screen):
        """关卡运行时的屏幕显示。"""
        pass

class Paused(State):
    """暂停游戏的状态,按任意键或点击鼠标退出暂停状态。"""

    def handle(self, event):
        """处理按任意键继续游戏。"""
        pass

    def update(self, game):
        """按任意键时进入下一个游戏状态。"""
        pass

    def paused_display(self, screen):
        """暂停时显示。"""
        pass

class Info(Paused):
    """游戏信息。"""
    pass

class StartUp(Paused):
    """进入游戏。"""
    pass

class LevelCleared(Paused):
    """游戏过关。"""

    def __init__(self, number):
        """过关信息。"""
        pass

    def next_state(self):
        """创建下一关卡。"""
        pass

class GameOver(Paused):
    """游戏结束。"""
    pass

class Game:
    """负责主事件循环的游戏对象,完成在不同状态间切换的任务。"""

    def __init__(self):
        """初始化。"""
        pass

    def run(self):
        """运行游戏。"""
        pass

if __name__ == '__main__':
    game = Game()
    game.run()

本节练习源代码:【点此下载

 

转载请注明:魔力Python » 练习项目20:使用python制作游戏(中)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)