first commit
This commit is contained in:
20
NitroxClient/MonoBehaviours/Gui/HUD/DenyOwnershipHand.cs
Normal file
20
NitroxClient/MonoBehaviours/Gui/HUD/DenyOwnershipHand.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.HUD;
|
||||
|
||||
public class DenyOwnershipHand : MonoBehaviour
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
// Forces the message to go away after a few seconds.
|
||||
Destroy(this, 2);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
//TODO: Check if this should be Hand
|
||||
HandReticle.main.SetText(HandReticle.TextType.Hand, "Nitrox_DenyOwnershipHand", true);
|
||||
HandReticle.main.SetText(HandReticle.TextType.HandSubscript, string.Empty, false);
|
||||
HandReticle.main.SetIcon(HandReticle.IconType.HandDeny);
|
||||
}
|
||||
}
|
287
NitroxClient/MonoBehaviours/Gui/HUD/RemotePlayerVitals.cs
Normal file
287
NitroxClient/MonoBehaviours/Gui/HUD/RemotePlayerVitals.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
using System;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.HUD;
|
||||
|
||||
public class RemotePlayerVitals : MonoBehaviour
|
||||
{
|
||||
private static readonly Color OXYGEN_BAR_COLOR = new(0.168f, 0.666f, 0.60f, 1.0f);
|
||||
private static readonly Color OXYGEN_BAR_BORDER_COLOR = new(0.227f, 0.949f, 0.969f, 1.0f);
|
||||
private static readonly Color HEALTH_BAR_COLOR = new(0.859f, 0.373f, 0.251f, 1.0f);
|
||||
private static readonly Color HEALTH_BAR_BORDER_COLOR = new(0.824f, 0.651f, 0.424f, 1.0f);
|
||||
private static readonly Color FOOD_BAR_COLOR = new(0.965f, 0.655f, 0.149f, 1.0f);
|
||||
private static readonly Color FOOD_BAR_BORDER_COLOR = new(0.957f, 0.914f, 0.251f, 1.0f);
|
||||
private static readonly Color WATER_BAR_COLOR = new(0.212f, 0.663f, 0.855f, 1.0f);
|
||||
private static readonly Color WATER_BAR_BORDER_COLOR = new(0.227f, 0.949f, 0.969f, 1.0f);
|
||||
private Canvas canvas;
|
||||
private Bar foodBar;
|
||||
private Bar healthBar;
|
||||
private Bar oxygenBar;
|
||||
|
||||
private string playerName;
|
||||
|
||||
private Bar waterBar;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a player vitals UI elements for the player id.
|
||||
/// </summary>
|
||||
/// <param name="playerId">Unique player id to create the vitals UI elements for.</param>
|
||||
public static RemotePlayerVitals CreateForPlayer(RemotePlayer remotePlayer)
|
||||
{
|
||||
RemotePlayerVitals vitals = new GameObject("RemotePlayerVitals").AddComponent<RemotePlayerVitals>();
|
||||
|
||||
try
|
||||
{
|
||||
vitals.canvas = vitals.CreateCanvas(remotePlayer.Body.transform);
|
||||
|
||||
vitals.playerName = remotePlayer.PlayerName;
|
||||
vitals.CreatePlayerName(vitals.canvas);
|
||||
vitals.CreateStats(vitals.canvas);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Encountered an error while creating vitals for player {remotePlayer.PlayerId}, destroying them.");
|
||||
Destroy(vitals.gameObject);
|
||||
return null;
|
||||
}
|
||||
|
||||
return vitals;
|
||||
}
|
||||
|
||||
public void SetStatsVisible(bool visible)
|
||||
{
|
||||
oxygenBar.SetVisible(visible);
|
||||
healthBar.SetVisible(visible);
|
||||
foodBar.SetVisible(visible);
|
||||
waterBar.SetVisible(visible);
|
||||
}
|
||||
|
||||
public void SetOxygen(float oxygen, float maxOxygen)
|
||||
{
|
||||
oxygenBar.SetTargetValue(oxygen);
|
||||
oxygenBar.SetMaxValue(maxOxygen);
|
||||
}
|
||||
|
||||
public void SetHealth(float health)
|
||||
{
|
||||
healthBar.SetTargetValue(health);
|
||||
}
|
||||
|
||||
public void SetFood(float food)
|
||||
{
|
||||
foodBar.SetTargetValue(food);
|
||||
}
|
||||
|
||||
public void SetWater(float water)
|
||||
{
|
||||
waterBar.SetTargetValue(water);
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
oxygenBar.UpdateVisual();
|
||||
healthBar.UpdateVisual();
|
||||
foodBar.UpdateVisual();
|
||||
waterBar.UpdateVisual();
|
||||
|
||||
// Make canvas face camera.
|
||||
Camera camera = Camera.main;
|
||||
if (canvas && camera)
|
||||
{
|
||||
canvas.transform.forward = camera.transform.forward;
|
||||
}
|
||||
}
|
||||
|
||||
private Canvas CreateCanvas(Transform playerTransform)
|
||||
{
|
||||
// Canvas
|
||||
transform.SetParent(playerTransform, false);
|
||||
transform.localPosition = new Vector3(0, 0, 0);
|
||||
|
||||
Canvas vitalsCanvas = gameObject.AddComponent<Canvas>();
|
||||
vitalsCanvas.renderMode = RenderMode.WorldSpace;
|
||||
|
||||
CanvasScaler scaler = gameObject.AddComponent<CanvasScaler>();
|
||||
scaler.dynamicPixelsPerUnit = 100;
|
||||
|
||||
return vitalsCanvas;
|
||||
}
|
||||
|
||||
private void CreateStats(Canvas canvas)
|
||||
{
|
||||
// uGUI is a script at the topmost of the uGUI(Clone) object which contains the uGUI_ classes whe're looking for
|
||||
uGUI uGUI = uGUI.main;
|
||||
if (!uGUI)
|
||||
{
|
||||
throw new NullReferenceException($"[{nameof(RemotePlayerVitals)}] Couldn't find uGUI main instance when creating vitals");
|
||||
}
|
||||
healthBar = CreateBar(uGUI.GetComponentInChildren<uGUI_HealthBar>(true), canvas);
|
||||
oxygenBar = CreateBar(uGUI.GetComponentInChildren<uGUI_OxygenBar>(true), canvas);
|
||||
foodBar = CreateBar(uGUI.GetComponentInChildren<uGUI_FoodBar>(true), canvas);
|
||||
waterBar = CreateBar(uGUI.GetComponentInChildren<uGUI_WaterBar>(true), canvas);
|
||||
}
|
||||
|
||||
private Bar CreateBar<T>(T barBehaviour, Canvas canvas) where T : MonoBehaviour
|
||||
{
|
||||
GameObject originalBar = barBehaviour.gameObject;
|
||||
GameObject cloned = Instantiate(originalBar, canvas.transform, true);
|
||||
|
||||
uGUI_CircularBar newBar = cloned.GetComponentInChildren<uGUI_CircularBar>(true);
|
||||
newBar.texture = originalBar.GetComponentInChildren<uGUI_CircularBar>(true).texture;
|
||||
newBar.overlay = originalBar.GetComponentInChildren<uGUI_CircularBar>(true).overlay;
|
||||
|
||||
cloned.transform.localRotation = Quaternion.identity;
|
||||
// From uGUI_OxygenBar.Awake
|
||||
if (cloned.TryGetComponentInChildren(out TextMeshProUGUI text, true))
|
||||
{
|
||||
text.enableCulling = true;
|
||||
}
|
||||
|
||||
switch (barBehaviour)
|
||||
{
|
||||
case uGUI_HealthBar:
|
||||
newBar.color = HEALTH_BAR_COLOR;
|
||||
newBar.borderColor = HEALTH_BAR_BORDER_COLOR;
|
||||
cloned.transform.localPosition = new Vector3(-0.05f, 0.33f, 0f);
|
||||
cloned.transform.localScale = new Vector3(0.0014f, 0.0014f, 1f);
|
||||
break;
|
||||
case uGUI_OxygenBar:
|
||||
newBar.color = OXYGEN_BAR_COLOR;
|
||||
newBar.borderColor = OXYGEN_BAR_BORDER_COLOR;
|
||||
cloned.transform.localPosition = new Vector3(0.05f, 0.33f, 0f);
|
||||
cloned.transform.localScale = new Vector3(0.0006f, 0.0006f, 1f);
|
||||
// PulseWave is only present for uGUI_OxygenBar
|
||||
Destroy(cloned.FindChild("PulseWave"));
|
||||
break;
|
||||
case uGUI_FoodBar:
|
||||
newBar.color = FOOD_BAR_COLOR;
|
||||
newBar.borderColor = FOOD_BAR_BORDER_COLOR;
|
||||
cloned.transform.localPosition = new Vector3(-0.05f, 0.255f, 0f);
|
||||
cloned.transform.localScale = new Vector3(0.0014f, 0.0014f, 1f);
|
||||
break;
|
||||
case uGUI_WaterBar:
|
||||
newBar.color = WATER_BAR_COLOR;
|
||||
newBar.borderColor = WATER_BAR_BORDER_COLOR;
|
||||
cloned.transform.localPosition = new Vector3(0.05f, 0.255f, 0f);
|
||||
cloned.transform.localScale = new Vector3(0.0014f, 0.0014f, 1f);
|
||||
break;
|
||||
default:
|
||||
Log.Info($"Unhandled bar type: {barBehaviour.GetType()}");
|
||||
break;
|
||||
}
|
||||
|
||||
Destroy(cloned.FindChild("PulseHalo"));
|
||||
Destroy(cloned.GetComponent<T>());
|
||||
cloned.SetActive(true);
|
||||
return new Bar(cloned, 100f, 100f, 0.1f);
|
||||
}
|
||||
|
||||
private void CreatePlayerName(Canvas canvas)
|
||||
{
|
||||
// Text
|
||||
GameObject nameObject = new("RemotePlayerName");
|
||||
nameObject.transform.parent = canvas.transform;
|
||||
|
||||
Text nameText = nameObject.AddComponent<Text>();
|
||||
nameText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
nameText.text = playerName;
|
||||
Transform nameTransform = nameText.transform;
|
||||
nameTransform.localScale = new Vector3(0.015f, 0.015f, 1f);
|
||||
nameTransform.rotation = canvas.transform.rotation;
|
||||
nameText.fontSize = 14;
|
||||
nameText.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
// Text position
|
||||
RectTransform namePosition = nameObject.GetComponent<RectTransform>();
|
||||
namePosition.localPosition = new Vector3(0, 0.4f, 0);
|
||||
namePosition.sizeDelta = new Vector2(200, 100);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Must stay optional in case the destroy originates from a broken object
|
||||
oxygenBar?.Dispose();
|
||||
healthBar?.Dispose();
|
||||
foodBar?.Dispose();
|
||||
waterBar?.Dispose();
|
||||
}
|
||||
|
||||
private class Bar : IDisposable
|
||||
{
|
||||
private readonly GameObject gameObject;
|
||||
private readonly uGUI_CircularBar circularBar;
|
||||
private readonly TextMeshProUGUI text;
|
||||
|
||||
private bool isDisposed;
|
||||
private float vel;
|
||||
private float current;
|
||||
private float target;
|
||||
private float maximum;
|
||||
private float smoothTime;
|
||||
|
||||
public Bar(GameObject gameObject, float current, float maximum, float smoothTime)
|
||||
{
|
||||
this.gameObject = gameObject;
|
||||
this.current = current;
|
||||
target = current;
|
||||
this.maximum = maximum;
|
||||
this.smoothTime = smoothTime;
|
||||
|
||||
circularBar = gameObject.GetComponentInChildren<uGUI_CircularBar>(true);
|
||||
// text can be null
|
||||
text = gameObject.GetComponentInChildren<TextMeshProUGUI>(true);
|
||||
}
|
||||
|
||||
public void SetTargetValue(float value)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
target = value;
|
||||
}
|
||||
|
||||
public void SetMaxValue(float maxValue)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
maximum = maxValue;
|
||||
}
|
||||
|
||||
public void UpdateVisual()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
// Adapted from uGUI_OxygenBar
|
||||
float percentage = Mathf.Clamp01(target / maximum);
|
||||
current = Mathf.SmoothDamp(current, percentage, ref vel, smoothTime);
|
||||
circularBar.value = current;
|
||||
if (text)
|
||||
{
|
||||
text.SetText(IntStringCache.GetStringForInt(Mathf.RoundToInt(target)));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVisible(bool visible)
|
||||
{
|
||||
gameObject.SetActive(visible);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
isDisposed = true;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException("Tried to update visual on a disposed player stat.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user