1. 程式人生 > >Unity3D自學筆記——架構應用(十)角色屬性

Unity3D自學筆記——架構應用(十)角色屬性

角色屬性

效果圖
這裡寫圖片描述

類圖
這裡寫圖片描述

Attribute
提供公共的引數,每個引數都有兩個值
Atk, 基礎值,就是白屬性
AtkMax, 計算後的值,就是附魔,升級,強化,鑲嵌,充人民幣後的值

public abstract class Attribute
{
    private Attribute m_Parent;
    public int Hp { get; set; }
    public int Mp { get; set; }
    public int Atk { get; set; }
    public int Def { get; set; }
    public
int Spd { get; set; } public int Hit { get; set; } public double CriticalRate { get; set; } public double AtkSpd { get; set; } public double AtkRange { get; set; } public double MoveSpd { get; set; } public int HpMax { get; set; } public int MpMax { get; set; } public
int AtkMax { get; set; } public int DefMax { get; set; } public int SpdMax { get; set; } public int HitMax { get; set; } public double CriticalRateMax { get; set; } public double AtkSpdMax { get; set; } public double AtkRangeMax { get; set; } public double MoveSpdMax { get
; set; } public abstract void Calculate(); protected void SetParent(AttributeNode child) { child.m_Parent = this.m_Parent; } public Attribute GetParent() { return this.m_Parent; } }

AttributNode
繼承Attribute,遞迴實現Caculate,然後實現新增節點和刪除節點
就是給白屬性不斷的加各種效果

public class AttributeNode : Attribute
{
    private List<Attribute> m_NodeList = new List<Attribute>();
    public override void Calculate()
    {
        this.HpMax = this.Hp;
        this.MpMax = this.Mp;
        this.AtkMax = this.Atk;
        this.DefMax = this.Def;
        this.SpdMax = this.Spd;
        this.HitMax = this.Hit;
        this.CriticalRateMax = this.CriticalRate;
        this.AtkSpdMax = this.AtkSpd;
        this.AtkRangeMax = this.AtkRange;
        this.MoveSpdMax = this.MoveSpd;

        foreach (AttributeNode node in m_NodeList)
        {
            if (node.NodeCount() > 0)
            {
                node.Calculate();
            }

            this.HpMax += node.HpMax;
            this.MpMax += node.MpMax;
            this.AtkMax += node.AtkMax;
            this.DefMax += node.DefMax;
            this.SpdMax += node.SpdMax;
            this.HitMax += node.HitMax;
            this.CriticalRateMax += node.CriticalRateMax;
            this.AtkSpdMax += node.AtkSpdMax;
            this.MoveSpdMax += node.MoveSpdMax;
        }
    }
    public int NodeCount()
    {
        return m_NodeList.Count;
    }
    public void AddNode(AttributeNode node)
    {
        m_NodeList.Add(node);
    }
    public void RemoveNode(AttributeNode node)
    {
        m_NodeList.Remove(node);
    }
}

AttributeRoot
最頂級節點,就是角色屬性

最開始沒有Root類的,但是在處理當前血量時卡了很久
按照設計Hp應該是英雄的基礎屬性(1級的屬性),它不能變,不然一執行Caculate就跟開掛樣,不斷增加,所以還需要一個CurrentHp 來等於 MaxHp。又不想在PlayerInfo裡面又單獨定義一套屬性,所以就提取了Root類,畢竟主角光環,它特殊。可以看到大多方法是和Node一樣的,只是多了一個Caculate(bool),作為初始化是將HpCur = HpMax用。不用Root繼承Node的原因是,減小類之間的耦合關係,怕到後期變化過大導致不易修改。

public class AttributeRoot : Attribute
{
    public int HpCur { get; set; }
    public int MpCur { get; set; }
    public int AtkCur { get; set; }
    public int DefCur { get; set; }
    public int SpdCur { get; set; }
    public int HitCur { get; set; }
    public double CriticalRateCur { get; set; }
    public double AtkSpdCur { get; set; }
    public double AtkRangeCur { get; set; }
    public double MoveSpdCur { get; set; }

