手机网游
手机网游
休闲娱乐
模拟经营
赛车驾驶
冒险解谜
恋爱养成
策略塔防
战争对抗
体育竞速
卡牌对阵
VR游戏
3D手游
武侠修仙
动作闯关
射击枪战
音乐舞蹈
横板格斗
双人游戏
换装游戏
橙光游戏
其他游戏
传奇手游
安卓软件
安卓软件
主题壁纸
购物优惠
资讯阅读
健康美食
地图出行
影音播放
教育学习
游戏辅助
摄影摄像
其他软件
金融理财
言情小说
生活服务
电竞赛事
通讯社交
系统工具
效率办公
安卓游戏
安卓游戏
益智休闲
动作冒险
网络游戏
模拟经营
儿童教育
体育竞速
策略塔防
冒险解谜
角色扮演
音乐游戏
飞行射击
赛车游戏
破解游戏
传奇手游
其他游戏
攻略资讯
攻略资讯
游戏资讯
游戏攻略
游戏问答
软件教程
合集
合集
教程合集
游戏合集
软件合集
文章合集
首页 > 攻略资讯 > 游戏资讯

类魔兽世界moba技能系统的数值结构设计

编辑:啊妹 2017-11-02

类似魔兽世界,moba这种技能极其复杂,灵活性要求极高的技能系统,必须需要一套及其灵活的数值结构来搭配。数值结构设计好了,实现技能系统就会非常简单,否则就是一场灾难。

比如魔兽世界,一个人物的数值属性非常之多,移动速度,力量,怒气,能量,集中值,魔法值,血量,最大血量,物理攻击,物理防御,法术攻击,法术防御,等等多达几十种之多。属性跟属性之间又相互影响,buff又会给属性增加绝对值,增加百分比,或者某种buff又会在算完所有的增加值之后再来给你翻个倍。

普通的做法:

一般就是写个数值类:

class Numeric

{

public int Hp;

public int MaxHp;

public int Speed;

// 能量

public int Energy;

public int MaxEnergy;

// 魔法

public int Mp;

public int MaxMp;

.....

}

仔细一想,我一个盗贼使用的是能量,为什么要有一个Mp的值?我一个法师使用的是魔法为什么要有能量的字段?纠结这个搞毛,当作没看见不就行了吗?实在不行,我来个继承?

// 法师数值

calss MageNumeric: Numeric

{

// 魔法

public int Mp;

public int MaxMp;

}

// 盗贼数值

calss RougeNumeric: Numeric

{

// 能量

public int Energy;

public int MaxEnergy;

}

10个种族,每个种族7,8种英雄,光这些数值类继承关系,你就得懵逼了吧。面向对象是难以适应这种灵活的复杂的需求的。

再来看看Numeric类,每种数值可不能只设计一个字段,比如说,我有个buff会增加10点Speed,还有种buff增加50%的speed,那我至少还得加三个二级属性字段

class Numeric

{

// 速度最终值

public int Speed;

// 速度初始值

public int SpeedInit;

// 速度增加值

public int SpeedAdd;

// 速度增加百分比值

public int SpeedPct;

}

SpeedAdd跟SpeedPct改变后,进行一次计算,就可以算出最终的速度值。buff只需要去修改SpeedAdd跟SpeedPct就行了。

Speed=(SpeedInit SpeedAdd)*(1 SpeedPct)/100

每种属性都可能有好几种间接影响值,可以想想这个类是多么庞大,初略估计得有100多个字段。麻烦的是计算公式基本一样,但是就是无法统一成一个函数,例如MaxHp,也有buff影响

class Numeric

{

public int Speed;

public int SpeedInit;

public int SpeedAdd;

public int SpeedPct;

public int MaxHp;

public int MaxHpInit;

public int MaxHpAdd;

public int MaxHpPct;

}

也得写个Hp的计算公式

MaxHp=(MaxHpInit MaxHpAdd) * (1 MaxHpPct) / 100

几十种属性,就要写几十遍,并且每个二级属性改变都要正确调用对应的公式计算. 非常麻烦!

这样设计还有个很大的问题,buff配置表填对应的属性字段不是很好填,例如疾跑buff(增加速度50%),在buff表中怎么配置才能让程序简单的找到并操作SpeedPct字段呢?不好搞。

ET框架采用了Key Value形式保存数值属性

using System.Collections.Generic;

namespace Model

