道具系统设计
2. 道具的设计
不好意思,自从《前言》之后,隔了这个么多天,第二篇文章才跟上。上次有朋友反映,微云的连接数太少了,小弟翻看了记录,貌似35次就上限了,不解,更新了,但是作为后备,所以上传至Dropbox上,不知道能不能下载。 下面是Dropbox的连接:
如果微云再次爆满,请联系小弟,小弟会尽快修复的,或者大家有没有豪气点的平台推荐下哈。
好了,言归正传,我们正式开始道具系统的设计,第一部分将会是核心系统(code)的设计部分,这个部分将会分成2个部分,道具和道具管理器。顾名思义,所以不多解释了。我们马上开始道具的设计。
首先,打开你的unity,然后使用现有的或新建工程,然后在Project中,新建一个C#脚本,重命名为:Item_Profile。
在正式编码之前,我们需要了解我们的需求,我们需要设计出什么样子的道具,道具的种类,道具之间的共享属性等等,一般的做法是,设计一个父类,然后根据不同的道具种类需求,然后派生出不同的道具出来,例如Item下派生出Weapon,Armor,Bomb等等,然后你会发现,你会派生出N多个类出来。而作为独立制作人,我们(请允许我加入你们的队伍里)的通常的做法是,边设计,边编码,然后再设计,再编码,所以,在实际开发中,你会发现,需求在不断的变化,如果真的派生出这么多类出来,肯定要疯掉了,所以,小弟的设计是,将所有属性写在同一个类中,然后根据实际需求,来选择性读写某些属性。这两种做法各有优略,而单一类最大的优势就是,懒!
好了,说了半天,其实就是懒,OK。现在打开刚才的新建的 Item_Profile 文件,然后开始编码。- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
-
- [System.Serializable]
- public class Item_Profile : MonoBehaviour
- {
- }
复制代码 作为道具的一员,之间肯定有某些共同的元素,例如名字,买卖价格,稀有程度等等。所以,我们首先要设计的是这些共同的元素。
item_id ID,这个ID有系统自动分配,所以不需要对齐作出设计,保留为public,只是为了方便查看而已。
icon 2D图标。
comment 道具的描述。
type 道具类型,武器或护甲之类的。
rare 稀有度。
color 颜色,关联稀有度,白色到紫色之类的可视化等级。[size=13.63636302948px]
buy,sell 买卖价格。
limit_stack 堆栈上线,例如20个一组的面包,或且无法叠加的武器或护甲。
model 3D模型。- #region common
- // ********* common values ************//
- // public string name = "";
- public int item_id = -1; // this id assigned by item database manager
-
- //public string item_name; // use the gameobject's name as well
- public Texture2D icon;
- public string comment;
-
- public enum TYPE
- {
- None,
- Weapon,
- Shield,
- Armor,
- Recipe,
- Parts,
- Consumables,
- Bomb
- } ;
- public TYPE type;
-
- public int rare = 1000; // the rare level
- public Color color = Color.white;
-
- public int buy,sell;
- public int limit_stack = 1; // maximun # of stack
-
- public GameObject model;
-
- #endregion
复制代码 然后就是武器属性的设计
weapon_type 武器的类型,单手剑或双手剑。
damage 攻击力,物理攻击或各种元素攻击。
damage_r 攻击力的波动范围。- #region weapon
- // ********* weapon values ************//
- public enum WEAPON_TYPE
- {
- None,
- Single_Sword
- } ;
- public WEAPON_TYPE weapon_type;
-
- public int damage;
- public int damage_r; // randomly range
-
- public int damage_metal;
- public int damage_metal_r;
-
- public int damage_wood;
- public int damage_wood_r;
-
- public int damage_water;
- public int damage_water_r;
-
- public int damage_fire;
- public int damage_fire_r;
-
- public int damage_earth;
- public int damage_earth_r;
-
- //////////////////////////////////////////
- #endregion
复制代码- 接着就是护盾和护驾的设计了,将他们放一起,是因为他们都属于防具,属性都一样。
- clan 种族,精灵或且兽人,如果装备有指定种族的话,这个属性能帮上忙。
- armor_type 护甲类型,头部,手部还是护盾。
- def 防御力,各种元素防御力。
- [C#] 纯文本查看 复制代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- #region shield & armor
- // ********* shield & armor values ************//
- // public Material armor_material;
-
- // only for armor
- public enum CLAN_TYPE
- {
- None,
- Elven,
- Orc
- } ;
- public CLAN_TYPE clan = CLAN_TYPE.Orc;
-
- // only for armor
- public enum ARMOR_TYPE
- {
- None,
- Chest,
- Head,
- Shoulder,
- Belt
- } ;
- public ARMOR_TYPE armor_type;
-
- public int def;
- public int def_metal;
- public int def_wood;
- public int def_water;
- public int def_fire;
- public int def_earth;
-
- //////////////////////////////////////////
- #endregion
- 主要的道具我们都已经设计好了,下面让我们来搞点新意。小弟就拿大家都比较感兴趣的合成配方这个部分来举例吧。
- parts 合成所需的道具及数量。这里可能大家会有个疑问,为什么不用item_id 而要使用 Item_Profile 来关联道具,这个问题在设计道具管理器的时候会有解释。
- final_product 终于的合成品。
- [C#] 纯文本查看 复制代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- #region recipe
- // ********* recipe values ************//
- [System.Serializable]
- public class Recipe_Parts
- {
- public Item_Profile part;
- public int number;
-
- } ;
- public Recipe_Parts[] parts;
- public Item_Profile final_product;
- //////////////////////////////////////////
- #endregion
- 好了,差不多了,大致设计的方向就是这样了,再说下去估计大家都要无聊死了,所以,大家可以根据自身的需求来修改或扩写此类。现在,大家伙应该是迫不及待的要看看目前的设计成果了,OK,去吧,比卡丘。
- 马上新建一个Empty GameObject,然后挂载Item_Profile,然后你会发现,OMG,Inspector各种凌乱,完全无法继续设计下去了,这就是单一类带给我们的快乐,当然,今天绝对不会是这样结束的,我们接着下来要做的就是,改变这这一切。现在,小弟假设大家都有对Editor编程有一定的了解,如果你不知道什么是Editor变成,请参考官网:http://unity3d.com/learn/tutorials/modules/beginner/editor。
- OK,新建一个C#脚本,并重命名为:Item_Profile_Editor。
-
- [C#] 纯文本查看 复制代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- // 这里是需要改变指定的类在Inspector中的布局,这里我们需要改变的类就是Item_Profile。
- [CustomEditor(typeof(Item_Profile))]
- public class Item_Profile_Editor : Editor
- {
-
- void OnEnable ()
- {
- }
-
- // 这个函数,看名字就觉得很NB,这个就是在编辑状态下,Inspector的GUI的布局。
- public override void OnInspectorGUI ()
- {
- // target是Editor里的一个属性,指的就是我们需要改变的那个类,这里做强转换,不解释。
- Item_Profile item = target as Item_Profile;
- // 序列化更新,不解释。
- serializedObject.Update();
-
- // Add your code here.
- // ……
-
- // 更新编辑后的数据。
- serializedObject.ApplyModifiedProperties();
-
- }
-
-
- }
- 这段代码可以说是Editor编程的固定格式,不做过多的解释了,反正直接复制过去就对了,哈哈哈哈。
- 如果编译成功,你可能会发现,Inspector什么都没有了,嗯,这就是成功的第一步了。
-
- 现在开始显示道具们的共同元素。
- [C#] 纯文本查看 复制代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- // ********* common values **********//
- item.item_id = EditorGUILayout.IntField("auto_id", item.item_id);
-
- item.icon = EditorGUILayout.ObjectField ("icon", item.icon, typeof(Texture2D)) as Texture2D;
- item.name = EditorGUILayout.TextField ("name", item.name);
-
- item.comment = EditorGUILayout.TextField("comment",item.comment);
-
- GUILayout.Space(5f);
- EditorGUILayout.PropertyField( serializedObject.FindProperty("type") );
- GUILayout.Space(5f);
- item.rare = EditorGUILayout.IntField("rare",item.rare);
- EditorGUILayout.PropertyField( serializedObject.FindProperty("color") );
- GUILayout.Space(5f);
-
- item.buy = EditorGUILayout.IntField("buy", item.buy);
- item.sell = EditorGUILayout.IntField("sell",item.sell);
-
- GUILayout.Space(5f);
- item.limit_stack = EditorGUILayout.IntField("limit stack", item.limit_stack);
-
- item.model = EditorGUILayout.ObjectField ("model", item.model, typeof(GameObject)) as GameObject;
- 这段代码没有什么可以解释的,我们就抽选几个作为举例吧。
- 简单数据类型的处理方法:
- item.item_id = EditorGUILayout.IntField("auto_id", item.item_id); // 显示并更新item.item_id, “auto_id”为在Inspector中显示的名称。
- 内置的对象的处理方法:
- item.icon = EditorGUILayout.ObjectField ("icon", item.icon, typeof(Texture2D)) as Texture2D;
- 对枚举类型的处理方法:
- EditorGUILayout.PropertyField(serializedObject.FindProperty(“type"));
- GUILayout函数是GUI的布局函数而已,不必太在意。
- 编译成功后,看看目前的成果吧。
-
-
- 成功的第二步,现在Type值的改变还会没有为我们带来什么实际上的效果,现在,要搞的就是这部分。
- [C++] 纯文本查看 复制代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- // ********* core values **********//
- GUILayout.Space(10f);
- if (NGUIEditorTools.DrawHeader("Info:"))
- {
- NGUIEditorTools.BeginContents();
- //GUILayout.BeginVertical();
-
-
- switch (item.type)
- {
- case Item_Profile.TYPE.Weapon:
- Show_Weapon(item);
- break;
-
- case Item_Profile.TYPE.Armor:
- case Item_Profile.TYPE.Shield:
- Show_Armor_Shield(item);
- break;
-
- case Item_Profile.TYPE.Recipe:
- Show_Recipe(item);
- break;
-
- case Item_Profile.TYPE.Parts:
- Show_Parts(item);
- break;
-
- case Item_Profile.TYPE.Consumables:
- break;
-
- case Item_Profile.TYPE.Bomb:
- break;
- }
-
- //GUILayout.EndVertical();
- NGUIEditorTools.EndContents();
- }
- 你会发现这里有几个是NGUI的函数,如果你还没有NGUI插件的话,可以忽略这些,这只是个布局函数而已,好了,如果真的没有NGUI的话,直接从switch语句开始就好了。
- 你会发现,switch的参数就是item.type, 猜对了,Inspector会根据type的值,来显示其余的属性。这里就不做过多的贴代码行为了,都是大同小异的,这里特别想贴出来的是,Show_Recipe(item)。
- [C#] 纯文本查看 复制代码
- 1
- 2
- 3
- 4
- 5
- void Show_Recipe(Item_Profile item)
- {
- EditorGUILayout.PropertyField( serializedObject.FindProperty("parts"), true );
- EditorGUILayout.PropertyField( serializedObject.FindProperty("final_product"), true );
- }
- 特别想指出的是,因为这里包含了一个自定义数据的处理方法:
- EditorGUILayout.PropertyField( serializedObject.FindProperty("parts"), true );
- 好了,编译通过后,你会发现,当你修改Type值的时候,后续的内容也会跟着改变,现在是不是编辑起来方便和许多。(单一类和众派生类的做法基本相同,不同的就是需要根据type的值,来改变target的转换类型而已。)
-
- 单有道具类还不够,我们需要有效的管理起成千上万的道具,下篇,我们将设计一个道具管理器,并将它设计成一个单一类,在整个游戏过程中,确保它是我们唯一能获取道具信息的唯一类,保证游戏进程中道具的信息统一。
复制代码- 作为后备,为了放置连接数爆满,所以这里贴出全部代码,必要时可自行复制。嘻嘻。
- [size=13.63636302948px]Item_Profile:
- [size=13.63636302948px]
- [C#] 纯文本查看 复制代码
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- [System.Serializable]
- public class Item_Profile : MonoBehaviour
- {
- #region common
- // ********* common values ************//
- // public string name = "";
- public int item_id = -1; // this id assigned by item database manager
- //public string item_name; // use the gameobject's name as well
- public Texture2D icon;
- public string comment;
- public enum TYPE
- {
- None,
- Weapon,
- Shield,
- Armor,
- Recipe,
- Parts,
- Consumables,
- Bomb
- };
- public TYPE type;
- public int rare = 1000; // the rare level
- public Color color = Color.white;
- public int buy,sell;
- public int limit_stack = 1; // maximun # of stack
- public GameObject model;
- #endregion
- //////////////////////////////////////////
- #region weapon
- // ********* weapon values ************//
-
- public enum WEAPON_TYPE
- {
- None,
- Single_Sword
- };
- public WEAPON_TYPE weapon_type;
- public int damage;
- public int damage_r; // randomly range
- public int damage_metal;
- public int damage_metal_r;
- public int damage_wood;
- public int damage_wood_r;
- public int damage_water;
- public int damage_water_r;
- public int damage_fire;
- public int damage_fire_r;
- public int damage_earth;
- public int damage_earth_r;
- //////////////////////////////////////////
- #endregion
- #region shield & armor
- // ********* shield & armor values ************//
- // public Material armor_material;
- // only for armor
- public enum CLAN_TYPE
- {
- None,
- Elven,
- Orc
- };
- public CLAN_TYPE clan = CLAN_TYPE.Orc;
- // only for armor
- public enum ARMOR_TYPE
- {
- None,
- Chest,
- Head,
- Shoulder,
- Belt
- };
- public ARMOR_TYPE armor_type;
- public int def;
- public int def_metal;
- public int def_wood;
- public int def_water;
- public int def_fire;
- public int def_earth;
- //////////////////////////////////////////
- #endregion
- #region recipe
- // ********* recipe values ************//
- [System.Serializable]
- public class Recipe_Parts
- {
- public Item_Profile part;
- public int number;
- };
- public Recipe_Parts[] parts;
- public Item_Profile final_product;
- //////////////////////////////////////////
- #endregion
- #region parts
- // ********* Parte values ************//
- //////////////////////////////////////////
- // ********* Consumables ************//
- //////////////////////////////////////////
- // ************* Bomb ************//
-
-
- //////////////////////////////////////////
- #endregion
- }
- [size=13.63636302948px]
- [size=13.63636302948px]Item_Profile_Editor:
- [size=13.63636302948px]
- [C#] 纯文本查看 复制代码
- using UnityEngine;
- using System.Collections;
- using UnityEditor;
- [CustomEditor(typeof(Item_Profile))]
- public class Item_Profile_Editor : Editor
- {
- void OnEnable ()
- {
- }
- public override void OnInspectorGUI ()
- {
- Item_Profile item = target as Item_Profile;
- serializedObject.Update();
- // ********* common values **********//
- item.item_id = EditorGUILayout.IntField("auto_id", item.item_id);
- item.icon = EditorGUILayout.ObjectField ("icon", item.icon, typeof(Texture2D)) as Texture2D;
- item.name = EditorGUILayout.TextField ("name", item.name);
- item.comment = EditorGUILayout.TextField("comment",item.comment);
- GUILayout.Space(5f);
- EditorGUILayout.PropertyField( serializedObject.FindProperty("type") );
- GUILayout.Space(5f);
- item.rare = EditorGUILayout.IntField("rare",item.rare);
- EditorGUILayout.PropertyField( serializedObject.FindProperty("color") );
- GUILayout.Space(5f);
- item.buy = EditorGUILayout.IntField("buy", item.buy);
- item.sell = EditorGUILayout.IntField("sell",item.sell);
- GUILayout.Space(5f);
- item.limit_stack = EditorGUILayout.IntField("limit stack", item.limit_stack);
- item.model = EditorGUILayout.ObjectField ("model", item.model, typeof(GameObject)) as GameObject;
- // ********* core values **********//
- GUILayout.Space(10f);
- if (NGUIEditorTools.DrawHeader("Info:"))
- {
- NGUIEditorTools.BeginContents();
- //GUILayout.BeginVertical();
- switch (item.type)
- {
- case Item_Profile.TYPE.Weapon:
- Show_Weapon(item);
- break;
- case Item_Profile.TYPE.Armor:
- case Item_Profile.TYPE.Shield:
- Show_Armor_Shield(item);
- break;
- case Item_Profile.TYPE.Recipe:
- Show_Recipe(item);
- break;
- case Item_Profile.TYPE.Parts:
- Show_Parts(item);
- break;
- case Item_Profile.TYPE.Consumables:
- break;
- case Item_Profile.TYPE.Bomb:
- break;
- }
- //GUILayout.EndVertical();
- NGUIEditorTools.EndContents();
- }
- serializedObject.ApplyModifiedProperties();
- }
- void Show_Weapon(Item_Profile item)
- {
- SerializedProperty weapon_type = serializedObject.FindProperty("weapon_type");
- EditorGUILayout.PropertyField( weapon_type );
- item.damage = EditorGUILayout.IntField("damage", item.damage);
- item.damage_r = EditorGUILayout.IntField("damage_r", item.damage_r);
- item.damage_metal = EditorGUILayout.IntField("metal", item.damage_metal);
- item.damage_metal_r = EditorGUILayout.IntField("metal_r", item.damage_metal_r);
- item.damage_wood = EditorGUILayout.IntField("wood", item.damage_wood);
- item.damage_wood_r = EditorGUILayout.IntField("wood_r", item.damage_wood_r);
- item.damage_water = EditorGUILayout.IntField("water", item.damage_water);
- item.damage_water_r = EditorGUILayout.IntField("water_r", item.damage_water_r);
- item.damage_fire = EditorGUILayout.IntField("fire", item.damage_fire);
- item.damage_fire_r = EditorGUILayout.IntField("fire_r", item.damage_fire_r);
- item.damage_earth = EditorGUILayout.IntField("earth", item.damage_earth);
- item.damage_earth_r = EditorGUILayout.IntField("earth_r", item.damage_earth);
- }
- void Show_Armor_Shield(Item_Profile item)
- {
- //item.armor_material = EditorGUILayout.ObjectField ("armor_material", item.armor_material, typeof(Material)) as Material;
- if (item.type == Item_Profile.TYPE.Armor)
- {
- SerializedProperty armor_type = serializedObject.FindProperty("armor_type");
- EditorGUILayout.PropertyField( armor_type );
- SerializedProperty clan = serializedObject.FindProperty("clan");
- EditorGUILayout.PropertyField( clan );
- }
- item.def = EditorGUILayout.IntField("def",item.def);
- item.def_metal = EditorGUILayout.IntField("metal",item.def_metal);
- item.def_wood = EditorGUILayout.IntField("wood",item.def_wood);
- item.def_water = EditorGUILayout.IntField("water",item.def_water);
- item.def_fire = EditorGUILayout.IntField("fire",item.def_fire);
- item.def_earth = EditorGUILayout.IntField("earth",item.def_earth);
- }
- void Show_Recipe(Item_Profile item)
- {
- EditorGUILayout.PropertyField( serializedObject.FindProperty("parts"), true );
- EditorGUILayout.PropertyField( serializedObject.FindProperty("final_product"), true );
- }
- void Show_Parts(Item_Profile item)
- {
- }
- void Show_Consumables(Item_Profile item)
- {
- }
- void Show_Bomb(Item_Profile item)
- {
- }
- }
复制代码
|