    private List<Attribute> m_NodeList = new List<Attribute>();
    public override void Calculate()
    {
        this.HpMax = this.Hp;
        this.MpMax = this.Mp;
        this.AtkMax = this.Atk;
        this.DefMax = this.Def;
        this.SpdMax = this.Spd;
        this.HitMax = this.Hit;
        this.CriticalRateMax = this.CriticalRate;
        this.AtkSpdMax = this.AtkSpd;
        this.AtkRangeMax = this.AtkRange;
        this.MoveSpdMax = this.MoveSpd;

        foreach (AttributeNode node in m_NodeList)
        {
            if (node.NodeCount() > 0)
            {
                node.Calculate();
            }

            this.HpMax += node.HpMax;
            this.MpMax += node.MpMax;
            this.AtkMax += node.AtkMax;
            this.DefMax += node.DefMax;
            this.SpdMax += node.SpdMax;
            this.HitMax += node.HitMax;
            this.CriticalRateMax += node.CriticalRateMax;
            this.AtkSpdMax += node.AtkSpdMax;
            this.MoveSpdMax += node.MoveSpdMax;
        }
    }

    public void Calculate(bool isInit)
    {
        Calculate();
        if (isInit)
        {
            this.HpCur = this.HpMax;
            this.MpCur = this.MpMax;
            this.AtkCur = this.AtkMax;
            this.DefCur = this.DefMax;
            this.SpdCur = this.SpdMax;
            this.HitCur = this.HitMax;
            this.CriticalRateCur = this.CriticalRateMax;
            this.AtkSpdCur = this.AtkSpdMax;
            this.MoveSpdCur = this.MoveSpdMax;
        }
    }
    public int NodeCount()
    {
        return m_NodeList.Count;
    }
    public void AddNode(AttributeNode node)
    {
        m_NodeList.Add(node);
    }
    public void RemoveNode(AttributeNode node)
    {
        m_NodeList.Remove(node);
    }
}

PlayerStatus
掛在角色上的

目前實現了當角色在場景中建立成功後,呼叫Load事件進行初始化。這裡把Lv和Exp單獨抽出來,是沒有考慮裝備或者其他技能對LV和經驗的變化。而且經驗是變化最快的,沒殺一個怪就變了,一變就Caculate也太耗效能了。

public class PlayerStatus : MonoBehaviour {
    private UserEntity m_User;
    public double m_MultipleExp = 1.18;
    public int m_StartExp = 40;
    public string PlayerName { get; set; }
    public int Lv { get; set; }
    public int LvMax { get; set; }
    public double Exp { get; set; }
    public double ExpMax { get; set;}
    public double HpRegenTime { get; set; }
    public double MpRegenTime { get; set; }

    public AttributeNode statusGrowth = new AttributeNode();
    public AttributeNode statusEquip = new AttributeNode();
    public AttributeNode statusBuff = new AttributeNode();
    public AttributeRoot status = new AttributeRoot();

    void Start()
    {

    }

    private void InitAllStatus()
    {
        InitStatusGrowth();
        InitStatus();
    }

    private void InitStatusGrowth()
    {
        this.statusGrowth.Hp = this.Lv * this.m_User.Hero.HpGrowth;
        this.statusGrowth.Mp = this.Lv * this.m_User.Hero.MpGrowth;
        this.statusGrowth.Atk = this.Lv * this.m_User.Hero.AtkGrowth;
        this.statusGrowth.Def = this.Lv * this.m_User.Hero.DefGrowth;
        this.statusGrowth.Spd = this.Lv * this.m_User.Hero.SpdGrowth;
        this.statusGrowth.Hit = this.Lv * this.m_User.Hero.HitGrowth;
        this.statusGrowth.CriticalRate = this.Lv * this.m_User.Hero.CriticalRateGrowth;
        this.statusGrowth.AtkSpd = this.Lv * this.m_User.Hero.AtkSpdGrowth;
        this.statusGrowth.AtkRange = this.Lv * this.m_User.Hero.AtkRangeGrowth;
        this.statusGrowth.MoveSpd = this.Lv * this.m_User.Hero.MoveSpdGrowth;

        this.statusGrowth.Calculate();
    }

