游戏数值系统 - 基础功能实现
前言
游戏的各个子系统中充斥着各种不同的数值,比如:玩家金钱、等级、在线时长等,而这些数值又会跟其他的子系统有一些关联,比如任务、成就、榜单等,因此数值系统是非常重要的模块之一.
数值类型
玩家在体验游戏的过程当中,无非就是对不同的数值进行了修改,比如杀死了某个怪物之后获得了xx点经验、对某个英雄进行升级等,我们将这些数值统称数值类型,比如上面提到的金钱、等级、在线时长、经验等,这些数值集合用一个枚举来表示,代码如下:
menu ValueType {
Money,
Level,
OnlineTime
}
基础数值类型
所谓基础数值类型就是它的使用只会对本身产生影响,比如使用金钱进行的各类操作都只是金钱发生了变化,通过金钱的变化来改变其他的数值.
复杂数值类型
从字面上可以理解到这种数值类型其实是其他数值的集合,比如钱袋(使用之后会获得一定数量的金钱)、礼包(使用之后会获得N种其他的数值类型).
基础数值类型更新
我们先从一个简单的业务场景来讲解,比如1级升级到2级需要10元, 该业务中涉及了2个不同的数值类型的变化,伪代码如下:
user.money -= 10;
user.level += 1;
此时需求变化了,策划要求可以使用所有的钱进行升级,多出来的部分要转化成经验,假设玩家身上有15元,伪代码如下:
user.money -= 15;
user.level += 1;
user.exp += 5;
我们将以上的代码重构一下,将user.money
、user.level
、user.exp
提取到一个集合中,每种数值都是独立的元素,这样可以灵活扩展,将相关业务抽象化到一个通用的方法中,代码如下:
class ValueEntry {
public valueType: number;
public count: number;
}
class User {
private m_ValueTypeOfEntry: { [key: number]: ValueEntry } = {};
public update(...valueEntries: ValueEntry[]): void {
for (const r of valueEntries) {
let oldEntry = this.m_ValueTypeOfEntry[r.valueType];
if (!oldEntry) {
oldEntry = {
valueType: r.valueType,
count: 0,
};
this.m_ValueTypeOfEntry[r.valueType] = oldEntry;
}
oldEntry.count += r.count;
}
}
}
此时策划又有了新的需求,如果数值类型小于0的情况下,得报错,那么只需要对User.update扩展一下便可满足需求了,此处就不再给出代码了.
复合数值类型更新
由于复合数值类型的变更会对其他数值类型发生变化,其次就是在整个游戏的开发过程当中,复合类型会不断的增加,如果像上面那样频繁的对User.update进行修改,显然是不符合OCP的,因此我们应该再次对User.update进行扩展来支持复合数值类型的更新.
首先我们分析一下流程,当复合数值类型变化时会产出其他的简单数值类型,然后更新,因此我们应该在原先的代码之前加入拦截器,该拦截器的作用就是在更新m_ValueTypeOfEntry之前先把复合类型产出的简单类型添加到参数集合中,假设需求为使用每个钱包可以获得1000元,相关代码如下:
type InterceptAction = (valueEntry: ValueEntry, reduceValueEntries: ValueEntry[]) => void;
function walletIntercept(valueEntry: ValueEntry, reduceValueEntries: ValueEntry[]): void {
if (valueEntry.count >= 0) {
return;
}
valueEntries.push({
valueType: ValueType.Money,
count: Math.abs(valueEntry.count) * 1000,
});
}
class User {
public update(...valueEntries: ValueEntry[]): void {
let reduceValueEntries: ValueEntry[] = [];
for (const r of valueEntries) {
const interceptAction = InterceptorFactory.build(r.valueType);
if (interceptAction) {
interceptAction(r, reduceValueEntries);
}
}
if (reduceValueEntries.length) {
this.update(...reduceValueEntries);
}
// 原先代码
}
}
结束语
由于篇幅问题今天就先到这里了,数值系统的基础部分基本已经完成,以上代码均为同步代码仅作为参考并非实际项目中的代码,下周我会在此基础上加入奖励模块,配合奖励模块简化复合类型的更新,或者加入数值对象模块,比如英雄、宠物等对象在数值系统中的设计,如果有任何疑问或者错误欢迎指出,谢谢.