在Unity中创建和优化Head Health Bars

发表于2017-05-23
评论1 951浏览

目的

本篇文章要传到的想法只有一个, 关于创建和优化游戏 (特别是第三人游戏)中的 Head Health Bars。

 

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

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


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

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

 

容易吗?

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

案例测试 1

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

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

下面的图像显示相同︰


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


[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class PlayerGenerator : MonoBehaviour {  
  5.   
  6. public GameObject playerPrefab;  
  7. public GameObject healthBarPrefab;  
  8.   
  9. public Transform playersParent;  
  10. public RectTransform healthPanelRect;  
  11.   
  12. void Start()  
  13. {  
  14. GeneratePlayers();  
  15. }  
  16.   
  17. private void GeneratePlayers()  
  18. {  
  19. Vector3 position = new Vector3(3.75f,6.5f,5.0f);  
  20. for (int i = 0; i < 10; i++)  
  21. {  
  22. position -= new Vector3(0,0.6f,0.90f);  
  23. for (int j = 0; j < 10; j++)  
  24. {  
  25. GeneratePlayerAt(position);  
  26. position -= new Vector3(0.85f,0,0);  
  27. }  
  28. position = new Vector3(3.75f,position.y,position.z);  
  29. }  
  30. }  
  31.   
  32. private void GeneratePlayerAt(Vector3 position)  
  33. {  
  34. GameObject player = Instantiate(playerPrefab, position, Quaternion.identity) as GameObject;  
  35. player.transform.parent = playersParent;  
  36. }  
  37. }  


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

PlayerMovement.cs 


[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class PlayerMovement : MonoBehaviour {  
  5.   
  6.     public float speed=5;  
  7.     public Vector3 direction=new Vector3(0,1,0);  
  8.     // Update is called once per frame  
  9.     void Update () {  
  10.         transform.Translate(direction * speed * Time.deltaTime);  
  11.     }  
  12. }  
我们要看场景当前的FPS ,  工具脚本如下:

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

HUDFPS.cs 

[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using UnityEngine.UI;  
  4. public class HUDFPS : MonoBehaviour  
  5. {  
  6.   
  7.     // Attach this to a GUIText to make a frames/second indicator.  
  8.     //  
  9.     // It calculates frames/second over each updateInterval,  
  10.     // so the display doesz not keep changing wildly.  
  11.     //  
  12.     // It is also fairly accurate at very low FPS counts (<10).  
  13.     // We do this not by simply counting frames per interval, but  
  14.     // by accumulating FPS for each frame. This way we end up with  
  15.     // correct overall FPS even if the interval renders something like  
  16.     // 5.5 frames.  
  17.   
  18.     public float updateInterval = 0.5F;  
  19.     public Text t;  
  20.     private float accum = 0; // FPS accumulated over the interval  
  21.     private int frames = 0; // Frames drawn over the interval  
  22.     private float timeleft; // Left time for current interval  
  23.   
  24.     void Start()  
  25.     {  
  26.         if (!GetComponent())  
  27.         {  
  28.             Debug.Log("UtilityFramesPerSecond needs a GUIText component!");  
  29.             enabled = false;  
  30.             return;  
  31.         }  
  32.         timeleft = updateInterval;  
  33.         t = GetComponent();  
  34.     }  
  35.   
  36.     void Update()  
  37.     {  
  38.         timeleft -= Time.deltaTime;  
  39.         accum += Time.timeScale / Time.deltaTime;  
  40.         ++frames;  
  41.   
  42.         // Interval ended - update GUI text and start new interval  
  43.         if (timeleft <= 0.0)  
  44.         {  
  45.             // display two fractional digits (f2 format)  
  46.             float fps = accum / frames;  
  47.             string format = System.String.Format("{0:F2} FPS", fps);  
  48.             t.text = format;  
  49.   
  50.             if (fps < 30)  
  51.                 t.color = Color.yellow;  
  52.             else  
  53.                 if (fps < 10)  
  54.                 t.color = Color.red;  
  55.             else  
  56.                 t.color = Color.green;  
  57.             //DebugConsole.Log(format, level);  
  58.             timeleft = updateInterval;  
  59.             accum = 0.0F;  
  60.             frames = 0;  
  61.         }  
  62.     }  
  63. }  


我的手机显示 fps 约 30 FPS。



让我们看一看探查器

Canvas.SendWillRenderCanvases()占用 14 毫秒,

Canvas.builtBatch                               需要 6.76ms,

Canas.Render                                      需要 5.88ms。


 

解决方法?

如何使用single overlay canvas

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



案例测试 2

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

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

[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using UnityEngine.UI;  
  4. public class HealthBar : MonoBehaviour {  
  5.  
  6.     #region PRIVATE_VARIABLES  
  7.     private Vector2 positionCorrection = new Vector2(0, 100);  
  8.     #endregion  
  9.  
  10.     #region PUBLIC_REFERENCES  
  11.     public RectTransform targetCanvas;  
  12.     public RectTransform healthBar;  
  13.     public Transform objectToFollow;  
  14.  
  15.     #endregion  
  16.  
  17.     #region PUBLIC_METHODS  
  18.     public void SetHealthBarData(Transform targetTransform,RectTransform healthBarPanel)  
  19.     {  
  20.         this.targetCanvas = healthBarPanel;  
  21.         healthBar = GetComponent();  
  22.         objectToFollow = targetTransform;  
  23.         RepositionHealthBar();  
  24.         healthBar.gameObject.SetActive(true);  
  25.     }  
  26.   
  27.     public void OnHealthChanged(float healthFill)  
  28.     {  
  29.         healthBar.GetComponent().fillAmount = healthFill;  
  30.     }  
  31.     #endregion  
  32.  
  33.     #region UNITY_CALLBACKS  
  34.     void Update()  
  35.     {  
  36.         RepositionHealthBar();  
  37.     }  
  38.     #endregion  
  39.  
  40.     #region PRIVATE_METHODS  
  41.   
  42.     private void RepositionHealthBar()  
  43.     {  
  44.         Vector2 ViewportPosition = Camera.main.WorldToViewportPoint(objectToFollow.position);  
  45.         Vector2 WorldObject_ScreenPosition = new Vector2(  
  46.         ((ViewportPosition.x * targetCanvas.sizeDelta.x) - (targetCanvas.sizeDelta.x * 0.5f)),  
  47.         ((ViewportPosition.y * targetCanvas.sizeDelta.y) - (targetCanvas.sizeDelta.y * 0.5f)));  
  48.   
  49.         //now you can set the position of the ui element  
  50.         healthBar.anchoredPosition = WorldObject_ScreenPosition;  
  51.     }  
  52.     #endregion  
  53. }  

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

[csharp] view plain copy
 print?
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class PlayerGenerator : MonoBehaviour {  
  5.   
  6.     public GameObject playerPrefab;  
  7.     public GameObject healthBarPrefab;  
  8.   
  9.     public Transform playersParent;  
  10.     public RectTransform healthPanelRect;  
  11.   
  12.     void Start()  
  13.     {  
  14.         GeneratePlayers();  
  15.     }  
  16.   
  17.     private void GeneratePlayers()  
  18.     {  
  19.         Vector3 position = new Vector3(3.75f,6.5f,5.0f);  
  20.         for (int i = 0; i < 10; i++)  
  21.         {  
  22.             position -= new Vector3(0,0.6f,0.90f);  
  23.             for (int j = 0; j < 10; j++)  
  24.             {  
  25.                 GeneratePlayerAt(position);  
  26.                 position -= new Vector3(0.85f,0,0);  
  27.             }  
  28.             position = new Vector3(3.75f,position.y,position.z);  
  29.         }  
  30.     }  
  31.   
  32.     private void GeneratePlayerAt(Vector3 position)  
  33.     {  
  34.         GameObject player = Instantiate(playerPrefab, position, Quaternion.identity) as GameObject;  
  35.         player.transform.parent = playersParent;  
  36.     }  
  37.   
  38.     private void GeneratePlayerHealthBar(Transform player)  
  39.     {  
  40.         GameObject healthBar = Instantiate(healthBarPrefab) as GameObject;  
  41.         healthBar.GetComponent().SetHealthBarData(player, healthPanelRect);  
  42.         healthBar.transform.SetParent(healthPanelRect, false);  
  43.     }  
  44. }  


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


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

提升了  20 fps !!!!!



让我们现在检查探查器。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引