    private void InitStatus()
    {
        this.status.Hp = this.m_User.Hero.Hp;
        this.status.Mp = this.m_User.Hero.Mp;
        this.status.Atk = this.m_User.Hero.Atk;
        this.status.Def = this.m_User.Hero.Def;
        this.status.Spd = this.m_User.Hero.Spd;
        this.status.Hit = this.m_User.Hero.Hit;
        this.status.CriticalRate = this.m_User.Hero.CriticalRate;
        this.status.AtkSpd = this.m_User.Hero.AtkSpd;
        this.status.AtkRange = this.m_User.Hero.AtkRange;
        this.status.MoveSpd = this.m_User.Hero.MoveSpd;

        this.status.AddNode(this.statusGrowth);
        this.status.AddNode(this.statusEquip);
        this.status.AddNode(this.statusBuff);
        this.status.Calculate(true);
    }


    public void Load(UserEntity user)
    {
        this.m_User = user;
        this.Lv = this.m_User.Lv;
        this.PlayerName = this.m_User.Name;
        this.Exp = this.m_User.Exp;
        this.ExpMax = m_StartExp * m_MultipleExp * this.Lv;
        this.LvMax = this.m_User.Hero.MaxLv;
        this.HpRegenTime = this.m_User.HpRegenTime;
        this.MpRegenTime = this.m_User.MpRegenTime;

        InitAllStatus();
    }
}

UIPlayerInfo
角色屬性綁值

public class UIPlayerInfo : UIScene {
    private Image m_ImgHead;
    private Text m_TxtLv;
    private Text m_TxtName;
    private Text m_TxtHp;
    private Text m_TxtMp;
    private Slider m_SldHp;
    private Slider m_SldMp;
    private Slider m_SldExp;

    private PlayerStatus m_PlayerStatus;

    protected override void Start()
    {
        base.Start();
        InitWidget();
    }

    private void InitWidget()
    {
        this.m_ImgHead = UIHelper.FindChild<Image>(transform, "imgHead");
        this.m_TxtLv = UIHelper.FindChild<Text>(transform, "txtLv");
        this.m_TxtName = UIHelper.FindChild<Text>(transform, "txtName");
        this.m_SldHp = UIHelper.FindChild<Slider>(transform, "sldHp");
        this.m_SldMp = UIHelper.FindChild<Slider>(transform, "sldMp");
        this.m_SldExp = UIHelper.FindChild<Slider>(transform, "sldExp");
        this.m_TxtHp = UIHelper.FindChild<Text>(transform, "sldHp/Text");
        this.m_TxtMp = UIHelper.FindChild<Text>(transform, "sldMp/Text");
        GameObject player = GameObject.FindGameObjectWithTag("Player");
        if (player != null)
        {
            //TODO: this.m_ImgHead
            this.m_PlayerStatus = player.GetComponent<PlayerStatus>();
            this.m_TxtName.text = this.m_PlayerStatus.PlayerName;
            this.m_TxtLv.text = this.m_PlayerStatus.Lv.ToString();
            this.m_TxtHp.text = string.Format("{0}/{1}", this.m_PlayerStatus.status.HpCur, this.m_PlayerStatus.status.HpMax);
            this.m_TxtMp.text = string.Format("{0}/{1}", this.m_PlayerStatus.status.MpCur, this.m_PlayerStatus.status.MpMax);
            this.m_SldHp.value = this.m_PlayerStatus.status.HpCur / this.m_PlayerStatus.status.HpMax;
            this.m_SldExp.value = this.m_PlayerStatus.status.MpCur / this.m_PlayerStatus.status.MpMax;
            this.m_SldExp.value = (float)(this.m_PlayerStatus.Exp / this.m_PlayerStatus.ExpMax);
        }
    }
}