projectEli/Assets/NeoFPS/Core/HUD/HudShieldMeter.cs

146 lines
4.8 KiB
C#
Raw Normal View History

2022-11-07 01:28:33 +00:00
using System;
using System.Collections.Generic;
using UnityEngine;
namespace NeoFPS
{
[HelpURL("https://docs.neofps.com/manual/hudref-mb-hudshieldmeter.html")]
[RequireComponent(typeof(RectTransform))]
public class HudShieldMeter : PlayerCharacterHudBase
{
[SerializeField, Tooltip("A shield meter step (in the object hierarchy) that can be duplicated for multiple steps.")]
private HudShieldMeterStep m_StepPrototype = null;
private List<HudShieldMeterStep> m_Steps = null;
protected IShieldManager shield
{
get;
private set;
}
private void OnValidate()
{
if (m_StepPrototype == null)
m_StepPrototype = GetComponentInChildren<HudShieldMeterStep>(true);
}
public override void OnPlayerCharacterChanged(ICharacter character)
{
// Remove old steps objects
if (m_Steps != null)
{
for (int i = 1; i < m_Steps.Count; ++i)
Destroy(m_Steps[i].gameObject);
m_Steps = null;
}
// Unsubscribe from old shield
if (shield != null)
{
shield.onShieldValueChanged -= OnShieldValueChangedInternal;
shield.onShieldStateChanged -= OnShieldStateChanged;
shield.onShieldConfigChanged -= OnShieldConfigChanged;
}
// Get new shield
if (character != null && m_StepPrototype != null)
{
shield = character.GetComponent<IShieldManager>();
if (shield != null)
{
// Subscribe
shield.onShieldValueChanged += OnShieldValueChangedInternal;
shield.onShieldStateChanged += OnShieldStateChanged;
shield.onShieldConfigChanged += OnShieldConfigChanged;
// Set up steps
var parent = m_StepPrototype.transform.parent;
m_Steps = new List<HudShieldMeterStep>(shield.shieldStepCount);
m_Steps.Add(m_StepPrototype);
for (int i = 1; i < shield.shieldStepCount; ++i)
m_Steps.Add(Instantiate(m_StepPrototype, parent));
for (int i = 0; i < m_Steps.Count; ++i)
m_Steps[i].ResetLayout(i, shield.shieldStepCount);
// Show HUD
gameObject.SetActive(true);
// Update
UpdateStepMeters();
}
else
gameObject.SetActive(false);
}
else
gameObject.SetActive(false);
}
protected virtual void OnShieldValueChangedInternal(IShieldManager s, float from, float to)
{
UpdateStepMeters();
}
protected virtual void OnShieldStateChanged(IShieldManager s, ShieldState state)
{
}
protected virtual void OnShieldConfigChanged(IShieldManager s)
{
// Resize if required
if (s.shieldStepCount != m_Steps.Count)
ResizeSteps(s.shieldStepCount);
// Update step meters
UpdateStepMeters();
}
void UpdateStepMeters()
{
// Get the number of filled shield steps & remainder
int full = Mathf.FloorToInt((shield.shield + 0.01f) / shield.shieldStepCapacity);
float remainder = shield.shield - (full * shield.shieldStepCapacity);
// Full steps
int i = 0;
for (; i < full; ++i)
m_Steps[i].fill = 1f;
// Partial step
if (remainder > 0.001f)
{
m_Steps[i].fill = remainder / shield.shieldStepCapacity;
++i;
}
// Empty steps
for (; i < m_Steps.Count; ++i)
m_Steps[i].fill = 0f;
}
void ResizeSteps(int to)
{
if (to > m_Steps.Count)
{
// Get the correct transform parent
var parent = m_StepPrototype.transform.parent;
// Resize the list
m_Steps.Capacity = to;
// Add new items
while (m_Steps.Count < to)
m_Steps.Add(Instantiate(m_StepPrototype, parent));
}
else
{
// Trim steps
for (int i = m_Steps.Count - 1; i >= to; --i)
Destroy(m_Steps[i].gameObject);
m_Steps.RemoveRange(to, m_Steps.Count - to);
}
// Reset step layout
for (int i = 0; i < m_Steps.Count; ++i)
m_Steps[i].ResetLayout(i, to);
}
}
}