上一篇实现并演示了A Star寻路算法以及增强了其通用性(可用于不同size的精灵寻路),本文将基于上文,实现一个金塔守护的小游戏。
首先,少不了定义敌人和守护者。敌人和守护者有很多的共同特性,都有精灵的基本属性,还包含会自己找路,自己的战斗力和防御能力等。另外一点是所有精灵在抵达目的地的过程中都可能经历8个不同的方向的路径,需要展示精灵各个方向的行走动画。首先来说一下pygame动画通常使用的两种方式。
方式一是将每一个方向的没一个动作单独用一个图片,这些图片按照一定的规则进行编号,然后在运动的过程中根据方向和动作选择相应的图片来展示。方式二是使用 spritesheet,将所有的动画图片按照规律放在一个spritesheet上,运动过程中选择加载相应的子画面来实现。另外两种方式都需要在守护者遇到敌人时展示战斗动画。
这两种方式都是可以的,方式一的话零散的图片太多,管理起来比较麻烦一点,方式二相对来说比较一个精灵只需要一个spritesheet就可以,相对来说管理起来容易一点。但对于程序实现来说复杂度没有什么区别。本文采用spritesheet方式来实现。
比如下面是一个精灵的所有图片,放在一起组成一个spritesheet。一共九行,前八行是各个方向的行走帧,最后一行是战斗帧集。本文只是一个演示,好的素材能展现更细腻的效果。
下面是一个敌人的spritesheet素材。
既然敌人和守护者有很多的共同属性,那么先定义个基类。
class AllSprite(Sprite):
def __init__(self, shPath, spType, position, *groups):
self._layer = SP_DATA[spType]['LAYER']
super().__init__(*groups)
self.sheet = pygame.image.load(shPath + SP_DATA[spType]['IMAGE']).convert_alpha()
self.shRows = SP_DATA[spType]['ROWS']
self.shCols = SP_DATA[spType]['COLS']
self.attack = SP_DATA[spType]['ATTACK']
self.defence = SP_DATA[spType]['DEFENCE']
self.speed = SP_DATA[spType]['SPD']
self.speedupFactor = SP_DATA[spType]['SPD_FACTOR']
# 能观察多远距离,用于自由巡逻
self.visibility = SP_DATA[spType]['RANGE']
# 缺省图像。 在运动过程中根据运动路线、方向更新
self.rect = Rect(position[0] * GRID_WIDTH,
position[1] * GRID_HEIGHT,
self.sheet.get_size()[0] // self.shCols,
self.sheet.get_size()[1] // self.shRows)
self.image = self.sheet.subsurface(0, 0, self.rect.width, self.rect.height)
# 下面是与计算路径相关的属性。
# 该精灵的size,取最大边长计算
self.size = max(self.rect.height // GRID_HEIGHT, self.rect.width // GRID_WIDTH)
self.path = []
self.direction = []
self.target = None
self.currentPathNo = 0
# 下面是与行走时显示动作相关的属性,rowIndex/colIndex 分别记录subsurface在图像中的位置索引
self.rowIndex = 0
self.colIndex = 0
# 冲突检测定时
self.lastTick = COLLIDE_CHECK_INT
# 设置精灵状态
self.status = IDLE
SP_DATA 常量用来配置相关精灵的参数,放在配置文件中。大致如下:
ENEMY_TYPE = {
1:'ZOMBIE', 2: 'MONSTER'}
HERO_TYPE = {
11: 'SOLIDER', 12: 'RIDER'}
SP_DATA = {
'ZOMBIE': {
'IMAGE': "hunter.png", 'ROWS': 9, 'COLS': 8, 'ATTACK': 10, 'DEFENCE': 800, 'SPD': 2, 'SPD_FACTOR': 1, 'LAYER': 40, 'RANGE': 6},
'MONSTER': {
'IMAGE': "monster.png",'ROWS': 9, 'COLS': 8, 'ATTACK': 10, 'DEFENCE': 800, 'SPD': 2, 'SPD_FACTOR': 1, 'LAYER': 40, 'RANGE': 6},
'SOLIDER': {
'IMAGE': "farm.png", 'ROWS': 9, 'COLS': 8, 'ATTACK': 100, 'DEFENCE': 8000, 'SPD': 4, 'SPD_FACTOR': 1, 'LAYER': 50, 'RANGE': 8},
'RIDER': {
'IMAGE': "knight.png", 'ROWS': 9, 'COLS': 8, 'ATTACK': 100, 'DEFENCE': 9999, 'SPD': 4, 'SPD_FACTOR': 1, 'LAYER': 50, 'RANGE': 10}
}
分别给出敌人的类型集,英雄的类型集,用于演示,都只使用两种类型。
精灵在运动过程中的八个方向相关定义:
SOUTH = (0, (0, 1))
SOUTHEAST = (1, (0.7, 0.7))
EAST = (2, (1, 0))
NORTHEAST = (3, (0.7, -0.7))
NORTH = (4, (0, -1))
NORTHWEST = (5, (-0.7, -0.7))
WEST = (6, (-1, 0))
SOUTHWEST = (7, (-0.7, 0.7))
每个方向后面跟着一个元组,用于简化计算精灵行在该方向走一次时对水平和垂直方向的偏移度。偏移度*速度就是位移了,用于更新精灵的位置。注意,方向定义元组的第一个值与精灵的spritesheet是对应的。
下面完成精灵的寻路功能以及运动过程中的动画更新。
def init_path_info(self):
self