This commit is contained in:
2026-06-02 08:27:03 +07:00
parent 7889064469
commit a48cd962e1
4232 changed files with 2 additions and 36881 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 11c7b86541f8df64caf758c4f08dcb49
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,123 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace Invector
{
[CustomPropertyDrawer(typeof(vDamageModifier))]
public class vDamageModifierDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SerializedProperty name = property.FindPropertyRelative("name");
SerializedProperty filterMethod = property.FindPropertyRelative("filterMethod");
SerializedProperty damageTypes = property.FindPropertyRelative("damageTypes");
SerializedProperty value = property.FindPropertyRelative("value");
SerializedProperty percentage = property.FindPropertyRelative("percentage");
SerializedProperty destructible = property.FindPropertyRelative("destructible");
SerializedProperty resistance = property.FindPropertyRelative("resistance");
SerializedProperty maxResistance = property.FindPropertyRelative("maxResistance");
SerializedProperty onChangeResistance = property.FindPropertyRelative("onChangeResistance");
SerializedProperty onBroken = property.FindPropertyRelative("onBroken");
position.height = EditorGUIUtility.singleLineHeight;
label = EditorGUI.BeginProperty(position, label, property);
property.isExpanded = EditorGUI.Foldout(position, property.isExpanded, label);
if(property.isExpanded)
{
position.y += EditorGUIUtility.singleLineHeight;
// GUI.Box(position, "");
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.PropertyField(position, name);
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, filterMethod);
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, percentage);
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, value,new GUIContent(percentage.boolValue?value.displayName+" %": value.displayName));
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, destructible);
position.y += EditorGUIUtility.singleLineHeight;
if(destructible.boolValue)
{
EditorGUI.PropertyField(position, resistance);
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, maxResistance);
position.y += EditorGUIUtility.singleLineHeight;
}
if ((vDamageModifier.FilterMethod)filterMethod.enumValueIndex != vDamageModifier.FilterMethod.ApplyToAll)
{
Rect box = EditorGUI.IndentedRect(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight * (damageTypes.arraySize + 1) + 5));
GUI.Box(box, "", "box");
GUI.Label(EditorGUI.IndentedRect(new Rect(position.x + 5, position.y, position.width - 5, EditorGUIUtility.singleLineHeight)), "Damage Types");
Rect btnClear = new Rect(position.x + position.width - position.height - 1, position.y + 1, position.height, position.height);
if (GUI.Button(btnClear, new GUIContent("x", "Clear Types"), "box"))
{
damageTypes.arraySize = 0;
}
position.y += EditorGUIUtility.singleLineHeight + 2f;
position.width -= 8;
position.x += 5;
for (int i = 0; i < damageTypes.arraySize; i++)
{
var p = damageTypes.GetArrayElementAtIndex(i);
var _label = EditorGUI.BeginProperty(position, new GUIContent($"Type {i.ToString("0")}"), p);
EditorGUI.PropertyField(position, p, _label);
EditorGUI.EndProperty();
position.y += EditorGUIUtility.singleLineHeight;
}
position.y += 1f;
position.width += 3;
Rect btnA = new Rect(position.x + position.width - position.height * 2f + 1, position.y, position.height, position.height);
Rect btnB = new Rect(position.x + position.width - position.height, position.y, position.height, position.height);
if (GUI.Button(btnA, "-", "box"))
{
if (damageTypes.arraySize > 0) damageTypes.arraySize--;
}
if (GUI.Button(btnB, "+", "box"))
{
damageTypes.arraySize++;
}
}
if (destructible.boolValue)
{
position.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(position, onChangeResistance);
position.y += EditorGUI.GetPropertyHeight(onChangeResistance);
EditorGUI.PropertyField(position, onBroken);
}
}
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float height = EditorGUIUtility.singleLineHeight * 6;
if(property.FindPropertyRelative("destructible").boolValue)
{
height += EditorGUIUtility.singleLineHeight * 3;
height += EditorGUI.GetPropertyHeight(property.FindPropertyRelative("onChangeResistance"));
height += EditorGUI.GetPropertyHeight(property.FindPropertyRelative("onBroken"));
}
if ((vDamageModifier.FilterMethod)property.FindPropertyRelative("filterMethod").enumValueIndex != vDamageModifier.FilterMethod.ApplyToAll)
{
height += EditorGUIUtility.singleLineHeight * (property.FindPropertyRelative("damageTypes").arraySize + 2);
}
return property.isExpanded? height : EditorGUIUtility.singleLineHeight;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0760808e9da47b645b11be24e88b4a53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
using UnityEngine;
namespace Invector
{
/// <summary>
/// Damage Modifier. You can use this with <see cref="vIDamageReceiver.onStartReceiveDamage"/> to modificate the damage result
/// </summary>
[System.Serializable]
public class vDamageModifier
{
public enum FilterMethod
{
ApplyToAll,
ApplyToAllInList,
ApplyToAllOutList
}
[System.Serializable]
public class DamageModifierEvent : UnityEngine.Events.UnityEvent<vDamageModifier> { }
public string name = "MyModifier";
public FilterMethod filterMethod;
[Tooltip("List of Damage type that this can modify, keep empty if the filter will be applied to all types of damage")] public List<string> damageTypes = new List<string>();
[Tooltip("Modifier value")] public int value;
[Tooltip("true: Reduce a percentage of damage value\nfalse: Reduce da damage value directly")] public bool percentage;
[Tooltip("The Filter will receive all damage and decrease your self resistance")] public bool destructible = true;
public float resistance = 100;
public float maxResistance = 100;
public UnityEngine.UI.Slider.SliderEvent onChangeResistance;
public DamageModifierEvent onBroken;
public bool isBroken => destructible && resistance <= 0;
/// <summary>
/// Apply modifier to damage
/// </summary>
/// <param name="damage">Damage to modify</param>
public virtual void ApplyModifier(vDamage damage)
{
///Apply modifier conditions
if (damage.damageValue > 0 && (CanFilterDamage(damage.damageType)) && (!isBroken))
{
float modifier = 0;
if (percentage)
{
float reduction = (damage.damageValue / 100f) * value;
modifier = reduction; ///Calculate Percentage of the damage
}
else
{
modifier = value;/// default value
}
///apply damage to resistance
if (destructible)
{
resistance -= damage.damageValue;
onChangeResistance.Invoke(Mathf.Max((float)resistance, 0));
if (resistance <= 0) onBroken.Invoke(this);
}
///apply modifier to damage value
if ((!destructible || resistance > 0)) damage.damageValue -= modifier;
}
}
protected virtual bool CanFilterDamage(string damageType)
{
switch (filterMethod)
{
case FilterMethod.ApplyToAll:
return true;
case FilterMethod.ApplyToAllInList:
return damageTypes.Contains(damageType);
case FilterMethod.ApplyToAllOutList:
return !damageTypes.Contains(damageType);
}
return true;
}
public virtual void ResetModifier()
{
if (destructible)
{
resistance = maxResistance;
onChangeResistance.Invoke(Mathf.Max(resistance, 0));
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e9c306e530358f54f8367f65aad2de87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,120 @@
using System.Collections.Generic;
using UnityEngine;
namespace Invector
{
[vClassHeader("Damage Modifier Controller", openClose = false, useHelpBox = true, helpBoxText = "Needs a HealthController component")]
public class vDamageModifierController : vMonoBehaviour
{
public enum GetHealthControllerMethod
{
GetComponent,
GetComponentInParent,
GetComponentInChildren
}
[vReadOnly] public bool isInit;
[SerializeField] protected GetHealthControllerMethod getHealthMethod = GetHealthControllerMethod.GetComponent;
[Tooltip("Modifier List")]
public List<vDamageModifier> modifiers;
public UnityEngine.Events.UnityEvent onAllModifiersIsBroken;
protected vIHealthController healthController = null;
protected virtual void Awake()
{
Init();
}
protected void Init()
{
GetHealthController();
if (healthController != null)
{
AddDamageEvent();
InitModifiers();
isInit = true;
}
}
protected virtual void InitModifiers()
{
for (int i = 0; i < modifiers.Count; i++)
{
modifiers[i].ResetModifier();
modifiers[i].onBroken.AddListener((vDamageModifier m) => { CheckBrokedModifiers(); });
}
}
protected virtual void AddDamageEvent()
{
RemoveDamageEvent();
healthController.onStartReceiveDamage.AddListener(ApplyModifiers);
}
protected virtual void RemoveDamageEvent()
{
healthController.onStartReceiveDamage.RemoveListener(ApplyModifiers);
}
protected virtual void GetHealthController()
{
switch (getHealthMethod)
{
case GetHealthControllerMethod.GetComponent:
healthController = GetComponent<vIHealthController>();
break;
case GetHealthControllerMethod.GetComponentInChildren:
healthController = GetComponentInChildren<vIHealthController>();
break;
case GetHealthControllerMethod.GetComponentInParent:
healthController = GetComponentInParent<vIHealthController>();
break;
}
}
protected virtual void OnEnable()
{
if (isInit) AddDamageEvent();
}
protected virtual void OnDisable()
{
if (isInit) RemoveDamageEvent();
}
/// <summary>
/// Check if all modifiers is broken
/// </summary>
/// <param name="modifier"></param>
protected virtual void CheckBrokedModifiers()
{
if (!modifiers.Exists(m => m.isBroken == false)) onAllModifiersIsBroken.Invoke();
}
/// <summary>
/// Apply All Modifiers when healthcontroller takes damage
/// </summary>
/// <param name="damage">Damage to modify</param>
protected virtual void ApplyModifiers(vDamage damage)
{
for (int i = 0; i < modifiers.Count; i++)
{
modifiers[i].ApplyModifier(damage);
}
}
/// <summary>
/// Reset all breakeable modifiers (will fill yours resistance)
/// </summary>
public void ResetAllModifiers()
{
for (int i = 0; i < modifiers.Count; i++)
{
modifiers[i].ResetModifier();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9014197dd861d8a4da8baec1f9017180
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,257 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Invector
{
[vClassHeader("HealthController", iconName = "HealthControllerIcon")]
public class vHealthController : vMonoBehaviour, vIHealthController
{
#region Variables
[vEditorToolbar("Health", order = 0)]
[SerializeField][vReadOnly] protected bool _isDead;
[vBarDisplay("_maxHealth", false)][SerializeField] protected float _currentHealth;
public bool isImmortal = false;
[vHelpBox("If you want to start with different value, uncheck this and make sure that the current health has a value greater zero")]
public bool fillHealthOnStart = true;
[SerializeField] protected int _maxHealth = 100;
public virtual int maxHealth { get { return _maxHealth; } set { _maxHealth = value; } }
protected virtual void OnValidate()
{
if (currentHealth <= 0 && !isDead) isDead = true;
}
public virtual int MaxHealth
{
get
{
return maxHealth;
}
protected set
{
maxHealth = value;
}
}
public virtual float currentHealth
{
get
{
return _currentHealth;
}
protected set
{
if (_currentHealth != value)
{
_currentHealth = value;
_currentHealth = Mathf.Clamp(_currentHealth, 0, MaxHealth);
onChangeHealth.Invoke(_currentHealth);
HandleCheckHealthEvents();
}
var newDeathState = _currentHealth <= 0;
if (newDeathState != isDead)
{
isDead = newDeathState;
}
}
}
public virtual bool isDead
{
get
{
return _isDead;
}
set
{
if (_isDead != value)
{
_isDead = value;
if (value) onDead.Invoke(gameObject);
}
}
}
[SerializeField] protected float _healthRecovery = 0;
public virtual float healthRecovery { get { return _healthRecovery; } set { _healthRecovery = value; } }
[SerializeField] protected float _healthRecoveryDelay = 0f;
public virtual float healthRecoveryDelay { get { return _healthRecoveryDelay; } set { _healthRecoveryDelay = value; } }
protected float _currentHealthRecoveryDelay;
public virtual float currentHealthRecoveryDelay { get { return _currentHealthRecoveryDelay; } set { _currentHealthRecoveryDelay = value; } }
[vEditorToolbar("Events", order = 100)]
public List<CheckHealthEvent> checkHealthEvents = new List<CheckHealthEvent>();
[SerializeField] protected OnReceiveDamage _onStartReceiveDamage = new OnReceiveDamage();
[SerializeField] protected OnReceiveDamage _onReceiveDamage = new OnReceiveDamage();
[SerializeField] protected OnDead _onDead = new OnDead();
public ValueChangedEvent onChangeHealth;
public OnReceiveDamage onStartReceiveDamage { get { return _onStartReceiveDamage; } protected set { _onStartReceiveDamage = value; } }
public OnReceiveDamage onReceiveDamage { get { return _onReceiveDamage; } protected set { _onReceiveDamage = value; } }
public OnDead onDead { get { return _onDead; } protected set { _onDead = value; } }
public UnityEvent onResetHealth;
public virtual bool inHealthRecovery { get; set; }
#endregion
protected virtual void Start()
{
if (fillHealthOnStart)
currentHealth = maxHealth;
currentHealthRecoveryDelay = healthRecoveryDelay;
}
protected virtual bool canRecoverHealth
{
get
{
return (currentHealth >= 0 && healthRecovery > 0 && currentHealth < maxHealth);
}
}
protected virtual IEnumerator RecoverHealth()
{
inHealthRecovery = true;
while (canRecoverHealth && !isDead)
{
HealthRecovery();
yield return null;
}
inHealthRecovery = false;
}
protected virtual void HealthRecovery()
{
if (!canRecoverHealth || isDead) return;
if (currentHealthRecoveryDelay > 0)
currentHealthRecoveryDelay -= Time.deltaTime;
else
{
if (currentHealth > maxHealth)
currentHealth = maxHealth;
if (currentHealth < maxHealth)
currentHealth += healthRecovery * Time.deltaTime;
}
}
/// <summary>
/// Increase or decrease currentHealth (Positive or Negative Values)
/// </summary>
/// <param name="value">Value to change</param>
public virtual void AddHealth(int value)
{
currentHealth += value;
}
/// <summary>
/// Change the currentHealth of Character
/// </summary>
/// <param name="value"></param>
public virtual void ChangeHealth(int value)
{
currentHealth = value;
}
/// <summary>
/// Reset's current health to specific health value
/// </summary>
/// <param name="health">target health</param>
public virtual void ResetHealth(float health)
{
currentHealth = health;
onResetHealth.Invoke();
}
/// <summary>
/// Reset's current health to max health
/// </summary>
public virtual void ResetHealth()
{
currentHealth = maxHealth;
onResetHealth.Invoke();
}
/// <summary>
/// Change the MaxHealth of Character
/// </summary>
/// <param name="value"></param>
public virtual void ChangeMaxHealth(int value)
{
maxHealth += value;
if (maxHealth < 0)
maxHealth = 0;
}
/// <summary>
/// Set a value to HealthRecovery to start recovering health
/// </summary>
/// <param name="value"></param>
public virtual void SetHealthRecovery(float value)
{
healthRecovery = value;
StartCoroutine(RecoverHealth());
}
/// <summary>
/// Apply Damage to Current Health
/// </summary>
/// <param name="damage">damage</param>
public virtual void TakeDamage(vDamage damage)
{
if (damage != null)
{
onStartReceiveDamage.Invoke(damage);
currentHealthRecoveryDelay = currentHealth <= 0 ? 0 : healthRecoveryDelay;
if (currentHealth > 0 && !isImmortal)
{
currentHealth -= damage.damageValue;
}
if (damage.damageValue > 0)
onReceiveDamage.Invoke(damage);
}
}
protected virtual void HandleCheckHealthEvents()
{
var events = checkHealthEvents.FindAll(e => (e.healthCompare == CheckHealthEvent.HealthCompare.Equals && currentHealth.Equals(e.healthToCheck)) ||
(e.healthCompare == CheckHealthEvent.HealthCompare.HigherThan && currentHealth > (e.healthToCheck)) ||
(e.healthCompare == CheckHealthEvent.HealthCompare.LessThan && currentHealth < (e.healthToCheck)));
for (int i = 0; i < events.Count; i++)
{
events[i].OnCheckHealth.Invoke();
}
if (currentHealth < maxHealth && this.gameObject.activeInHierarchy && !inHealthRecovery)
StartCoroutine(RecoverHealth());
}
[System.Serializable]
public class CheckHealthEvent
{
public int healthToCheck;
public bool disableEventOnCheck;
public enum HealthCompare
{
Equals,
HigherThan,
LessThan
}
public HealthCompare healthCompare = HealthCompare.Equals;
public UnityEngine.Events.UnityEvent OnCheckHealth;
}
[System.Serializable]
public class ValueChangedEvent : UnityEvent<float>
{
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f56a83ea88140fa4f869bb2f7ffdb184
timeCreated: 1518749239
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace Invector
{
public class vHealthItem : MonoBehaviour
{
[Tooltip("How much health will be recovery")]
public float value;
public string tagFilter = "Player";
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(tagFilter))
{
// access the basic character information
var healthController = other.GetComponent<vHealthController>();
if (healthController != null)
{
// heal only if the character's health isn't full
if (healthController.currentHealth < healthController.maxHealth)
{
// limit healing to the max health
healthController.AddHealth((int)value);
Destroy(gameObject);
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0efba5381afa0d348829059ea927c1b8
timeCreated: 1462200765
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
using UnityEngine;
namespace Invector
{
[System.Serializable]
public class OnReceiveDamage : UnityEngine.Events.UnityEvent<vDamage> { }
public interface vIDamageReceiver
{
OnReceiveDamage onStartReceiveDamage { get; }
OnReceiveDamage onReceiveDamage { get; }
Transform transform { get; }
GameObject gameObject { get; }
void TakeDamage(vDamage damage);
}
public static class vDamageHelper
{
/// <summary>
/// Apply damage to gameObject if <see cref="CanReceiveDamage(GameObject)"/>
/// </summary>
/// <param name="receiver"></param>
/// <param name="damage"></param>
public static void ApplyDamage(this GameObject receiver, vDamage damage)
{
var receivers = receiver.GetComponents<vIDamageReceiver>();
if (receivers != null)
for (int i = 0; i < receivers.Length; i++)
receivers[i].TakeDamage(damage);
}
/// <summary>
/// check if gameObject can receive the damage
/// </summary>
/// <param name="receiver"></param>
/// <returns>return true if gameObject contains a <see cref="vIDamageReceiver"/></returns>
public static bool CanReceiveDamage(this GameObject receiver)
{
return receiver.GetComponent<vIDamageReceiver>() != null;
}
/// <summary>
/// Get Angle between transform position and hit point
/// </summary>
/// <param name="transform"></param>
/// <param name="hitpoint"></param>
/// <param name="normalized"></param>
/// <returns></returns>
public static float HitAngle(this Transform transform, Vector3 hitpoint, bool normalized = true)
{
var localTarget = transform.InverseTransformPoint(hitpoint);
var _angle = (int)(Mathf.Atan2(localTarget.x, localTarget.z) * Mathf.Rad2Deg);
if (!normalized) return _angle;
if (_angle <= 45 && _angle >= -45)
_angle = 0;
else if (_angle > 45 && _angle < 135)
_angle = 90;
else if (_angle >= 135 || _angle <= -135)
_angle = 180;
else if (_angle < -45 && _angle > -135)
_angle = -90;
return _angle;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d35407a447fbd854ea944edb99d4d7ab
timeCreated: 1529517543
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
using UnityEngine;
namespace Invector
{
[System.Serializable]
public class OnDead : UnityEngine.Events.UnityEvent<GameObject> { }
public interface vIHealthController : vIDamageReceiver
{
/// <summary>
/// Event called when <seealso cref="currentHealth"/> is zero or less
/// </summary>
OnDead onDead { get; }
/// <summary>
/// Current Health value
/// </summary>
float currentHealth { get; }
/// <summary>
/// Max Health value
/// </summary>
int MaxHealth { get; }
/// <summary>
/// Check if <seealso cref="currentHealth"/> is zero or less
/// </summary>
bool isDead { get; set; }
/// <summary>
/// Encrease or Decrease <seealso cref="currentHealth"/> respecting the <seealso cref="MaxHealth"/>
/// </summary>
/// <param name="value">value</param>
void AddHealth(int value);
/// <summary>
/// Change <seealso cref="currentHealth"/> respecting the <seealso cref="MaxHealth"/>
/// </summary>
/// <param name="value">value</param>
void ChangeHealth(int value);
/// <summary>
/// Change the Max Health value
/// </summary>
/// <param name="value">value</param>
void ChangeMaxHealth(int value);
/// <summary>
/// Reset's current health to specific health value
/// </summary>
/// <param name="health">target health</param>
void ResetHealth(float health);
/// <summary>
/// Reset's current health to max health
/// </summary>
void ResetHealth();
}
public static class vHealthControllerHelper
{
static vIHealthController GetHealthController(this GameObject gameObject)
{
return gameObject.GetComponent<vIHealthController>();
}
/// <summary>
/// Encrease or Decrease <seealso cref="currentHealth"/> respecting the <seealso cref="MaxHealth"/>
/// </summary>
/// <param name="receiver">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <param name="health"></param>
public static void AddHealth(this GameObject receiver, int health)
{
var healthController = receiver.GetHealthController();
if (healthController != null)
{
healthController.AddHealth(health);
}
}
/// <summary>
/// Change <seealso cref="currentHealth"/> respecting the <seealso cref="MaxHealth"/>
/// </summary>
/// <param name="receiver">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <param name="health"></param>
public static void ChangeHealth(this GameObject receiver, int health)
{
var healthController = receiver.GetHealthController();
if (healthController != null)
{
healthController.ChangeHealth(health);
}
}
/// <summary>
/// Change the Max Health value
/// </summary>
/// <param name="receiver">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <param name="health"></param>
public static void ChangeMaxHealth(this GameObject receiver, int health)
{
var healthController = receiver.GetHealthController();
if (healthController != null)
{
healthController.ChangeMaxHealth(health);
}
}
/// <summary>
/// Check if GameObject Has a vIHealthController
/// </summary>
/// <param name="gameObject">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <returns></returns>
public static bool HasHealth(this GameObject gameObject)
{
return gameObject.GetHealthController() != null;
}
/// <summary>
/// Check if GameObject is dead
/// </summary>
/// <param name="gameObject">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <returns>return true if GameObject does not has a vIHealthController or currentHealth is less or equals zero </returns>
public static bool IsDead(this GameObject gameObject)
{
var health = gameObject.GetHealthController();
return health == null || health.isDead;
}
/// <summary>
/// Reset's current health to specific health value
/// </summary>
/// <param name="receiver">Target to GetComponent <seealso cref="vIHealthController"/> </param>
/// <param name="health">target health</param>
public static void ResetHealth(this GameObject receiver, float health)
{
var healthController = receiver.GetHealthController();
if (healthController != null)
{
healthController.ResetHealth(health);
}
}
/// <summary>
/// Reset's current health to max health
/// </summary>
/// <param name="receiver">Target to GetComponent <seealso cref="vIHealthController"/> </param>
public static void ResetHealth(this GameObject receiver)
{
var healthController = receiver.GetHealthController();
if (healthController != null)
{
healthController.ResetHealth();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5bea8c3318504e641b164ac52e4787e3
timeCreated: 1529517493
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
namespace Invector.vCharacterController
{
[vClassHeader("SpriteHealth", "Assign your canvas object in the 'healthBar' field to hide and only display when receive damage - leave it empty if you want to display the healthbar all the time.", openClose = false)]
public class v_SpriteHealth : vMonoBehaviour
{
[Tooltip("UI to show on receive damage")]
[SerializeField]
protected GameObject healthBar;
public bool lookToCamera = true;
[Header("UI properties")]
[SerializeField] protected Slider _healthSlider;
[SerializeField] protected Slider _damageDelay;
[SerializeField] protected float _smoothDamageDelay;
[SerializeField] protected Text _damageCounter;
[SerializeField] protected float _damageCounterTimer = 1.5f;
[SerializeField] protected bool _showDamageType = true;
private vHealthController healthControl;
private bool inDelay;
private float damage;
private float currentSmoothDamage;
internal Transform cameraMain;
void Start()
{
cameraMain = Camera.main ? Camera.main.transform : null;
healthControl = transform.GetComponentInParent<vHealthController>();
if (healthControl == null)
{
Debug.LogWarning("The character must have a ICharacter Interface");
Destroy(this.gameObject);
}
healthControl.onReceiveDamage.AddListener(Damage);
_healthSlider.maxValue = healthControl.maxHealth;
_healthSlider.value = _healthSlider.maxValue;
_damageDelay.maxValue = healthControl.maxHealth;
_damageDelay.value = _healthSlider.maxValue;
_damageCounter.text = string.Empty;
if (healthBar) healthBar.SetActive(false);
}
void SpriteBehaviour()
{
if (lookToCamera && cameraMain != null) transform.LookAt(cameraMain.position, Vector3.up);
if (healthControl == null || healthControl.currentHealth <= 0)
Destroy(gameObject);
_healthSlider.value = healthControl.currentHealth;
}
void Update()
{
if (!healthBar)
{
SpriteBehaviour();
}
}
public void Damage(vDamage damage)
{
try
{
this.damage += damage.damageValue;
_damageCounter.text = this.damage.ToString("00") + ((_showDamageType && !string.IsNullOrEmpty(damage.damageType)) ? (" : by " + damage.damageType) : "");
_healthSlider.value -= damage.damageValue;
if (!inDelay && healthControl && healthControl.gameObject.activeInHierarchy)
StartCoroutine(DamageDelay());
}
catch
{
Destroy(this);
}
}
IEnumerator DamageDelay()
{
inDelay = true;
if (healthBar) SpriteBehaviour();
if (healthBar) healthBar.SetActive(true);
while (_damageDelay.value > _healthSlider.value)
{
if (healthBar) SpriteBehaviour();
_damageDelay.value -= _smoothDamageDelay;
yield return null;
}
inDelay = false;
yield return new WaitForSeconds(_damageCounterTimer);
damage = 0;
_damageCounter.text = string.Empty;
if (healthBar) healthBar.SetActive(false);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8553221e1fc915c49b36f6e633dffaff
timeCreated: 1452874805
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: