目的
本篇文章要传到的想法只有一个, 关于创建和优化游戏 (特别是第三人游戏)中的 Head Health Bars。
Head Health Bars?是真的没什么大不了?
理想的例子使用Head Health Bars的地方就是帝国时代(如下图所示的屏幕)。
会出现的问题就是 FPS 很低!!!!!
很多人的做法可能是在 每个角色上添加 world space canvas 这个UGUI !
容易吗?
让我们理解这一些案例,然后最后讨论出一个理想的解决方案。
案例测试 1
让我们生成 100 个角色。(在我的例子中使用球体)
创建角色与world canvas作为角色的子对象(像下图一样设置Canvas 和 Image)
下面的图像显示相同︰
在这里有一个 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);
-
- void Update () {
- transform.Translate(direction * speed * Time.deltaTime);
- }
- }
我们要看场景当前的FPS , 工具脚本如下: 同时为脚本赋值(在编辑器中)
HUDFPS.cs
- using UnityEngine;
- using System.Collections;
- using UnityEngine.UI;
- public class HUDFPS : MonoBehaviour
- {
-
-
-
-
-
-
-
-
-
-
-
-
- public float updateInterval = 0.5F;
- public Text t;
- private float accum = 0;
- private int frames = 0;
- private float timeleft;
-
- void Start()
- {
- if (!GetComponent())
- {
- Debug.Log("UtilityFramesPerSecond needs a GUIText component!");
- enabled = false;
- return;
- }
- timeleft = updateInterval;
- t = GetComponent();
- }
-
- void Update()
- {
- timeleft -= Time.deltaTime;
- accum += Time.timeScale / Time.deltaTime;
- ++frames;
-
-
- if (timeleft <= 0.0)
- {
-
- 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;
-
- timeleft = updateInterval;
- accum = 0.0F;
- frames = 0;
- }
- }
- }
我的手机显示 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 脚本,如下所示,并将其附加到刚刚的预制体上:
- 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();
- objectToFollow = targetTransform;
- RepositionHealthBar();
- healthBar.gameObject.SetActive(true);
- }
-
- public void OnHealthChanged(float healthFill)
- {
- healthBar.GetComponent().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)));
-
-
- 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().SetHealthBarData(player, healthPanelRect);
- healthBar.transform.SetParent(healthPanelRect, false);
- }
- }
每创建一个角色,同时也创建一个 health bar 然后位置放到头顶位置!
现在,让我们在移动设备上测试它。
提升了 20 fps !!!!!
让我们现在检查探查器。