關於Unity中NGUI的3D角色血條的實現


首先要到Unity的Assets Store里面去下載一個擴展的Package叫NGUI HUD Text v1.13(81),注意如果沒有安裝NGUI就必須先安裝NGUI插件,否則會用不了,因為HUD Text是依賴於NGUI插件的,作者是同一個。

 

3D角色血條實例

1.創建Unity項目工程和文件目錄

2.導入模型資源(使用NGUI里面自帶的ORC)和NGUI HUD Text v1.13的Package

3.把模型拖進場景中,調整畫面,選中Main Camera---->GameObject---->Align With View攝像機對齊選中視圖,使得Game視圖顯現我們想要的畫面,如果看不見可能是Camera的Culling Mask沒有設置對,要設置成可以看見模型所在的層

4.在ORC模型節點下創建一個Target的子節點當作血量字體的父節點,調整位置到ORC的頭頂,血量字體都從這里生成

5.創建一個NGUI的Label然后刪除Label,只留下UI Root和攝像機,攝像機的深度值要注意比3D攝像機的深度值大,然后在UI Root節點下再創建一個空節點HUDTextObj

6.添加Assets\HUD Text\Scripts下的HUDText.cs和UIFollowTarget.cs腳本組件到HUDTextObj節點下

7.設置HUDText的Bitmap Font字體屬性為Assets\HUD Text\Examples\Atlases下的Arimo20.prefab,如果設置True Type Font為以前的那個msyh,就可以寫中文,Font Size字體大小,Effect Color字體特效顏色。

 設置UIFollowTarget的target為剛才創建的target,跟隨這個節點,Game Camera為3D游戲場景的Camera,UI Camera為UI Root下的Camera,Disable if Invisible如果當前節點不可見就刪除,Destroy With Target跟隨target節點一起刪除

8.寫一個腳本test.cs掛載在HUDTextObj節點下控制模型生命值的變化

 test.cs

using UnityEngine;
using System.Collections;

public class test : MonoBehaviour {

    public HUDText hudText;
    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
        //hudText.Add(要顯示的文字或數字等, 顏色, 停留的時間),實現自動變換的效果
        //hudText.Add(Time.deltaTime*10f, Color.yellow, 3f);//在1秒內從1遞增到10,停留3秒

        if (Input.GetMouseButtonUp(0))//鼠標左鍵抬起加血
        {
            hudText.Add("Add blood +10", Color.green, 0.1f);
        }

        if (Input.GetMouseButtonUp(1))//鼠標右鍵抬起扣血
        {
            hudText.Add("Attacked -20", Color.red, 0.1f);
        }
    }
}

9.效果

  

10.添加血條,NGUI---->Open---->Prefab Toolbar,選擇一個預制體的進度條拖進場景中,作為UI Root的子節點,設置大小和顏色,位置在模型頭頂

11.給test.cs腳本添加關聯和控制Slider的語句,可以通過代碼控制Slider的Value,從而達到加血扣血會改變血條的值

 test.cs

using UnityEngine;
using System.Collections;

public class test : MonoBehaviour {

    public HUDText hudText;
    public UISlider slider;
    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
        //hudText.Add(要顯示的文字或數字等, 顏色, 停留的時間),實現自動變換的效果
        //hudText.Add(Time.deltaTime*10f, Color.yellow, 3f);//在1秒內從1遞增到10,停留3秒

        if (Input.GetMouseButtonUp(0))//鼠標左鍵加血
        {
            hudText.Add("Add blood +2", Color.green, 0.1f);
            slider.value += 0.02f;
        }

        if (Input.GetMouseButtonUp(1))//鼠標右鍵扣血
        {
            hudText.Add("Attacked -2", Color.red, 0.1f);
            slider.value -= 0.02f;
        }
    }
}

12.效果

  

 13.UIFollowTarget.cs部分代碼

    void Start()
    {
        if (target)
        {
            if (gameCamera == null) gameCamera = NGUITools.FindCameraForLayer(target.gameObject.layer);//通過層找到3D攝像機
            if (uiCamera == null) uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);//通過層找到UI攝像機
            Update();
        }
        else
        {
            if (destroyWithTarget) Destroy(gameObject);
            else enabled = false;
        }
    }

    /// <summary>
    /// Update the position of the HUD object every frame such that is position correctly over top of its real world object.
    /// </summary>

    void Update ()
    {
        if (target && uiCamera != null)
        {
            //把跟隨的節點的坐標轉換為gameCamera的視圖坐標
            Vector3 pos = gameCamera.WorldToViewportPoint(target.position);

            //判斷是否可見,是否在可視區域內
            // Determine the visibility and the target alpha
            int isVisible = (gameCamera.orthographic || pos.z > 0f) && (pos.x > 0f && pos.x < 1f && pos.y > 0f && pos.y < 1f) ? 1 : 0;
            bool vis = (isVisible == 1);

            // If visible, update the position
            if (vis)
            {
                pos = uiCamera.ViewportToWorldPoint(pos);
                pos = mTrans.parent.InverseTransformPoint(pos);
                //pos.x = Mathf.RoundToInt(pos.x);
                //pos.y = Mathf.RoundToInt(pos.y);
                pos.z = 0f;
                mTrans.localPosition = pos;
            }

            // Update the visibility flag
            if (mIsVisible != isVisible)
            {
                mIsVisible = isVisible;

                if (disableIfInvisible)
                {
                    for (int i = 0, imax = mTrans.childCount; i < imax; ++i)
                        NGUITools.SetActive(mTrans.GetChild(i).gameObject, vis);//開始激活
                }

                // Inform the listener
                if (onChange != null) onChange(vis);
            }
        }
        else Destroy(gameObject);
    }

 14. HUDText.cs部分代碼

  提高游戲性能的編程方法:池,是用List來模擬
  循環利用已經創建的gameObject,避免了頻繁的初始化gameObject(因為創建,初始化gameObject是需要消耗CPU時間的)
  避免了短時間的卡頓現象,比如捕魚達人,在一兩幀內批量創建幾百條的魚可能會出現瞬時間的卡頓,在手機上性能優化比電腦上明顯

  被激活的gameObject
  List<Entry> mList = new List<Entry>();
  保存被銷毀的文字,但是我們不銷毀gameObject,只是隱藏gameObject;然后添加到未使用的List列表中
  List<Entry> mUnused = new List<Entry>();

