IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [译]在Unity中创建和优化Head Health Bars

    u010019717发表于 2017-05-13 18:05:58
    love 0

    孙广东  2017.3.27

    http://blog.csdn.NET/u010019717


    翻译自:http://www.theappguruz.com/blog/create-and-optimize-on-head-health-bars-in-unity  



    目的

    这篇博客的主要目的是要给你一个想法, 关于创建和优化你游戏 (特别是第三人游戏)中的 Head Health Bars。

     

    如果你想要学习如何优化你的游戏,你可以查阅这篇博客︰

    • Unity游戏的的最新优化倡议。

     

    Head Health Bars?是真的没什么大不了?

    理想的例子使用Head Health Bars的地方就是帝国时代(如下图所示的屏幕)。

    Health Bars Age of Empires


    会出现的问题就是 FPS 很低!!!!!

    很多人的做法可能是在 每个角色上添加 world space canvas 这个UGUI !

     

    容易吗?

    让我们理解这一些案例,然后最后讨论出一个理想的解决方案。

    案例测试 1

    让我们生成 100 个角色。(在我的例子中使用球体)

    创建角色与world canvas作为角色的子对象(像下图一样设置Canvas 和 Image)

    下面的图像显示相同︰

    Health Bars on world Canvas


    在这里有一个  PlayerGenerate.cs    脚本,生成的100个角色的代码


    using UnityEngine;
    using System.Collections;
    
    public class PlayerGenerator : MonoBehaviour {
    
    public GameObject playerPrefab;
    public GameObject healthBarPrefab;
    
    public Transform playersParent;
    public RectTransform healthPanelRect;
    
    void Start()
    {
    GeneratePlayers();
    }
    
    private void GeneratePlayers()
    {
    Vector3 position = new Vector3(3.75f,6.5f,5.0f);
    for (int i = 0; i < 10; i++)
    {
    position -= new Vector3(0,0.6f,0.90f);
    for (int j = 0; j < 10; j++)
    {
    GeneratePlayerAt(position);
    position -= new Vector3(0.85f,0,0);
    }
    position = new Vector3(3.75f,position.y,position.z);
    }
    }
    
    private void GeneratePlayerAt(Vector3 position)
    {
    GameObject player = Instantiate(playerPrefab, position, Quaternion.identity) as GameObject;
    player.transform.parent = playersParent;
    }
    }
    


    此外让每个玩家运动起来, 把以下脚本附加到角色上。

    PlayerMovement.cs 


    using UnityEngine;
    using System.Collections;
    
    public class PlayerMovement : MonoBehaviour {
    
        public float speed=5;
        public Vector3 direction=new Vector3(0,1,0);
        // Update is called once per frame
        void Update () {
            transform.Translate(direction * speed * Time.deltaTime);
        }
    }
    
    
    我们要看场景当前的FPS ,  工具脚本如下:

                同时为脚本赋值(在编辑器中)

    HUDFPS.cs 

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    public class HUDFPS : MonoBehaviour
    {
    
        // Attach this to a GUIText to make a frames/second indicator.
        //
        // It calculates frames/second over each updateInterval,
        // so the display doesz not keep changing wildly.
        //
        // It is also fairly accurate at very low FPS counts (<10).
        // We do this not by simply counting frames per interval, but
        // by accumulating FPS for each frame. This way we end up with
        // correct overall FPS even if the interval renders something like
        // 5.5 frames.
    
        public float updateInterval = 0.5F;
        public Text t;
        private float accum = 0; // FPS accumulated over the interval
        private int frames = 0; // Frames drawn over the interval
        private float timeleft; // Left time for current interval
    
        void Start()
        {
            if (!GetComponent<Text>())
            {
                Debug.Log("UtilityFramesPerSecond needs a GUIText component!");
                enabled = false;
                return;
            }
            timeleft = updateInterval;
            t = GetComponent<Text>();
        }
    
        void Update()
        {
            timeleft -= Time.deltaTime;
            accum += Time.timeScale / Time.deltaTime;
            ++frames;
    
            // Interval ended - update GUI text and start new interval
            if (timeleft <= 0.0)
            {
                // display two fractional digits (f2 format)
                float fps = accum / frames;
                string format = System.String.Format("{0:F2} FPS", fps);
                t.text = format;
    
                if (fps < 30)
                    t.color = Color.yellow;
                else
                    if (fps < 10)
                    t.color = Color.red;
                else
                    t.color = Color.green;
                //DebugConsole.Log(format, level);
                timeleft = updateInterval;
                accum = 0.0F;
                frames = 0;
            }
        }
    }
    
    


    我的手机显示 fps 约 30 FPS。


    Unoptimized Multiple world Canvases


    让我们看一看探查器

    Unoptimized case profiler reading

    Canvas.SendWillRenderCanvases()占用 14 毫秒,

    Canvas.builtBatch                               需要 6.76ms,

    Canas.Render                                      需要 5.88ms。


     

    解决方法?

    如何使用single overlay canvas?

    计算出的位置,只需将health bar图像放在每个角色?



    案例测试 2

    1) 创建一个 health bar 预制体  内容就是一个简单的图像。

    2) 现在创建   HealthBar.cs    脚本,如下所示,并将其附加到刚刚的预制体上:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    public class HealthBar : MonoBehaviour {
    
        #region PRIVATE_VARIABLES
        private Vector2 positionCorrection = new Vector2(0, 100);
        #endregion
    
        #region PUBLIC_REFERENCES
        public RectTransform targetCanvas;
        public RectTransform healthBar;
        public Transform objectToFollow;
    
        #endregion
    
        #region PUBLIC_METHODS
        public void SetHealthBarData(Transform targetTransform,RectTransform healthBarPanel)
        {
            this.targetCanvas = healthBarPanel;
            healthBar = GetComponent<RectTransform>();
            objectToFollow = targetTransform;
            RepositionHealthBar();
            healthBar.gameObject.SetActive(true);
        }
    
        public void OnHealthChanged(float healthFill)
        {
            healthBar.GetComponent<Image>().fillAmount = healthFill;
        }
        #endregion
    
        #region UNITY_CALLBACKS
        void Update()
        {
            RepositionHealthBar();
        }
        #endregion
    
        #region PRIVATE_METHODS
    
        private void RepositionHealthBar()
        {
            Vector2 ViewportPosition = Camera.main.WorldToViewportPoint(objectToFollow.position);
            Vector2 WorldObject_ScreenPosition = new Vector2(
            ((ViewportPosition.x * targetCanvas.sizeDelta.x) - (targetCanvas.sizeDelta.x * 0.5f)),
            ((ViewportPosition.y * targetCanvas.sizeDelta.y) - (targetCanvas.sizeDelta.y * 0.5f)));
    
            //now you can set the position of the ui element
            healthBar.anchoredPosition = WorldObject_ScreenPosition;
        }
        #endregion
    }
    
    

    3) 修改以前的PlayerGenerator.cs脚本,如下所示。

    using UnityEngine;
    using System.Collections;
    
    public class PlayerGenerator : MonoBehaviour {
    
        public GameObject playerPrefab;
        public GameObject healthBarPrefab;
    
        public Transform playersParent;
        public RectTransform healthPanelRect;
    
        void Start()
        {
            GeneratePlayers();
        }
    
        private void GeneratePlayers()
        {
            Vector3 position = new Vector3(3.75f,6.5f,5.0f);
            for (int i = 0; i < 10; i++)
            {
                position -= new Vector3(0,0.6f,0.90f);
                for (int j = 0; j < 10; j++)
                {
                    GeneratePlayerAt(position);
                    position -= new Vector3(0.85f,0,0);
                }
                position = new Vector3(3.75f,position.y,position.z);
            }
        }
    
        private void GeneratePlayerAt(Vector3 position)
        {
            GameObject player = Instantiate(playerPrefab, position, Quaternion.identity) as GameObject;
            player.transform.parent = playersParent;
        }
    
        private void GeneratePlayerHealthBar(Transform player)
        {
            GameObject healthBar = Instantiate(healthBarPrefab) as GameObject;
            healthBar.GetComponent<HealthBar>().SetHealthBarData(player, healthPanelRect);
            healthBar.transform.SetParent(healthPanelRect, false);
        }
    }
    
    
    


       每创建一个角色,同时也创建一个 health bar 然后位置放到头顶位置!


    现在,让我们在移动设备上测试它。

    Multiple Health Bar images on single canvas

    提升了  20 fps !!!!!



    让我们现在检查探查器。

    Optimized profiler reading







沪ICP备19023445号-2号
友情链接