使用Unity3D编写ARPG游戏——角色属性的定义与实现(一)
今天考完了大学最后一门考试,是瞬间感觉轻松了一点,花了一天多的时间预习一本书,马上就去考试了,就结果而言还是不错的。但是不知道是一种解脱,还是马上要戴上的一种新的枷锁。总归还是不错的。好了,闲话少扯,继续谈谈如何制作一款ARPG游戏,sunset在上两篇博客中已经介绍过了几种常见的ARPG游戏的人物控制方式,都比较简单,易于理解。接下来来看看制作ARPG游戏还需要什么,先从玩家可操作的角色出发,我们还需要人物的血量,或者用于释放魔法的魔量,这样就转入一种新的概念——人物属性。下面开始sunset个人编写的可视化人物属性编辑器:
人物属性分析
我们不能还没有经过分析或者思考就去动手写代码,这样只会一味给自己增加难度,延后代码编写完成的时间,这也是软件工程的基本理论。在首先编写代码之前,先来分析一下:我们需要什么?一个属性编辑器;这个编辑器中包含哪些属性?只要玩过一定数量的游戏,就会明白游戏人物一般都会有移动速度,攻击速度,攻击力,防御力等等属性值。我举例一款对属性比较看重的游戏——《Dota2》。虽然这款游戏是一款Moba游戏,但是丝毫不妨碍我们对属性经行分析,《Dota2》里英雄的属性包括:力量、敏捷、智力、攻击力、护甲、移动速度、转身速率、攻击速度、攻击距离等等等等。通过一款优秀的游戏可以得出我们所需要的解决的问题的答案,我们是否也需要敏捷、智力等等属性呢?一切都由你来决定,因为这是你的游戏。
sunset在个人制作的ARPG游戏项目中采用了这样一些属性:等级(LV)、血量(HP)、魔法值(MP)、攻击力(Attack)、防御力(Defend)、强壮(Strength)、敏捷(Agility)、智力(Intelligence)、体力(Power)、移动速度(MoveSpeed)、转身速度(RotationSpeed)、攻击距离(AttackRange)、暴击伤害百分比(CriticalDamage)、暴击概率(CriticalRate)等。这些属性值基本上满足了一款ARPG游戏的属性要求。接下来sunset给出的属性编辑器也基本上是基于这些属性进行编写的。
编辑器编写思考
经过属性中基本的属性量的定义后,我们还要进一步思考脚本该怎么编写才能使其更加易用与将来可能出现的武器属性加成或者被动技能属性加成等问题。所以将属性又分别分成几种类型:1)基础属性(BaseAttribute);2)额外(附加)属性(AdditiveAtribute);3)当前属性(CurrentAttribute);4)升级属性(GrowthAttribute);5)总属性(SumAttribute)等。这部分必须进行仔细思考,当写到一半才发觉还需要定义新的属性类型才能完成编写而不得不回头的时候,你会感觉非常无奈而致使完成时间向后拖延,所以经过仔细思考后再动手会事半功倍(个人经验)。
编写第一步——定义属性类
C#是面向对象的编程语言,所以我们直接定义“属性”类,并定义类属性,针对每个类的实例对象编写实现方法。代码如下:
[System.Serializable]public class BaseAttribute{//等级public int LV;/// <summary>///血量,魔量 /// </summary>public float HP, MP;/// <summary>///攻击力, 防御力, 力量, 智力, 敏捷, 体力 /// </summary>public float Attack, Defend, Strong, Intelligence, Agility, Power;/// <summary>/// 攻击速度,散步速度,跑步速度,后退速度,转身移动速度,转身速度,攻击范围,经验值,暴击概率,暴击伤害百分比;/// </summary>public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, Exp, CriticalRate, CriticalDamage;/// <summary>/// 每秒血量回复,每秒魔量回复/// </summary>public float HPRecoverPerSecond, MPRecoverPerSecond;}[System.Serializable]public class AdditionAttribute{/// <summary>///血量,魔量 /// </summary>public float HP, MP;/// <summary>///攻击力, 防御力, 力量, 智力, 敏捷, 体力 /// </summary>public float Attack, Defend, Strong, Intelligence, Agility, Power;/// <summary>/// 攻击速度,散步速度,跑步速度,后退速度,转身移动速度,转身速度,攻击范围,暴击概率,暴击伤害百分比;//暴击概率和攻击范围仅由装备影响。/// </summary>public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, CriticalRate,CriticalDamage;/// <summary>/// 每秒血量回复,每秒魔量回复/// </summary>public float HPRecoverPerSecond, MPRecoverPerSecond;}[System.Serializable]public class CurAttribute{/// <summary>///血量,魔量 /// </summary>public float CurHP, CurMP;/// <summary>///攻击力, 防御力, 力量, 智力, 敏捷, 体力 /// </summary>public float CurAttack, CurDefend, CurStrong, CurIntelligence, CurAgility, CurPower;/// <summary>/// 当前攻击速度,当前散步速度,当前跑步速度,当前后退速度,当前转身移动速度,当前转身速度,当前攻击范围,当前暴击概率, 当前暴击伤害百分比;/// </summary>public float CurAttackSpeed, CurMoveSpeed, CurRotationSpeed, CurAttackRange, CurCriticalRate, CurCriticalDamage;/// <summary>/// 每秒血量回复,每秒魔量回复/// </summary>public float HPRecoverPerSecond, MPRecoverPerSecond;}[System.Serializable]public class SumAttribute{/// <summary>///血量,魔量 /// </summary>public float HP, MP;/// <summary>///攻击力, 防御力, 力量, 智力, 敏捷, 体力 /// </summary>public float Attack, Defend, Strong, Intelligence, Agility, Power;/// <summary>/// 攻击速度,移动速度,转身速度,攻击范围,暴击概率,暴击伤害百分比;/// </summary>public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, CriticalRate, CriticalDamage;/// <summary>/// 每秒血量回复,每秒魔量回复/// </summary>public float HPRecoverPerSecond, MPRecoverPerSecond;}[System.Serializable]public class AttributeGrowth{/// <summary>///血量,魔量 /// </summary>public float HP, MP;/// <summary>///攻击力, 防御力, 力量, 智力, 敏捷, 体力 /// </summary>public float Attack, Defend, Strong, Intelligence, Agility, Power;}
注释的相当仔细,一看就懂。
然后我们还需要定义一些单独存在的量:比如最高等级,最大经验值、当前等级所需经验,如果有各种动画状态,还需要单独定义步行速度(WalkSpeed)、跑步速度(RunSpeed)、左右转身时向左或向右移动的速度(TurnSpeed),或者还可以定义后退时的移动速度(BackwardSpeed),看个人需求。然后定义出上文代码中定义的类对象的实例对象,编写过程中主要是使用类的实例对象。代码:
/// <summary>/// 最高等级/// </summary>public int MaxLV;/// <summary>/// 当前等级所需要的经验总量/// </summary>public float NeedExpPerLV;//当前等级到下一个等级还需要的经验量public float EXP2NextLV;//到当前为止所获得的所有经验量public float MaxExp;//各类的实例对象:public BaseAttribute BaseStatus;public AdditionAttribute AddStatus;public CurAttribute CurStatus;public SumAttribute SumStatus;public AttributeGrowth attributeGrowth, growthPoint;//定义各种速度:
public float RunSpeed;public float WalkSpeed;public float TurnSpeed;public float BackSpeed;
嗯,基本需要用到的量都已经定义好了,下一步开始编写方法使用这些量。
编写第二步——实施方法
我们首先来编写人物经验的计算方法,这里sunset个人所用的经验计算公式是:基数A * 当前等级 * 当前等级 + 基数B * 当前等级。这算是一种较为简单的计算方法了,一个一元二次方程。这个可以自行决定。先计算到当前为止所获得的所有经验量(包括当前等级到下一级),然后计算当前等级所需经验:(这里所采用的基数A和B分别为40和60)
void CalculateExp(){//更新到当前等级为止的所有经验,包括本级到下一级MaxExp = 40.0f * BaseStatus.LV * BaseStatus.LV + 60.0f * BaseStatus.LV;//更新本级到下一级所需要的经验值;NeedExpPerLV = MaxExp - (40.0f * (BaseStatus.LV - 1) * (BaseStatus.LV - 1) + 60.0f * (BaseStatus.LV - 1));}
然后更新当前经验值:
public void UpdateExp()//更新经验值{if (BaseStatus.LV >= MaxLV) {BaseStatus.Exp = NeedExpPerLV;BaseStatus.LV = MaxLV;}else {if(BaseStatus.Exp >= NeedExpPerLV){GetLvUp = true;//更新当前在本级拥有经验BaseStatus.Exp = BaseStatus.Exp - NeedExpPerLV;//更新等级BaseStatus.LV += 1;CalculateExp();GrowthisAdd = false;//更新属性UpdateAttribute();CurStatus.CurHP = SumStatus.HP;CurStatus.CurMP = SumStatus.MP;}}}
先判断当前等级是否大于最高等级,再判断当前经验是否达到当前等级所要求的经验量,如果达到就升级,并更新相关属性。升级时恢复血量和魔量到最大值。
接下来是更新相关属性的方法:
void UpdateAttribute(){if (!GrowthisAdd) {CalculateAttributePointGrowth ();BaseStatus.HP += attributeGrowth.HP;BaseStatus.MP += attributeGrowth.MP;BaseStatus.Attack += attributeGrowth.Attack;BaseStatus.Defend += attributeGrowth.Defend;BaseStatus.Strong += attributeGrowth.Strong;BaseStatus.Intelligence += attributeGrowth.Intelligence;BaseStatus.Agility += attributeGrowth.Agility;BaseStatus.Power += attributeGrowth.Power;GrowthisAdd = true;}SumStatus.Strong = BaseStatus.Strong + AddStatus.Strong;SumStatus.Intelligence = BaseStatus.Intelligence + AddStatus.Intelligence;SumStatus.Agility = BaseStatus.Agility + AddStatus.Agility;SumStatus.Power = BaseStatus.Power + AddStatus.Power;SumStatus.Attack = BaseStatus.Attack + AddStatus.Attack + Mathf.FloorToInt(SumStatus.Strong * 0.2f);SumStatus.Defend = BaseStatus.Defend + AddStatus.Defend + Mathf.FloorToInt(SumStatus.Power * 0.2f);SumStatus.HP = BaseStatus.HP + AddStatus.HP + Mathf.FloorToInt(SumStatus.Strong * 0.4f);SumStatus.MP = BaseStatus.MP + AddStatus.MP + Mathf.FloorToInt(SumStatus.Intelligence * 0.4f);SumStatus.AttackSpeed = BaseStatus.AttackSpeed + AddStatus.AttackSpeed + Mathf.FloorToInt(SumStatus.Agility * 0.2f);SumStatus.MoveSpeed = BaseStatus.MoveSpeed + AddStatus.MoveSpeed + Mathf.FloorToInt(SumStatus.Agility * 0.3f);SumStatus.RotationSpeed = BaseStatus.RotationSpeed + AddStatus.RotationSpeed + Mathf.FloorToInt(SumStatus.Agility * 0.2f);SumStatus.CriticalRate = BaseStatus.CriticalRate + AddStatus.CriticalRate;SumStatus.CriticalDamage = BaseStatus.CriticalDamage + AddStatus.CriticalDamage;CurStatus.CurAttack = SumStatus.Attack;CurStatus.CurDefend = SumStatus.Defend;CurStatus.CurStrong = SumStatus.Strong;CurStatus.CurIntelligence = SumStatus.Intelligence;CurStatus.CurAgility = SumStatus.Agility;CurStatus.CurPower = SumStatus.Power;CurStatus.CurCriticalRate = SumStatus.CriticalRate;CurStatus.CurCriticalDamage = SumStatus.CriticalDamage;}
这里主要说明一下,sunset个人定义的属性中强壮部分决定了攻击力和血量上限,体力部分决定了防御力,智力部分决定了魔法值上限,敏捷部分决定了各种速度等等,自行理解。
然后在计算更新属性方法中还定义了一种当存在升级点数加成时,计算升级属性相关的方法:
void CalculateAttributePointGrowth(){if (growthPoint.HP > 0) {attributeGrowth.HP += 2 * growthPoint.HP;}if (growthPoint.Attack > 0) {attributeGrowth.Attack += 2 * growthPoint.Attack; }if(growthPoint.MP > 0){attributeGrowth.MP += 2 * growthPoint.MP;} if(growthPoint.Defend > 0){attributeGrowth.Defend += 2 * growthPoint.Defend;}if(growthPoint.Strong > 0){attributeGrowth.Strong += 2 * growthPoint.Strong;}if(growthPoint.Intelligence > 0){attributeGrowth.Intelligence += 2 * growthPoint.Intelligence;}if(growthPoint.Agility > 0){attributeGrowth.Agility += 2 * growthPoint.Agility;}if(growthPoint.Power > 0){attributeGrowth.Power += 2 * growthPoint.Power;}}
这样更新属性方面的相关方法就差不多了,然后我们还要检测血量等属性值,避免血量等属性值超过总属性值。
//检测HP、MP的当前值是否超出规定,每帧调用void CheckHPMP(){AnimatorStateInfo H_CurrentState = H_Animator.GetCurrentAnimatorStateInfo (0);if (!H_CurrentState.IsName ("Base.H_Death")){CurStatus.CurHP += Mathf.FloorToInt(BaseStatus.HPRecoverPerSecond * 0.33f);CurStatus.CurMP += Mathf.FloorToInt(BaseStatus.MPRecoverPerSecond * 0.50f);}else {CurStatus.CurHP = 0;CurStatus.CurMP = 0;}if (CurStatus.CurHP < 0) {CurStatus.CurHP = 0;}if (CurStatus.CurMP < 0) {CurStatus.CurMP = 0;}if (CurStatus.CurHP >= SumStatus.HP) {CurStatus.CurHP = SumStatus.HP;}if (CurStatus.CurMP >= SumStatus.MP) {CurStatus.CurMP = SumStatus.MP;}}
这样属性编辑器在原始属性定义方面就差不多完成了,然而现在我们编写的还只是脚本,不能算的上是一种可视化编辑器,还需要编辑一个Editor文件来对上文定义的变量进行值的输入。Editor文件的编写在原理上是十分简单的,就是一味的套用Unity本身的制定的GUIEditor的方法就好了,编写插件也是通过这种方法进行编写的,只是编写的好坏以及是否美观简洁、是否易于输入与识别的区别而已,这当然需要大量的动手编写经验。基本的语法都可以在API文档中找到sunset在这里不再赘述给出sunset个人编写的一个简单的人物属性Editor文件的源代码:
using UnityEditor;
using UnityEngine;
using System.Collections;[CustomEditor(typeof(HeroStatus))]
public class HeroStatusEditor : Editor {public bool ShowBaseAttribute = true;public bool ShowAddtitionAttribute = true;public bool ShowCurAttribute = true;public bool ShowSumAttribute = true;public bool ShowAttributeGrowth = true;public override void OnInspectorGUI(){HeroStatus heroStatus = (HeroStatus)target;heroStatus.HeroName = EditorGUILayout.TextField ("Hero Name:", heroStatus.HeroName);heroStatus.BaseStatus.LV = EditorGUILayout.IntField ("Hero Lv:", heroStatus.BaseStatus.LV);heroStatus.MaxLV = EditorGUILayout.IntField ("Max LV:", heroStatus.MaxLV);heroStatus.BaseStatus.Exp = EditorGUILayout.FloatField ("Hero Current Exp:", heroStatus.BaseStatus.Exp);heroStatus.EXP2NextLV = EditorGUILayout.FloatField ("Need Exp To Next LV:", (heroStatus.NeedExpPerLV - heroStatus.BaseStatus.Exp));heroStatus.CurrentPoint = EditorGUILayout.IntField ("Growth Point:", heroStatus.CurrentPoint);EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Walk Speed:" , heroStatus.WalkSpeed.ToString());EditorGUILayout.LabelField ("Run Speed:" , heroStatus.RunSpeed.ToString());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Back Speed:" , heroStatus.BackSpeed.ToString());EditorGUILayout.LabelField ("Turn Speed:" , heroStatus.TurnSpeed.ToString());EditorGUILayout.EndHorizontal ();ShowCurAttribute = EditorGUILayout.Foldout (ShowCurAttribute, "Current Status:");if (ShowCurAttribute){EditorGUI.indentLevel++;EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("HP:", heroStatus.CurStatus.CurHP.ToString ());EditorGUILayout.LabelField ("MP:", heroStatus.CurStatus.CurMP.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Attack:", heroStatus.CurStatus.CurAttack.ToString ());EditorGUILayout.LabelField ("Defend:", heroStatus.CurStatus.CurDefend.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Strong:", heroStatus.CurStatus.CurStrong.ToString ());EditorGUILayout.LabelField ("Intelligence:", heroStatus.CurStatus.CurIntelligence.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Agility:", heroStatus.CurStatus.CurAgility.ToString ());EditorGUILayout.LabelField ("Power:", heroStatus.CurStatus.CurPower.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Attack Speed:", heroStatus.CurStatus.CurAttackSpeed.ToString ());EditorGUILayout.LabelField ("Attack Range:", heroStatus.CurStatus.CurAttackRange.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Move Speed:", heroStatus.CurStatus.CurMoveSpeed.ToString ());EditorGUILayout.LabelField ("Rotation Range:", heroStatus.CurStatus.CurRotationSpeed.ToString ().ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal ();EditorGUILayout.LabelField ("Cur Critical Damage:", heroStatus.CurStatus.CurCriticalDamage.ToString ());EditorGUILayout.LabelField ("Critical Rate:", heroStatus.CurStatus.CurCriticalRate.ToString ());EditorGUILayout.EndHorizontal ();EditorGUILayout.BeginHorizontal();EditorGUILayout.LabelField("Cur HP Recover Per Second:", heroStatus.CurStatus.HPRecoverPerSecond.ToString());EditorGUILayout.LabelField("Cur MP Recover Per Second:", heroStatus.CurStatus.MPRecoverPerSecond.ToString());EditorGUILayout.EndHorizontal();}EditorGUI.indentLevel--;EditorGUILayout.Space();ShowBaseAttribute = EditorGUILayout.Foldout (ShowBaseAttribute, "Base Attribute");EditorGUI.indentLevel++;if (ShowBaseAttribute) {heroStatus.BaseStatus.HP = (float)EditorGUILayout.Slider("Base HP:", heroStatus.BaseStatus.HP, 0.0f, 9999.0f);ProgressBar(heroStatus.BaseStatus.HP/9999f,"Base HP");heroStatus.BaseStatus.MP = (float)EditorGUILayout.Slider("Base MP:", heroStatus.BaseStatus.MP, 0.0f, 9999.0f);ProgressBar(heroStatus.BaseStatus.MP/9999f,"Base MP");heroStatus.BaseStatus.Attack = (float)EditorGUILayout.Slider("Base Attack", heroStatus.BaseStatus.Attack, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Attack/999.0f,"Base Attack");heroStatus.BaseStatus.Defend = (float)EditorGUILayout.Slider("Base Defend", heroStatus.BaseStatus.Defend, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Defend/999.0f,"Base Defend");heroStatus.BaseStatus.Strong = (float)EditorGUILayout.Slider("Base Strong", heroStatus.BaseStatus.Strong, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Strong/999.0f,"Base Strong");heroStatus.BaseStatus.Intelligence = (float)EditorGUILayout.Slider("Base Intelligence", heroStatus.BaseStatus.Intelligence, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Intelligence/999.0f,"Base Intelligence");heroStatus.BaseStatus.Agility = (float)EditorGUILayout.Slider("Base Agility", heroStatus.BaseStatus.Agility, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Agility/999.0f,"Base Agility");heroStatus.BaseStatus.Power = (float)EditorGUILayout.Slider("Base Power", heroStatus.BaseStatus.Power, 0.0f, 999.0f);ProgressBar(heroStatus.BaseStatus.Power/999.0f,"Base Power");heroStatus.BaseStatus.AttackSpeed = (float)EditorGUILayout.Slider("Base AttackSpeed", heroStatus.BaseStatus.AttackSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.AttackSpeed/100.0f,"Base AttackSpeed");heroStatus.BaseStatus.MoveSpeed = (float)EditorGUILayout.Slider("Base MoveSpeed", heroStatus.BaseStatus.MoveSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.MoveSpeed/100.0f,"Base MoveSpeed");heroStatus.BaseStatus.RotationSpeed = (float)EditorGUILayout.Slider("Base RotationSpeed", heroStatus.BaseStatus.RotationSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.RotationSpeed/100.0f,"Base RotationSpeed");heroStatus.BaseStatus.AttackRange = (float)EditorGUILayout.Slider("Base AttackRange", heroStatus.BaseStatus.AttackRange, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.AttackRange/100.0f,"Base AttackRange");heroStatus.BaseStatus.CriticalRate = (float)EditorGUILayout.Slider("Base CriticalRate", heroStatus.BaseStatus.CriticalRate, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.CriticalRate/100.0f,"Base CriticalRate");heroStatus.BaseStatus.CriticalDamage = (float)EditorGUILayout.Slider("Base CriticalDamage", heroStatus.BaseStatus.CriticalDamage, 0.0f, 100.0f);ProgressBar(heroStatus.BaseStatus.CriticalDamage/100.0f,"Base CriticalDamage");heroStatus.BaseStatus.HPRecoverPerSecond = EditorGUILayout.FloatField("HP Recover Per Second:", heroStatus.BaseStatus.HPRecoverPerSecond);ProgressBar(heroStatus.BaseStatus.HPRecoverPerSecond / 100.0f, "Base HP Recover Per Second:");heroStatus.BaseStatus.MPRecoverPerSecond = EditorGUILayout.FloatField("MP Recover Per Second:", heroStatus.BaseStatus.MPRecoverPerSecond);ProgressBar(heroStatus.BaseStatus.MPRecoverPerSecond / 100.0f, "Base MP Recover Per Second:");}EditorGUI.indentLevel--;EditorGUILayout.Space ();ShowAddtitionAttribute = EditorGUILayout.Foldout (ShowAddtitionAttribute, "Addtition Attribute:");EditorGUI.indentLevel++;if (ShowAddtitionAttribute) {heroStatus.AddStatus.HP = (float)EditorGUILayout.Slider("Addtition HP:", heroStatus.AddStatus.HP, 0.0f, 9999.0f);ProgressBar(heroStatus.AddStatus.HP/9999f,"Addtition HP");heroStatus.AddStatus.MP = (float)EditorGUILayout.Slider("Addtition MP:", heroStatus.AddStatus.MP, 0.0f, 9999.0f);ProgressBar(heroStatus.AddStatus.MP/9999f,"Addtition MP");heroStatus.AddStatus.Attack = (float)EditorGUILayout.Slider("Addtition Attack", heroStatus.AddStatus.Attack, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Attack/999.0f,"Addtition Attack");heroStatus.AddStatus.Defend = (float)EditorGUILayout.Slider("Addtition Defend", heroStatus.AddStatus.Defend, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Defend/999.0f,"Addtition Defend");heroStatus.AddStatus.Strong = (float)EditorGUILayout.Slider("Addtition Strong", heroStatus.AddStatus.Strong, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Strong/999.0f,"Addtition Strong");heroStatus.AddStatus.Intelligence = (float)EditorGUILayout.Slider("Addtition Intelligence", heroStatus.AddStatus.Intelligence, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Intelligence/999.0f,"Addtition Intelligence");heroStatus.AddStatus.Agility = (float)EditorGUILayout.Slider("Addtition Agility", heroStatus.AddStatus.Agility, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Agility/999.0f,"Addtition Agility");heroStatus.AddStatus.Power = (float)EditorGUILayout.Slider("Addtition Power", heroStatus.AddStatus.Power, 0.0f, 999.0f);ProgressBar(heroStatus.AddStatus.Power/999.0f,"Addtition Power");heroStatus.AddStatus.AttackSpeed = (float)EditorGUILayout.Slider("Addtition AttackSpeed", heroStatus.AddStatus.AttackSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.AttackSpeed/100.0f,"Addtition AttackSpeed");heroStatus.AddStatus.MoveSpeed = (float)EditorGUILayout.Slider("Addtition MoveSpeed", heroStatus.AddStatus.MoveSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.MoveSpeed/100.0f,"Addtition MoveSpeed");heroStatus.AddStatus.RotationSpeed = (float)EditorGUILayout.Slider("Addtition RotationSpeed", heroStatus.AddStatus.RotationSpeed, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.RotationSpeed/100.0f,"Addtition RotationSpeed");heroStatus.AddStatus.AttackRange = (float)EditorGUILayout.Slider("Addtition AttackRange", heroStatus.AddStatus.AttackRange, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.AttackRange/100.0f,"Addtition AttackRange");heroStatus.AddStatus.CriticalRate = (float)EditorGUILayout.Slider("Addtition CriticalRate", heroStatus.AddStatus.CriticalRate, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.CriticalRate/100.0f,"Addtition CriticalRate");heroStatus.AddStatus.CriticalDamage = (float)EditorGUILayout.Slider("Addtition CriticalDamage", heroStatus.AddStatus.CriticalDamage, 0.0f, 100.0f);ProgressBar(heroStatus.AddStatus.CriticalDamage/100.0f,"Addtition CriticalDamage");}EditorGUI.indentLevel--;EditorGUILayout.Space ();ShowAttributeGrowth = EditorGUILayout.Foldout (ShowAttributeGrowth, "Growth Attribute:");EditorGUI.indentLevel++;if (ShowAttributeGrowth) {EditorGUILayout.BeginHorizontal();heroStatus.attributeGrowth.HP = EditorGUILayout.FloatField("HP:", heroStatus.attributeGrowth.HP);heroStatus.attributeGrowth.MP = EditorGUILayout.FloatField("MP:", heroStatus.attributeGrowth.MP);EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();heroStatus.attributeGrowth.Attack = EditorGUILayout.FloatField("Attack:", heroStatus.attributeGrowth.Attack);heroStatus.attributeGrowth.Defend = EditorGUILayout.FloatField("Defend:", heroStatus.attributeGrowth.Defend);EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();heroStatus.attributeGrowth.Strong = EditorGUILayout.FloatField("Strong:", heroStatus.attributeGrowth.Strong);heroStatus.attributeGrowth.Intelligence = EditorGUILayout.FloatField("Intelligence:", heroStatus.attributeGrowth.Intelligence);EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();heroStatus.attributeGrowth.Agility = EditorGUILayout.FloatField("Agility:", heroStatus.attributeGrowth.Agility);heroStatus.attributeGrowth.Power = EditorGUILayout.FloatField("Power:", heroStatus.attributeGrowth.Power);EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();heroStatus.attributeGrowth.Agility = EditorGUILayout.FloatField("Agility:", heroStatus.attributeGrowth.Agility);heroStatus.attributeGrowth.Power = EditorGUILayout.FloatField("Power:", heroStatus.attributeGrowth.Power);EditorGUILayout.EndHorizontal();}EditorGUI.indentLevel--;EditorGUILayout.Space ();ShowSumAttribute = EditorGUILayout.Foldout (ShowSumAttribute, "Total Attribute:");EditorGUI.indentLevel++;if (ShowSumAttribute) {EditorGUILayout.LabelField("Total HP:", heroStatus.SumStatus.HP.ToString());ProgressBar(heroStatus.SumStatus.HP/9999f,"Total HP");EditorGUILayout.LabelField("Total MP:", heroStatus.SumStatus.MP.ToString());ProgressBar(heroStatus.SumStatus.MP/9999f,"Total MP");EditorGUILayout.LabelField("Total Attack", heroStatus.SumStatus.Attack.ToString());ProgressBar(heroStatus.SumStatus.Attack/999.0f,"Total Attack");EditorGUILayout.LabelField("Total Defend", heroStatus.SumStatus.Defend.ToString());ProgressBar(heroStatus.SumStatus.Defend/999.0f,"Total Defend");EditorGUILayout.LabelField("Total Strong", heroStatus.SumStatus.Strong.ToString());ProgressBar(heroStatus.SumStatus.Strong/999.0f,"Total Strong");EditorGUILayout.LabelField("Total Intelligence", heroStatus.SumStatus.Intelligence.ToString());ProgressBar(heroStatus.SumStatus.Intelligence/999.0f,"Total Intelligence");EditorGUILayout.LabelField("Total Agility", heroStatus.SumStatus.Agility.ToString());ProgressBar(heroStatus.SumStatus.Agility/999.0f,"Total Agility");EditorGUILayout.LabelField("Total Power", heroStatus.SumStatus.Power.ToString());ProgressBar(heroStatus.SumStatus.Power/999.0f,"Total Power");EditorGUILayout.LabelField("Addtition AttackSpeed", heroStatus.SumStatus.AttackSpeed.ToString());ProgressBar(heroStatus.SumStatus.AttackSpeed/100.0f,"Addtition AttackSpeed");EditorGUILayout.LabelField("Addtition MoveSpeed", heroStatus.SumStatus.MoveSpeed.ToString());ProgressBar(heroStatus.SumStatus.MoveSpeed/100.0f,"Addtition MoveSpeed");EditorGUILayout.LabelField("Total RotationSpeed", heroStatus.SumStatus.RotationSpeed.ToString());ProgressBar(heroStatus.SumStatus.RotationSpeed/100.0f,"Total RotationSpeed");EditorGUILayout.LabelField("Total AttackRange", heroStatus.SumStatus.AttackRange.ToString());ProgressBar(heroStatus.SumStatus.AttackRange/100.0f,"Total AttackRange");EditorGUILayout.LabelField("Total CriticalRate", heroStatus.SumStatus.CriticalRate.ToString());ProgressBar(heroStatus.SumStatus.CriticalRate/100.0f,"Total CriticalRate");EditorGUILayout.LabelField("Total CriticalDamage", heroStatus.SumStatus.CriticalDamage.ToString());ProgressBar(heroStatus.SumStatus.CriticalDamage/100.0f,"Total CriticalDamage");EditorGUILayout.LabelField("Total HP Recover Per Second:", heroStatus.SumStatus.HPRecoverPerSecond.ToString());ProgressBar(heroStatus.SumStatus.HPRecoverPerSecond / 100.0f, "Total HP Recover Per Second:");EditorGUILayout.LabelField("Total MP Recover Per Second:", heroStatus.SumStatus.MPRecoverPerSecond.ToString());ProgressBar(heroStatus.SumStatus.MPRecoverPerSecond / 100.0f, "Total MP Recover Per Second:");}}public void ProgressBar (float val,string label) {Rect rect = GUILayoutUtility.GetRect (18, 18, "TextField");EditorGUI.ProgressBar (rect, val, label);EditorGUILayout.Space ();}
}
嗯,Editor文件只是一系列重复的语句,修改其中的关键词以符合各种属性就好了,是不是很简单呢?程序编写的脚本能让策划简单易懂的实现值的输入是非常重要的,写的美观简洁易懂不止是给策划方便,也是给自己方便。嗯,今天写的有点多了,现在时间也很晚了至于人物编辑器编写的剩下部分就明天下午更吧,就这样。
使用Unity3D编写ARPG游戏——角色属性的定义与实现(一)相关推荐
- 使用Unity3D编写ARPG游戏——角色属性的定义与实现(二)
在上一篇博客中,已经编写了人物属性编辑器的大部分,但是光有一些属性的定义并没有什么卵用,我们还需要添加在角色受到伤害时,反映在人物属性上的变化,或者状态的变化.其实说到底,这部分也就是编写两个方法来接 ...
- 从无主之地看FPS+ARPG游戏的发展方向
这里以<无主之地>系列和<命运>系列为例做一个游戏分类学上的研究. 笔者还记得接触<无主之地>初代时自己有多么震惊:五花八门奇形怪状的各式枪支,美式漫画画风的废土世 ...
- unity3d横版游戏移动_制作游戏并不困难。 回顾Unity3D上的小型移动项目
unity3d横版游戏移动 Clearly, I'm telling about my experience and my vision, but many things would be commo ...
- C语言第十二课:编写扫雷游戏(综合练习2)
目录 前言: 一.文件建立: 1.头文件game.h: 2.函数定义文件game.c: 3.工程测试文件test.c: 二.编写井字棋游戏: 1.程序整体执行思路: 2.menu菜单: 3.game游 ...
- Unity3D研究院之游戏开发中的人工智能AI
很久没有写Unity3D相关的东西了,是因为这段时间我深陷一款IOS的软件开发中.不过以后我还是会回归Unity3D游戏开发的.什么语言都在用,生活与工作都挺给力的嚯嚯.今天还是打开了久违的U ...
- pythonturtle画飞机_浅谈pygame编写外星人入侵游戏第一步(屏幕上绘制飞机)......
本人小白 刚开始学习python半月,到目前将python基础语法跑了一遍,不算透彻,只是有一些映像...... 于是学着做外星人入侵游戏,想从项目中深度学习,直接上目前的效果图: --------- ...
- 如何编写 C++ 游戏引擎
如何编写 C++ 游戏引擎 原创: 伯乐在线 CPP开发者 6月5日 (点击上方公众号,可快速关注) 编译:伯乐在线 - 李大萌 英文:Jeff Preshing http://blog.jobbol ...
- ui动效 unity_针对Unity3D的小游戏UI框架——IceCreamView
前言 IceCreamView是什么? IceCreamView(以下简称ICView)是一套针对Unity3D的小游戏UI快速构建框架. 同时ICView是一套面向组件开发模式的UI框架,以容器+组 ...
- Tc2.0编写俄罗斯方块游戏
Tc2.0编写俄罗斯方块游戏 作者:陈畅 联系地址:上海财经大学图书馆 电子邮件:shufechenchang@263.net 个人主页:http://shchenchang.top263.net/ ...
- 【Unity3D开发小游戏】《愤怒的小鸟》开发教程
[Unity3D开发小游戏]<愤怒的小鸟>开发教程 2019年09月11日 10:34:36 恬静的小魔龙 阅读数 1698更多 分类专栏: Unity3D日常 Unity3d手游开发 U ...
最新文章
- linux ln 权限不够,每次执行./都会出现权限不够,已经是root了 已解决!
- POJ 3628 Bookshelf 2
- C# lambda表达式及初始化器
- 塑壳断路器用考虑启动电流么_塑壳式断路器知识
- c语言rtu crc16,Modbus-RTU-crc16校验方法C语言实现
- android文本复制自定义剪切板,android 剪切板-文本复制、粘贴
- JavaScript传参年月日格式日期自动运算问题解决
- Windows系统历史版本简介
- 移动光猫固件备份、刷机、改sn和mac等
- JDK1.8下载、安装和环境配置教程
- 计算机笔记本硬盘,笔记本取证之--笔记本硬盘拆卸
- vue中.lazy 相当于change事件
- 湖南任务书 数据库服务渗透测试
- 赫夫曼编码树(图解+完整代码)
- GRDDC2020数据集下载及介绍
- 计算机休眠不播放音乐,电脑休眠后不能播放音乐怎么办
- 怎样选择适合您的EDI供应商?
- 需求定律公式和需求弹性推导——《可…
- 基于epoll实现的c++聊天室(全代码)
- 寓言之政府和计划生育——写在30年后的又一次改革——上海自贸区的成立
热门文章
- 嵌入式蓝桥杯又一个神之BUG Keil4 ADC仿真值出不来
- OceanBase 社区版 ODC 功能解读
- 所谓的flash、ddr、ufs
- 基因、DNA、碱基、染色体之间的关系是什么?
- 关于部分积分,动能公式另一种推导
- 如何在Word中的项目符号列表中自定义项目符号
- 项目管理知识体系指南 (四)
- 背包问题(最大装载价值)
- qt4.8.7 2016年4月18日 error reading collection file qthelpcollection cannot load sql
- 补点C#基础_022_json校验和json在线编辑器-bejson