Entry Create ()
    {
        // See if an unused entry can be reused看是否可以被復用
        if (mUnused.Count > 0)
        {
            Entry ent = mUnused[mUnused.Count - 1];//從未激活的List的最后一個開始取
            mUnused.RemoveAt(mUnused.Count - 1);//取出后再刪除未激活的List里面的最后一個
            ent.time = Time.realtimeSinceStartup;
            ent.label.depth = NGUITools.CalculateNextDepth(gameObject);//改變深度值
            NGUITools.SetActive(ent.label.gameObject, true);//激活
            ent.offset = 0f;
            mList.Add(ent);//添加到已被激活的List里面去
            return ent;
        }
        
        // New entry重新創建
        Entry ne = new Entry();
        ne.time = Time.realtimeSinceStartup;
        ne.label = NGUITools.AddWidget<UILabel>(gameObject);//耗時的
        ne.label.name = counter.ToString();
        ne.label.ambigiousFont = ambigiousFont;
        ne.label.fontSize = fontSize;
        ne.label.fontStyle = fontStyle;
        ne.label.applyGradient = applyGradient;
        ne.label.gradientTop = gradientTop;
        ne.label.gradientBottom = gradienBottom;
        ne.label.effectStyle = effect;
        ne.label.effectColor = effectColor;
        ne.label.overflowMethod = UILabel.Overflow.ResizeFreely;

        // Make it small so that it's invisible to start with
        ne.label.cachedTransform.localScale = new Vector3(0.001f, 0.001f, 0.001f);
        mList.Add(ne);//添加到已被激活的List里面去
        ++counter;
        return ne;
    }

    /// <summary>
    /// Delete the specified entry, adding it to the unused list.
    /// </summary>

    void Delete (Entry ent)
    {
        mList.Remove(ent);//從已經激活的List里面刪除
        mUnused.Add(ent);//添加到未激活的等待被復用的List里面
        NGUITools.SetActive(ent.label.gameObject, false);//設置為不可見
    }
void Update ()
    {
#if UNITY_EDITOR
        if (!Application.isPlaying) return;
#endif
        float time = RealTime.time;

        if (mOffsets == null)
        {
            mOffsets = offsetCurve.keys;
            mAlphas = alphaCurve.keys;
            mScales = scaleCurve.keys;
        }

        float offsetEnd = mOffsets[mOffsets.Length - 1].time;
        float alphaEnd = mAlphas[mAlphas.Length - 1].time;
        float scalesEnd = mScales[mScales.Length - 1].time;
        float totalEnd = Mathf.Max(scalesEnd, Mathf.Max(offsetEnd, alphaEnd));

        // Adjust alpha and delete old entries
        for (int i = mList.Count; i > 0; )
        {
            Entry ent = mList[--i];
            float currentTime = time - ent.movementStart;
            ent.offset = offsetCurve.Evaluate(currentTime);
            ent.label.alpha = alphaCurve.Evaluate(currentTime);

            // Make the label scale in
            float s = scaleCurve.Evaluate(time - ent.time);
            if (s < 0.001f) s = 0.001f;
            ent.label.cachedTransform.localScale = new Vector3(s, s, s);

            // Delete the entry when needed超過一定時間刪除
            if (currentTime > totalEnd) Delete(ent);
            else ent.label.enabled = true;
        }

        float offset = 0f;

        // Move the entries
        for (int i = mList.Count; i > 0; )
        {
            Entry ent = mList[--i];
            offset = Mathf.Max(offset, ent.offset);
            ent.label.cachedTransform.localPosition = new Vector3(0f, offset, 0f);
            offset += Mathf.Round(ent.label.cachedTransform.localScale.y * ent.label.fontSize);
        }
    }

 

小技巧

1.升級API,可以在Assets---->Run API Update手動升級

2.當在Scene視圖里面調好我們想從Game視圖看到的樣子后,可以選中Main Camera---->GameObject---->Align With View瞬間把攝像機對齊這個畫面,使得Game視圖里面就是顯現我們要的畫面

3.Update()的刷新是按照每幀來顯示的,但是Time.deltaTime是按照秒來統計的。當Time.deltaTime*10.0f的時候,這個乘的結果表示是在1秒內從1不斷遞增到10

4.使用msyh字模就可以寫中文


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM