Update
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11c7b86541f8df64caf758c4f08dcb49
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0760808e9da47b645b11be24e88b4a53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9c306e530358f54f8367f65aad2de87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9014197dd861d8a4da8baec1f9017180
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f56a83ea88140fa4f869bb2f7ffdb184
|
||||
timeCreated: 1518749239
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0efba5381afa0d348829059ea927c1b8
|
||||
timeCreated: 1462200765
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d35407a447fbd854ea944edb99d4d7ab
|
||||
timeCreated: 1529517543
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bea8c3318504e641b164ac52e4787e3
|
||||
timeCreated: 1529517493
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8553221e1fc915c49b36f6e633dffaff
|
||||
timeCreated: 1452874805
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user