zoukankan      html  css  js  c++  java
  • 关于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.添加AssetsHUD TextScripts下的HUDText.cs和UIFollowTarget.cs脚本组件到HUDTextObj节点下

    7.设置HUDText的Bitmap Font字体属性为AssetsHUD TextExamplesAtlases下的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字模就可以写中文

  • 相关阅读:
    JQuery 中 某个标签 remove 时添加特效方法
    JQuery each 方法
    JQuery 中 animate() 方法使用
    final关键字
    坑爹之Server Farm
    正确使用Google英文版
    SQLServer2014下载地址
    微软这是要作死啊
    Why not me ?
    页面无法调试?
  • 原文地址:https://www.cnblogs.com/HangZhe/p/7475707.html
Copyright © 2011-2022 走看看