战斗系统的模型构建思考
战斗系统是一个游戏的玩法核心,也是游戏之间差别最大的地方,想要建立可复用的模型,可谓困难最大。但是,游戏的玩法本身也是有分类和传承的。需要特别注意的是,作为服务器端程序,战斗系统的职责是有多种不同层级的:
记录战斗结果,发放战斗奖励。很多开房间和按“局”算的游戏,如棋牌类,其游戏本身是分为很多“局”的。游戏是在一局结束后,才结算所有的奖励。另外如《地下城与勇士》(DNF),其游戏为一个个地下城“副本”,本身也是这种分局的。如果服务器端只是为了游戏完成一局后做“结算”,那么其逻辑还是比较简单的:主要就是校验游戏中的消耗与产出是否合理,有无作弊嫌疑,然后更具战斗数据,发放战斗奖励给玩家。这种模型下其实无需很复杂的模型,无论任何的玩法,实际上都可以用一个“校验与奖励”函数作为抽象即可。如果战斗过程中有消耗品使用或者奖励掉落,还要增加一个消耗品函数和奖励掉落函数即可。
在二维游戏场景下,对战斗过程进行模拟,且时常会结合帧同步广播来协调游戏。例子就如著名的《英雄联盟》。这一类战斗服务器,往往会作为“主广播器”,生成AI的行为,转发广播玩家的动作,同时计算每个战斗动作的“成败输赢”。这种做法其实和一个客户端计算战斗过程是差别不大的。这种战斗服务器的抽象模型是由几个部分组成:AI控制+状态广播+战斗判定。每一个战斗“帧”,服务器都会更新所有玩家、怪物的状态,然后判定战斗结果,最后广播状态和战斗情况给客户端。这种模型是相对比较复杂的,其最复杂的地方在于处理AI和判定战斗结果的时候,必须在内存中根据二维的战场状况,重现整个游戏情况。这对于一般来说不显示画面的服务器端程序来说,是比较复杂的。
在三维游戏场景下,对战斗过程的模拟和广播协调。很多FPS游戏都是这种,而著名的WOW也是这一类例子。其实这个模型和上面第2种情况是类似的,只不过3维空间的计算复杂程度比二维更高。
基于上面所说,一个战斗系统确实是游戏中最复杂的部分,因此我们的建模也不能很轻易简单的完成,而是应该分为几个不同的层次和阶段。第一个层次对应最简单的战斗结果校验和奖励模型:
在这里,我们使用“战斗关卡”这个模型来抽象战斗内容,“奖励对象”只是一个用于抽象可能存在的不同奖励内容的接口。一般来说我们的奖励是物品道具、货币,但是也有可能会有更复杂的内容,比如开通某种特殊权限,完成某个任务等等。这些复杂的“战斗奖励”也许不是一个RPG的物品基类能涵盖的。所以不如以组合的形式来耦合关卡奖励和具体的物品。由于战斗关卡的数据项目一般很少,所以就不列举数据属性的设计,而专门关注关键行为的模型:
战斗关卡
根据ID从持久化数据中构建关卡
返回战斗关卡的介绍,应该返回一个游戏自定义的介绍数据结构。
输入所有进入玩家对象,开始一局关卡游戏。有可能开始一局游戏会扣减某些玩家资源和检查是否能开始游戏。
输入玩家对象,计算关卡中掉落物品
输入玩家对象,计算关卡中消耗物品
判断关卡是否结束。根据战斗关卡的数据来判断是否应该结束关卡。
输入所有当前玩家对象,进行关卡结束的计算,返回关卡的奖励。此操作会计算游戏过程中的掉落物品和消耗物品。
关卡奖励
输入玩家对象,执行奖励(虚函数)
在第二个层次中,战斗系统的模型会变的复杂很多,其中有一块是关于AI模块的。关于AI的模型本文恐怕无法简单完成,因此可以把他看成是一个黑盒子。当然AI简单的用一个状态机实现也可以。在这种情况下,战斗的标准流程是:按帧接受玩家操作,AI产生怪物/NPC操作,计算战斗结果,更新战场状态,广播战场状况。因此模型大致如下:
在这个模型下,战斗主要执行逻辑对象,是由“帧同步广播器”来执行的,当然也有可能游戏不是帧同步模型的,但是无论如何都会有一个战斗驱动器来循环的调度战斗进行。如果这个战斗驱动器是帧同步或定时器的,那么游戏就会是实时游戏,如果这个战斗驱动器是由玩家命令触发(可能带超时触发)的,那么游戏可能会是回合制的。不过归根结底,战斗系统都是一个“战斗判定”循环,只是这个循环的定时器的快慢差别,以及是否能由玩家主动暂停或加速的差别。因此以上对象的主要行为应该包括:
战斗驱动器(此处是“帧同步广播器)
驱动帧(虚函数)函数:此函数可以由各种不同的情况触发,如定时器、玩家命令等。负责执行具体的战斗计算状况。
战场状态集。有时候关卡的战斗状态和这个对象是同一个对象。
获得战场状态:包括所有战场上角色对象及其2D、3D坐标
输入目标角色与技能范围,返回是否命中。(辅助函数,根据2D/3D的差别,会有很多不同的模型,如射线命中判断用于FPS)
AI模块。AI模块可能包含复杂的状态机模型,但只有一个驱动函数而已。
输入游戏角色对象,执行其AI结果操作。(虚函数)
关于战斗驱动器的几种模型下表有一个分类:
关于战斗动作,在2维和3维下略有不同(同理,如果有1维的游戏也是一样的),但是仅仅是参数的区别。实际上,针对特定类型的游戏玩法,比如FPS或者MOBA&RTS类型,这里的战斗动作都具备相当高的可复用可能。这些动作的内容各有不同,但是其“动作”的主要行为是:
判断——是否碰撞(命中),返回碰撞对象
动作——修改发出动作对象以及碰撞对象状态
对于纯数值类型游戏,其实就相当于0维空间游戏,战斗动作的判断实际上返回的对象由动作本身确定,无需空间计算。这在很多RPG或者策略类游戏中是很常见的。
最后总结一下战斗系统的完整流程,在有些游戏中,关卡和战斗是配合一起操作的,但是有些游戏则没有关卡,只有战斗,不过这种游戏主要是世界地图的MMORPG,现在这类游戏已经渐渐式微了:
尽管战斗系统是如此的复杂和多变,但是其运作还是一个模拟状态变化的系统,所以还是有不同层次的可重用模型可以设计。核心的战斗驱动就是模拟时间因数,而战斗动作则负责对空间因数进行模拟。关卡系统是对战斗的一个时空区隔,也是各种奖励、消耗的小结,因此更常见于游戏当中。