{

public enum NumericType

{

Max = 10000,

Speed = 1000,

SpeedBase = Speed * 10 1,

SpeedAdd = Speed * 10 2,

SpeedPct = Speed * 10 3,

SpeedFinalAdd = Speed * 10 4,

SpeedFinalPct = Speed * 10 5,

Hp = 1001,

HpBase = Hp * 10 1,

MaxHp = 1002,

MaxHpBase = MaxHp * 10 1,

MaxHpAdd = MaxHp * 10 2,

MaxHpPct = MaxHp * 10 3,

MaxHpFinalAdd = MaxHp * 10 4,

MaxHpFinalPct = MaxHp * 10 5,

}

public class NumericComponent: Component

{

public readonly Dictionary NumericDic = new Dictionary();

public void Awake()

{

// 这里初始化base值

}

public float GetAsFloat(NumericType numericType)

{

return (float)GetByKey((int)numericType) / 10000;

}

public int GetAsInt(NumericType numericType)

{

return GetByKey((int)numericType);

}

public void Set(NumericType nt, float value)

{

this[nt] = (int) (value * 10000);

}

public void Set(NumericType nt, int value)

{

this[nt] = value;

}

public int this[NumericType numericType]

{

get

{

return this.GetByKey((int) numericType);

}

set

{

int v = this.GetByKey((int) numericType);

if (v == value)

{

return;

}

NumericDic[(int)numericType] = value;

Update(numericType);

}

}

private int GetByKey(int key)

{

int value = 0;

this.NumericDic.TryGetValue(key, out value);

return value;

}

public void Update(NumericType numericType)

{

if (numericType > NumericType.Max)

{

return;

}

int final = (int) numericType / 10;

int bas = final * 10 1;

int add = final * 10 2;

int pct = final * 10 3;

int finalAdd = final * 10 4;

int finalPct = final * 10 5;

// 一个数值可能会多种情况影响,比如速度,加个buff可能增加速度绝对值100,也有些buff增加10%速度,所以一个值可以由5个值进行控制其最终结果

// final = (((base add) * (100 pct) / 100) finalAdd) * (100 finalPct) / 100;

this.NumericDic[final] = ((this.GetByKey(bas) this.GetByKey(add)) * (100 this.GetByKey(pct)) / 100 this.GetByKey(finalAdd)) * (100 this.GetByKey(finalPct)) / 100;

Game.Scene.GetComponent().Run(EventIdType.NumbericChange, this.Entity.Id, numericType, final);

}

}

}

1.数值都用key value来保存,key是数值的类型,由NumericType来定义,value都是整数,float型也可以转成整数,例如乘以1000;key value保存属性会变得非常灵活,例如法师没有能量属性,那么初始化法师对象不加能量的key value就好了。盗贼没有法力值,没有法术伤害等等,初始化就不用加这些。

2.魔兽世界中,一个数值由5个值来影响,可以统一使用一条公式:

final = (((base add) * (100 pct) / 100) finalAdd) * (100 finalPct) / 100;

比如说速度值speed,有个初始值speedbase,有个buff1增加10点绝对速度,那么buff1创建的时候会给speedadd加10,buff1删除的时候给speedadd减10,buff2增加20%的速度,那么buff2创建的时候给speedpct加20,buff2删除的时候给speedpct减20.甚至可能有buff3,会在最终值上再加100%,那么buff3将影响speedfinalpct。这5个值发生改变,统一使用Update函数就可以重新计算对应的属性了。buff配置中对应数值字段相当简单,buff配置中填上相应的NumericType,程序很轻松就能操作对应的数值。

3.属性的改变可以统一抛出事件给其它模块订阅,写一个属性变化监视器变得非常简单。例如成就模块需要开发一个成就生命值超过1000,会获得长寿大师的成就。那么开发成就模块的人将订阅HP的变化:

/// 监视hp数值变化

[NumericWatcher(NumericType.Hp)]

public class NumericWatcher_Hp : INumericWatcher

{

public void Run(long id, int value)

{

if (value > 1000)

{

//获得成就长寿大师成就

}

}

}

同理,记录一次金币变化大于10000的异常日志等等都可以这样做。

有了这个数值组件,一个moba技能系统可以说已经完成了一半。


免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

良心推荐

nfc可以应用于各种场景,而有些人不知道如何下载nfc软件,今天乖乖小编在这里为大家带来了各种类型的手机nfc读写工具,无论是模拟门禁卡、公交卡,还是银行卡,都可以直接读取到手机中,只用携带手机就可以了,再也不用带各种卡片在身上了,极大了方便了我们的生活。

相关资讯