游戏数值系统

前言

游戏的各个子系统中充斥着各种不同的数值,比如:玩家金钱、等级、在线时长等,而这些数值又会跟其他的子系统有一些关联,比如任务、成就、榜单等,因此数值系统是非常重要的模块之一.

数值类型

玩家在体验游戏的过程当中,无非就是对不同的数值进行了修改,比如杀死了某个怪物之后获得了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.moneyuser.leveluser.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);
        }

        // 原先代码
    }
}

结束语

由于篇幅问题今天就先到这里了,数值系统的基础部分基本已经完成,以上代码均为同步代码仅作为参考并非实际项目中的代码,下周我会在此基础上加入奖励模块,配合奖励模块简化复合类型的更新,或者加入数值对象模块,比如英雄、宠物等对象在数值系统中的设计,如果有任何疑问或者错误欢迎指出,谢谢.

文章原始地址: https://my.oschina.net/ahl5esoft/blog/4301907

原文地址:https://www.cnblogs.com/ahl5esoft/p/13054234.html