1. 程式人生 > >使用Unity3D編寫ARPG遊戲——角色屬性的定義與實現(一)

使用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 MoveSp