Skip to content

Instantly share code, notes, and snippets.

@adammyhre
Created August 24, 2025 09:23
Show Gist options
  • Select an option

  • Save adammyhre/382802233e66356c1bd4fe9183da2bab to your computer and use it in GitHub Desktop.

Select an option

Save adammyhre/382802233e66356c1bd4fe9183da2bab to your computer and use it in GitHub Desktop.
Unity 6.2 World Space UI
using System;
using System.Collections.Generic;
using TMPro;
using Unity.Cinemachine;
using UnityEngine;
using UnityEngine.UI;
using UnityUtils;
[DisallowMultipleComponent]
public class EnemyWorldUI : MonoBehaviour {
public enum FacingTarget { Camera, Player, Hybrid }
[Header("References")]
public Canvas canvas;
public TMP_Dropdown dropdown;
public Button button;
[Header("Behavior")]
public Transform player;
public Camera uiCamera;
[Min(0f)] public float triggerRadius = 5f;
public FacingTarget faceTarget = FacingTarget.Camera;
public string[] dropdownOptions = { "Talk", "Trade", "Inspect" };
[Header("Cinemachine")]
public CinemachineInputAxisController inputAxisController;
[Header("Group Easing")]
public CinemachineTargetGroup targetGroup;
[Min(0f)] public float groupWeight = 0.25f;
[Min(0f)] public float groupRadius = 0.5f;
float targetWeight, currentWeight, weightVelocity;
float targetRadius, currentRadius, radiusVelocity;
int targetGroupIndex = -1;
[Header("UI Fade")]
CanvasGroup canvasGroup;
bool pendingHide;
public float fadeSmoothTime = 0.2f;
float targetAlpha, currentAlpha, alphaVelocity;
SphereCollider trigger;
EnemyMover mover;
Action targetAction;
void Start() {
if (!player) player = GameObject.FindGameObjectWithTag("Player").transform;
if (!uiCamera) uiCamera = Camera.main;
trigger = gameObject.GetOrAdd<SphereCollider>();
trigger.isTrigger = true;
trigger.radius = triggerRadius;
mover = gameObject.GetOrAdd<EnemyMover>();
inputAxisController = player.GetComponentInChildren<CinemachineInputAxisController>();
UpdateTargetAction();
}
void UpdateTargetAction() {
targetAction = faceTarget switch {
FacingTarget.Camera => FaceCamera,
FacingTarget.Player => FacePlayer,
FacingTarget.Hybrid => FaceHybrid,
_ => null
};
}
void Update() {
UpdateTargetAction();
if (targetGroup && canvas) {
currentWeight = Mathf.SmoothDamp(currentWeight, targetWeight, ref weightVelocity, 0.25f);
currentRadius = Mathf.SmoothDamp(currentRadius, targetRadius, ref radiusVelocity, 0.25f);
ApplyGroupInfluence(currentWeight, currentRadius);
}
if (canvasGroup) {
currentAlpha = Mathf.SmoothDamp(currentAlpha, targetAlpha, ref alphaVelocity, fadeSmoothTime);
canvasGroup.alpha = currentAlpha;
bool interact = currentAlpha > 0.5f;
canvasGroup.interactable = interact;
canvasGroup.blocksRaycasts = interact;
}
if (pendingHide) {
bool alphaDone = !canvasGroup || currentAlpha <= 0.01f || Mathf.Approximately(currentAlpha, 0f);
if (alphaDone) {
canvas.gameObject.SetActive(false);
mover.Resume();
inputAxisController.enabled = true;
pendingHide = false;
}
}
}
void FacePlayer() {
if (!canvas || !player) return;
var toPlayer = canvas.transform.position - player.position;
var flat = Vector3.ProjectOnPlane(toPlayer, Vector3.up); // pitch=0, roll=0
if (flat.sqrMagnitude <= Vector3.kEpsilon) return;
canvas.transform.rotation = Quaternion.LookRotation(flat, Vector3.up);
}
void FaceHybrid() {
if (!canvas || !uiCamera) return;
var camFwdFlat = Vector3.ProjectOnPlane(uiCamera.transform.forward, Vector3.up);
if (camFwdFlat.sqrMagnitude <= Vector3.kEpsilon) return;
canvas.transform.rotation = Quaternion.LookRotation(camFwdFlat, Vector3.up);
}
void FaceCamera() {
if (!canvas || !uiCamera) return;
var toCam = canvas.transform.position - uiCamera.transform.position;
canvas.transform.rotation = Quaternion.LookRotation(toCam, Vector3.up);
}
void LateUpdate() {
if (canvas.gameObject.activeSelf) targetAction?.Invoke();
}
void OnTriggerEnter(Collider other) {
if (!other.CompareTag("Player")) return;
ShowUI();
}
void OnTriggerExit(Collider other) {
if (!other.CompareTag("Player")) return;
HideUI();
}
void ApplyGroupInfluence(float weight, float radius) {
if (!targetGroup) return;
int idx = targetGroupIndex >= 0 ? targetGroupIndex : targetGroup.FindMember(canvas.transform);
if (idx < 0) return;
var targets = targetGroup.Targets;
var t = targets[idx];
t.Weight = weight;
t.Radius = radius;
targets[idx] = t;
targetGroup.Targets = targets;
targetGroupIndex = idx;
}
void ShowUI() {
canvas.gameObject.SetActive(true);
mover.Pause();
inputAxisController.enabled = false;
targetWeight = groupWeight;
targetRadius = groupRadius;
targetAlpha = 1f;
}
void HideUI() {
targetWeight = 0f;
targetRadius = 0f;
targetAlpha = 0f;
pendingHide = true;
}
void OnEnable() {
if (!canvas) {
Debug.LogError("[EnemyEmbeddedUI] Canvas reference missing.", this);
return;
}
canvas.renderMode = RenderMode.WorldSpace;
canvas.worldCamera = uiCamera;
canvas.gameObject.SetActive(false);
if (!canvasGroup) canvas.TryGetComponent(out canvasGroup);
if (canvasGroup) {
currentAlpha = targetAlpha = 0f;
alphaVelocity = 0f;
canvasGroup.alpha = 0f;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
}
if (dropdown) {
if (!dropdown.template) {
dropdown.template = dropdown.transform.Find("Template") as RectTransform;
}
if (dropdown.template.gameObject.activeSelf) dropdown.template.gameObject.SetActive(false);
dropdown.onValueChanged.RemoveAllListeners();
dropdown.options.Clear();
foreach (var o in dropdownOptions) dropdown.options.Add(new TMP_Dropdown.OptionData(o));
dropdown.onValueChanged.AddListener(i => Debug.Log($"[{name}] {dropdown.options[i].text}"));
dropdown.RefreshShownValue();
}
if (button) {
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => Debug.Log($"[{name}] Click me"));
}
if (targetGroup && canvas) {
targetGroup.AddMember(canvas.transform, 0f, 0f);
currentWeight = targetWeight = 0f;
currentRadius = targetRadius = 0f;
weightVelocity = radiusVelocity = 0f;
targetGroupIndex = targetGroup.FindMember(canvas.transform);
}
}
void OnDisable() {
HideUI();
if (targetGroup && canvas) {
targetGroup.RemoveMember(canvas.transform);
targetGroupIndex = -1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment