游戏实体的属性模型

在游戏中,每个实体有各种各样的属性和状态,受外界或自身影响而不断改变,例如动作游戏中玩家控制的角色有移动速度、生命值、攻击力等属性和眩晕、硬直、减速等状态,控制的角色有属性这点比较好理解,但真的只有在场景中存在的实体才有属性和状态吗?卡牌游戏中每回合抽牌的数量是“卡组”的属性,射击游戏中的枪械后坐力是“枪械”的属性,自走棋游戏中的刷新棋子概率是“商店”的属性,同样他们也有状态,例如枪械没有子弹了就陷入“空弹”状态,无法射击。如果有一个统一的属性模型能套用在多种不同的事物上那会给拓展和使用带来极大的便利。

我认为用于一个描述一个事物的属性模型应该具有以下特点:

· 可序列化

· 属性修改的稳定性

· 使用方便

可序列化的意义是能够方便地存储和克隆,在进行存档和读档时因其可序列化能很方便地记录和还原数据,在克隆物体时只需要持有一份序列化数据即可,不需要已有实例。

属性修改的稳定性的意义是正确的修改属性,在排序算法中有排序的稳定性一说,稳定的排序意味着元素的相对次序保持不变,属性修改的稳定性与之有些类似,意味着属性修改无论顺序如何结果应该一样。

必须先提一点,那就是属性修改的基数分为两种,初始值和当前值,一个简单的例子,单位最初有100点攻击力,buffA效果为增加100%攻击力,若基数为初始值,这意味着叠加1次为200、2次为300、3次为400,线性递增,容易控制。若基数为当前值则意味着叠加1次为200、2次为400、3次为800,指数递增,这会导致恐怖的数值膨胀,当然这并不一定是坏事,有的养成游戏为了达到凸显成长会故意这么做,但这种设计通常难以驾驭,所以大多数游戏中的大多数属性修改都是基于初始值的,但既然只是大多数也就意味着两者的共存几乎是必然的,而让两者共存则需要优先级来辅助计算。例如英雄联盟中狐狸的魅惑技能会导致对方的移动速度固定变为200,无论怎么加速都没用,这是因为魅惑导致的移动速度修改优先级最高,最后计算。

若没有优先级,不同的修改顺序会导致不同的结果,举个例子:单位初始攻击力为100点,buffA效果为增加100%攻击力(基数为当前值),buffB效果为增加100点攻击力,先加A后加B的结果为300,先加B后加A的结果为400。若预期是顺序不应改变结果那么就需要让A的优先级高于B,A后于B计算,这样无论是先A后B还是先B后A结果都是400。

使用方便的意义不必多说,标准就是使用起来和简单将属性作为字段存储到类中一样,能做到实例.MaxHp、实例.Attack来进行访问。

属性模型在程序中有3个类:

模型:PropertyModel

修改信息:PropertyModifyInfo

序列化类:PropertyModelSerializable

PropertyModifyInfo是属性修改信息类,修改信息包括发起修改的对象、修改的计算值、修改类型、修改优先级。每次外部修改某对象属性时传入的是修改信息而非直接对其属性进行修改,在获取对象某属性时通过存储的修改信息计算并返回最终值。

IPropertyModel是属性模型的抽象接口。每个PropertyModel用一个字典存储所有属性,内部使用GetProp和SetProp访问和修改字典中的属性值,用一个字段存储所有属性的修改信息,外部用DoModify和UndoModify来记录和删除修改信息,使用GetProp访问值时根据参数决定返回的属性为字典中的初始值或是计算后的最终值,通过记录修改信息而不是直接修改值,并用优先级进行辅助计算得到的结果不会被调用顺序所影响。

内部添加属性值时同时添加相同键的修改信息:

获取值时若获取初始值则直接返回字典中的属性值,若为当前值则将该属性的修改信息根据优先级进行排序而后计算得到最终值:

PropertyModelSerializable为序列化模型类,包含类名和所有属性的信息。存储每条属性使用一个序列化属性类,包含属性名和属性值信息。

每种类型对象的序列化模型名字规范为当前类名+Serializable,在序列化模型对象时实例化一个对应的序列化对象,然后将类名和所有属性设置进去:

反序列化一个属性模型时将序列化的属性一一设置进字典中:

为了达到使用方便的目的,将每条属性封装成字段进行使用。

例如最大生命值,在模型内部使用MAX_HP作为键记录初始属性值,外部使用BaseMaxHp访问和设置初始值,使用MaxHp获取当前值:

最后简单提一下模型状态的实现思路,因为自己的项目只有简单的状态需求所以该方案可能无法应对复杂的需求。

使用一个字典存储状态信息,状态名作为键,一个存储对象的哈希表作为值:

采用计数的方式来判断是否处于某状态:

添加状态很好理解,但移除状态有两个方法,一个是用于发起者移除自己添加的状态(RemoveState),例如某buff开始时添加眩晕状态,buff结束时移除眩晕状态,为了不移除别人添加的眩晕状态需要传入发起者对象,还有一个是用于清除某状态(ClearState),例如某buff有净化效果,移除所有减速效果,那么不需要理会发起者是谁直接清空减速状态的值即可:

上述的属性模型的例子都是针对角色单位的,但其实任何可能有属性改变的东西都可以套用,比如我的项目中商店就使用了属性模型,商店等级就是其中一条属性,当我拿到某个强化时会给商店添加1个提升等级的buff,当我移除该强化时则会移除此buff,buff被移除时执行的清理逻辑为移除自己添加的属性修改信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值