zoukankan      html  css  js  c++  java
  • 游戏数值系统

    前言

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

    数值类型

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

  • 相关阅读:
    B1009
    (OK)(OK) [android-x86-6.0-rc1] compile_Android-x86_64_in_IBM-X3650-M4.txt
    Fortran, Matlab, Octave, Scilab计算速度比较
    GNU Octave
    [android-x86-6.0-rc1] /system/etc/init.sh
    [android-x86-6.0-rc1] /system/xbin/log.sh
    Android源码学习之接着浅析SystemServer
    Android源码学习之浅析SystemServer脉络
    Android-x86_64
    Android-x86_64
  • 原文地址:https://www.cnblogs.com/ahl5esoft/p/13054234.html
Copyright © 2011-2022 走看看