Hi all,
I’ve been making a small system to show UI elements on a canvas in the position of game objects in the world.
I’m trying to make it pretty flexible and I’m just looking for general advice for improvements or rework of this system to improve flexibility and/or performance.
Here is a script I’ve been putting on the game objects in the world:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PointOfInterest : MonoBehaviour
{
public GameObject pOIIconPrefab;
public Vector3 offset = new Vector3(0, 0, 0);
public bool iconSpawned;
[HideInInspector]
public Image icon;
}
This just holds the icon to use, an offset and if the icon has been instantiated onto the canvas or not.
Here’s a script I’ve placed on the player to display the points of interest icons on a canvas:
using Cinemachine;
using Cinemachine;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerDisplayPointsOfInterest : MonoBehaviour
{
[SerializeField] Canvas canvas;
[SerializeField] Camera playerCamera;
[SerializeField] float viewRange = 5f;
[SerializeField] float interactRange = 2f;
private void Awake()
{
// Using the CameraUpdateEvent from Cinemachine to prevent elements lagging behind-
// -when vSync is on
CinemachineCore.CameraUpdatedEvent.AddListener(DrawGUI);
}
void DrawGUI(CinemachineBrain arg0)
{
Collider[] colliderArray = Physics.OverlapSphere(transform.position, viewRange);
foreach (Collider col in colliderArray)
{
if (col.TryGetComponent(out PointOfInterest poi))
{
if (poi.iconSpawned == false && Vector3.Distance(col.transform.position, playerCamera.transform.position) <= viewRange)
{
poi.icon = Instantiate(poi.pOIIconPrefab, canvas.transform).GetComponent<Image>();
poi.icon.transform.SetAsFirstSibling();
poi.iconSpawned = true;
}
else if (poi.iconSpawned == true && Vector3.Distance(col.transform.position, playerCamera.transform.position) > viewRange && poi.icon != null)
{
Destroy(poi.icon.gameObject);
poi.iconSpawned = false;
continue;
}
if (poi.iconSpawned == true)
{
poi.icon.transform.position = playerCamera.WorldToScreenPoint(poi.transform.position + poi.offset);
}
}
}
}
}
As you can see, this is using Cinemachine and I’m running the update method when the camera updates. This was just to solve an issue to do with the order of execution which was causing the icons to lag behind a little.
Is this a bit excessive for an icons system? I feel like there’s a lot going on and there may be a simpler and more performant way of doing it.
These scripts are fully working however and I could just be overthinking it, so obviously feel free to use this code if you have a use for it.
Thanks!