游戏物品系统通用架构
source link: http://www.luzexi.com/2013/12/31/%E6%B8%B8%E6%88%8F%E7%89%A9%E5%93%81%E7%B3%BB%E7%BB%9F%E9%80%9A%E7%94%A8%E6%9E%B6%E6%9E%84
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
游戏物品系统通用架构
游戏物品系统通用架构,物品系统是游戏中最最常用的功能之一,面对各种纷繁复杂的游戏物品系统,在具体项目中如何顺手拈来、驾驭自如?请容我一一到来。在内容前我有必要说明几点,所有内容都是基于我最大的架构思想之下,其中 客户端U3D架构思想的文章地址为 Unity3D游戏架构 ,以及服务器架构:《王图霸业》战争策略游戏服务器架构。
首先,我们先归纳一下物品的基本属性。 物品基本属性:名字,描述,数量,最大可叠加数,图标 装备物品扩展属性:装备位置,攻击力,防御力,暴击率,魔力,血量,等等 消耗物品扩展属性:BUFF增加,HP增加,最大HP增加,等等
在游戏项目中,把这些物品的扩展属性,单个提取出来组合成各种游戏中需要的物品,如何做到?
1.把所有属性都写进物品数据配置表中?数据表过大,导致最终项目人员更改数据缓慢,错误不断,甚至连写此系统的程序员自己也吃不消。
2.把每个物品都按单各类进行特殊处理?假设物品有100种,那程序员就得写100各类实例,每增加一个写一个,浪费人力浪费时间。
3.以物品基类的继承的形式,将各种物品分类处理,归类,派生?繁琐,分类时间过长,效率过低,程序员最终会为物品该归到哪一类和策划人员而打起来。
如何才能做到物品系统适应不同的游戏需要,又能使得物品配置方便扩展性强?在这里我引入一个Action概念,Action以动作的概念来理解。当物品使用时,就调用不同的Action来达到不同的效果,例如:加血100加魔法200的物品,点击后,该物品执行加血100的Action实例,接着执行加魔200的实例,完毕后我们就能看到我们需要的效果了。所以物品只需要对应N各Action就可以完全做到你想做的,甚至可以做到你想不到的。
我们能发现,其实物品的很多功能是可以用不同单个功能组合起来的,比如加血,比如加魔,比如加BUFF状态,把这些相同功能的Action都做成一个,然后把不同的Action做成一个集合是多么完美的事,既达到了数据持续化存储和更新能力,又可使得物品功能完全由策划人员自行配置,发挥他们的无限想象力。
现在来看看实际中Action是如何编写的。把加血动作写成 类ActionAddHp,类中参数一个:HP,把加魔法动作写成 类ActionAddMP,类中参数一个:MP,这两个Action从数据表中读取相应的参数数据,变成众多Action实例里的一个,由ActionManager管理存储。到此回头看看,所有继承自Action类的扩展类拥有几个共同的属性:ID(唯一标识,用来区分所有Action),RunType(用来区分不同类型的Action),Read接口(用来读取数据),Excute接口(用来执行Action)。我在此之上加上一个Action类型,把所有Action拆分为条件类Action和执行类Action,条件类Action主要用来判断该物品的使用条件是否满足,执行类Action主要用来执行该动作的效果。因此Action基类就成了这样:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// CAction.cs
// Author: Lu Zexi
// 2013-12-24
//base action
public abstract class CAction : IAction
{
private int m_iID; //id
// id (0-99999) , actionType(0-99) , runType(0-99)
public CAction(int id, int actionType, int runType)
{
this.m_iID = actionType*10000000 + runType*100000 + id;
}
public abstract ActionError Excute(ActionInput input);
//roll back action
public virtual ActionError RollBack(ActionInput input)
{
return ActionError.NoError;
}
//get id
public int ID
{
get
{
return this.m_iID;
}
}
}
有人会问,那如何让物品对应好几个Action呢?我再引入一个Action事件类,把它定义为类EventAction,他里面存储着16个Action ID,前8个ActionID是条件型动作,后8个ActionID为执行型动作。物品的数据中就有一个EventAction的ID,由这个EventAction来判断该执行那些Action,是否满足物品执行条件。当EventAction执行时,首先执行前8个Action,看看是否满足物品执行条件,如果不满足,则不执行后8个效果,如果满足再去执行后8个Action效果。因此EventAction也有很多各实例,由ID来区分不同的EventAction,由EventActionManager来管理所有事件Action。EventAction类结构:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// EventAction.cs
// Author: Lu zexi
// 2013-12-24
/// <summary>
/// Action event
/// </summary>
public class EventAction
{
private int m_iID; //ID
private int[] m_vecActions; //Action ID list
private int[] m_vecReqActions; //Require Action ID list
public EventAction()
{
this.m_vecActions = new int[8];
this.m_vecReqActions = new int[8];
}
// id (0-99999) , actionType(0-99) , runType(0-99)
public EventAction( int id , int eventType , int runType)
{
this.m_iID = eventType * 10000000 + runType*100000 + id;
}
//get id
public int ID
{
get
{
return this.m_iID;
}
}
//set action
public void SetAction( int[] act )
{
this.m_vecActions = act;
}
//set require
public void SetRequire( int[] req )
{
this.m_vecReqActions = req;
}
//excute action
public ActionError Excute( ActionInput input )
{
for (int i = 0; i < this.m_vecActions.Length; i++)
{
CAction action = ActionManager.sInstance.GetAction(this.m_vecActions[i]);
if (action != null)
{
ActionError error = action.Excute(input);
if ( error != null && error.code != ACTION_ERROR_CODE.NONE)
return error;
}
}
return ActionError.NoError;
}
//action require
public ActionError Require( ActionInput input)
{
for (int i = 0; i < this.m_vecReqActions.Length; i++)
{
CAction action = ActionManager.sInstance.GetAction(this.m_vecReqActions[i]);
if (action != null)
{
ActionError error = action.Excute(input);
if ( error != null && error.code != ACTION_ERROR_CODE.NONE)
return error;
}
}
return ActionError.NoError;
}
//action roll back
public ActionError RollBack(ActionInput input)
{
for (int i = 0; i < this.m_vecActions.Length; i++)
{
CAction action = ActionManager.sInstance.GetAction(this.m_vecActions[i]);
if (action != null)
{
ActionError error = action.RollBack(input);
if (error != null && error.code != ACTION_ERROR_CODE.NONE)
return error;
}
}
return ActionError.NoError;
}
}
以上描述解决了物品中消耗品的问题,物品素材本身就是没有功能的消耗品,在这里我就不介绍了。而下面,我们来看看如何解决物品装备。 装备物品在消耗品上多了几样关于英雄角色的属性,这些属性有的明,有的暗,那我们就把那些明的属性提取出来,例如加增攻击力,增加防御力。而那些暗的属性,再拆分两种,一种是直接写进明的配置表中而不显示在界面上,另一个是直接写进动作Action里,当需要时执行相应EventAction实例。
最后,我们看看整个物品系统数据配置和系统源码。
物品类:名字,物品类型(消耗品,装备,素材),描述,数量,最大叠加数量,使用等级,EventActionID,装备位置,攻击力,防御力,HP,MP
Action表: ID , 描述 , ActionType , RunType , 参数1,参数2...
EventAction表: ID,描述,
ReqActionID1,ReqActionID2,...ReqActionID8,
ActionID9,ActionID10,...ActionID16.
源码:https://github.com/luzexi/Unity3DItemSystem
测试案例:https://github.com/luzexi/Unity3DItemSystem-Test
转载请注明出处:http://www.luzexi.com
December 31, 2013 · Unity3D, 游戏架构, 游戏通用模块感谢您的耐心阅读
Thanks for your reading
版权申明
本文为博主原创文章,未经允许不得转载:
Copyright attention
Please don't reprint without authorize.
微信公众号,文章同步推送,致力于分享一个资深程序员在北上广深拼搏中对世界的理解
QQ交流群: 777859752 (高级程序书友会)
Recommend
-
42
-
16
用粉碎机粉碎100件物品,莫名的看到停不下来
-
39
新华社南京10月27日电(记者王珏玢)近年来随着“天猫”“ 京东 ”等多种网购平台的兴起,已有越来越多人加入网络购物的大军。但各种由网购滋生的骗局也不断翻新。江苏无锡警方提醒,近期已出现多起假客服打着甲醛超标旗号声...
-
47
京东 - @wisdom - 双十一在京东买了个电子产品拆包发现是二手的打客服电话升级专员专员直接说发个新的旧的不要了瞬间无语,有钱就是任性
-
44
-
66
【猎云网(微信:)北京】7月11日报道 7月11日,滴滴公众评议会推出第七期,邀请社会各界聚焦滴滴网约车将新增的“遗失物品送回”功能...
-
10
日本防疫物品大赏!霓虹人民试图用魔法打败病毒?!网友:看着有用,但有种奇怪的感觉… 日本设计 时间:2021-01-22 10:3...
-
8
NFT 的核心精神是数字物品的物理化,而非原子物品的上链(图:中国加密艺术家宋婷作品,部分。图片来源于网络) 正文之前,先说说盘面。比特币从 8 号站上 4 万刀随后开始转熊,到现在已经大半个月了,一度失守 3 万刀。DeFi 板块仍呈现结构性上涨...
-
3
Offline Recommend(离线层) 作用:对海量数据进行离线加工 工具:Hadoop/Spark Nearline Recommend(近线层) 作用:利用流式处理技术对实时产生的数据进行加工 工具:Storm/Spark
-
4
复杂业务系统的通用架构设计法则 皮亮 2023-06-09 09:43:35 ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK