797 lines
30 KiB
C#
797 lines
30 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
// Sci-Fi Ship Controller. Copyright (c) 2018-2023 SCSM Pty Ltd. All rights reserved.
|
||
namespace SciFiShipController
|
||
{
|
||
/// <summary>
|
||
/// This module can be used to trigger a DestructModule when the health of the object reaches 0.
|
||
/// For a simplified solution, see SSCTargetable.
|
||
/// IMPORTANT: If you want a ship, a ship’s damage regions, or a surface turret to take damage,
|
||
/// use the features included in the Ship Control Module or the Surface Turret Module. This
|
||
/// module is to be used with regular gameobjects that don’t include those components.
|
||
/// Examples could include buildings or destructible props.
|
||
/// </summary>
|
||
[AddComponentMenu("Sci-Fi Ship Controller/Object Components/Destructive Object Module")]
|
||
[DisallowMultipleComponent]
|
||
[RequireComponent(typeof(SciFiShipController.DamageReceiver))]
|
||
[HelpURL("http://scsmmedia.com/ssc-documentation")]
|
||
public class DestructibleObjectModule : MonoBehaviour
|
||
{
|
||
#region Public Variables
|
||
public bool initialiseOnStart = false;
|
||
|
||
/// <summary>
|
||
/// How much health the object has initially
|
||
/// </summary>
|
||
public float startingHealth = 100f;
|
||
|
||
/// <summary>
|
||
/// Whether this object uses shielding. Up until a point, shielding protects the object from damage
|
||
/// </summary>
|
||
public bool useShielding = false;
|
||
/// <summary>
|
||
/// Damage below this value will not affect the shield or the object's health while the shield is still active
|
||
/// (i.e. until the shield has absorbed damage more than or equal to the shieldingAmount value from damage events above the
|
||
/// damage threshold). Only relevant if useShielding is enabled.
|
||
/// </summary>
|
||
public float shieldingDamageThreshold = 10f;
|
||
/// <summary>
|
||
/// How much damage the shield can absorb before it ceases to protect the object from damage. Only relevant if
|
||
/// useShielding is enabled.
|
||
/// </summary>
|
||
public float shieldingAmount = 100f;
|
||
|
||
/// <summary>
|
||
/// When useShielding is true, this is the rate per second that a shield will recharge (default = 0)
|
||
/// </summary>
|
||
[Range(0f, 100f)] public float shieldingRechargeRate = 0f;
|
||
|
||
/// <summary>
|
||
/// When useShielding is true, and shieldingRechargeRate is greater than 0, this is the delay, in seconds,
|
||
/// between when damage occurs to a shield and it begins to recharge.
|
||
/// </summary>
|
||
[Range(0f, 300f)] public float shieldingRechargeDelay = 10f;
|
||
|
||
/// <summary>
|
||
/// The sound or particle FX used when object is destroyed
|
||
/// If you modify this, call ReinitialiseEffects().
|
||
/// </summary>
|
||
public EffectsModule destructionEffectsObject;
|
||
|
||
/// <summary>
|
||
/// The offset in the forward direction, from the objects gameobject, that the destruction effect is instantiated.
|
||
/// </summary>
|
||
public Vector3 destructionEffectsOffset = Vector3.zero;
|
||
|
||
/// <summary>
|
||
/// This is used when you want pre-build fragments of the object to explode out from the object position when it is destroyed.
|
||
/// If you modify this, call ReinitialiseDestructObjects().
|
||
/// </summary>
|
||
public DestructModule destructObject = null;
|
||
|
||
/// <summary>
|
||
/// The offset in the forward direction, from the objects gameobject, that the destruct module is instantiated.
|
||
/// </summary>
|
||
public Vector3 destructObjectOffset = Vector3.zero;
|
||
|
||
/// <summary>
|
||
/// The relative size of the blip on the radar mini-map
|
||
/// Must be between 1 and 5 inclusive.
|
||
/// </summary>
|
||
[Range(1, 5)] public byte radarBlipSize = 1;
|
||
|
||
#endregion
|
||
|
||
#region Public Properties
|
||
|
||
/// <summary>
|
||
/// The current health value of this object.
|
||
/// </summary>
|
||
public float Health
|
||
{
|
||
get { return health; }
|
||
set
|
||
{
|
||
// Update the health value
|
||
health = value < 0f ? 0f : value;
|
||
|
||
if (isInitialised && health == 0f)
|
||
{
|
||
DestructObject();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// [READONLY]
|
||
/// Normalised (0.0 – 1.0) value of the health of the object.
|
||
/// </summary>
|
||
public float HealthNormalised
|
||
{
|
||
get
|
||
{
|
||
float _healthN = startingHealth == 0f ? 0f : health / startingHealth;
|
||
if (_healthN > 1f) { return 1f; }
|
||
else if (_healthN < 0f) { return 0f; }
|
||
else { return _healthN; }
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// [READONLY] Has the module been initialised?
|
||
/// </summary>
|
||
public bool IsInitialised { get { return isInitialised; } }
|
||
|
||
/// <summary>
|
||
/// [READONLY] The number used by the SSCRadar system to identify this object at a point in time.
|
||
/// This should not be stored across frames and is updated as required by the system.
|
||
/// </summary>
|
||
public int RadarId { get { return radarItemIndex; } }
|
||
|
||
/// <summary>
|
||
/// The current health value of this object's shield.
|
||
/// When a shield is destroyed, its value is set to -0.01.
|
||
/// </summary>
|
||
public float ShieldHealth
|
||
{
|
||
get { return shieldHealth; }
|
||
set
|
||
{
|
||
// Update the health value
|
||
shieldHealth = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// [READONLY]
|
||
/// Normalised (0.0 – 1.0) value of the shield for this object. If useShielding is false, it will
|
||
/// always return 0.
|
||
/// </summary>
|
||
public float ShieldNormalised
|
||
{
|
||
get
|
||
{
|
||
float _shieldN = !useShielding || shieldingAmount == 0f ? 0f : shieldHealth / shieldingAmount;
|
||
if (_shieldN > 1f) { return 1f; }
|
||
else if (_shieldN < 0f) { return 0f; }
|
||
else { return _shieldN; }
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Private or Internal variables
|
||
|
||
private bool isInitialised = false;
|
||
private DamageReceiver damageReceiver = null;
|
||
|
||
private float health;
|
||
private float shieldHealth;
|
||
|
||
/// <summary>
|
||
/// Whether damage type multipliers are used when calculating damage from projectiles.
|
||
/// </summary>
|
||
[SerializeField] private bool useDamageMultipliers = false;
|
||
|
||
/// <summary>
|
||
/// The array of damage multipliers for this object.
|
||
/// </summary>
|
||
[SerializeField] private float[] damageMultipliersArray;
|
||
|
||
/// <summary>
|
||
/// [INTERNAL USE ONLY] Instead, call EnableRadar() or DisableRadar().
|
||
/// </summary>
|
||
[SerializeField] private bool isRadarEnabled = false;
|
||
|
||
/// <summary>
|
||
/// The faction or alliance the object belongs to. This can be used to identify if a object is friend or foe. Neutral = 0.
|
||
/// </summary>
|
||
[SerializeField] private int factionId = 0;
|
||
|
||
/// <summary>
|
||
/// Although normally representing a squadron of ships, this can be used on a gameobjects to group it with other things in your scene
|
||
/// </summary>
|
||
[SerializeField] private int squadronId = -1;
|
||
|
||
/// <summary>
|
||
/// This identifies the destructionEffectsObject instance that may have been instantiated.
|
||
/// </summary>
|
||
[System.NonSerialized] internal SSCEffectItemKey destructionEffectItemKey;
|
||
|
||
/// <summary>
|
||
/// The ID number for this damage region's destruct prefab (as assigned by the SSCManager in the scene).
|
||
/// This is the index in the SSCManager destructTemplateList.
|
||
/// [INTERNAL USE ONLY]
|
||
/// </summary>
|
||
[System.NonSerialized] internal int destructObjectPrefabID;
|
||
|
||
/// <summary>
|
||
/// Flag for whether the destruct object has been activated.
|
||
/// [INTERNAL USE ONLY]
|
||
/// </summary>
|
||
[System.NonSerialized] internal bool isDestructObjectActivated;
|
||
|
||
/// <summary>
|
||
/// This identifies the destruct object instance that may have been instantiated.
|
||
/// </summary>
|
||
[System.NonSerialized] internal SSCDestructItemKey destructItemKey;
|
||
|
||
/// <summary>
|
||
/// [INTERNAL USE ONLY]
|
||
/// Flag for when the object destroy "event" has been actioned after health reaches 0
|
||
/// </summary>
|
||
[System.NonSerialized] internal bool isDestroyed = false;
|
||
|
||
[System.NonSerialized] private SSCManager sscManager = null;
|
||
|
||
// Radar variables
|
||
[System.NonSerialized] private SSCRadar sscRadar = null;
|
||
[System.NonSerialized] internal int radarItemIndex = -1;
|
||
//[System.NonSerialized] internal SSCRadarPacket sscRadarPacket;
|
||
|
||
/// <summary>
|
||
/// [INTERNAL USE ONLY]
|
||
/// </summary>
|
||
[System.NonSerialized] internal float shieldRechargeDelayTimer;
|
||
|
||
/// <summary>
|
||
/// The ID number for this object's destruction effects object prefab (as assigned by the Ship Controller Manager in the scene).
|
||
/// This is the index in the SSCManager effectsObjectTemplatesList.
|
||
/// [INTERNAL USE ONLY]
|
||
/// </summary>
|
||
[System.NonSerialized] public int effectsObjectPrefabID;
|
||
|
||
/// <summary>
|
||
/// Flag for whether the destruction effects object has been instantiated.
|
||
/// [INTERNAL USE ONLY]
|
||
/// </summary>
|
||
[System.NonSerialized] public bool isDestructionEffectsObjectInstantiated;
|
||
|
||
#endregion
|
||
|
||
#region Initialise methods
|
||
// Start is called before the first frame update
|
||
void Start()
|
||
{
|
||
if (initialiseOnStart) { Initialise(); }
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Update Methods
|
||
|
||
private void Update()
|
||
{
|
||
if (isInitialised)
|
||
{
|
||
CheckShieldRecharge();
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Private Methods
|
||
|
||
/// <summary>
|
||
/// Add or remove this gameobject from radar.
|
||
/// </summary>
|
||
/// <param name="isEnabled"></param>
|
||
private void EnableOrDisableRadar(bool isEnabled)
|
||
{
|
||
if (isEnabled)
|
||
{
|
||
if (isInitialised && radarItemIndex == -1)
|
||
{
|
||
// Create as a RadarItemType.GameObject
|
||
if (sscRadar == null) { sscRadar = SSCRadar.GetOrCreateRadar(); }
|
||
if (sscRadar != null) { radarItemIndex = sscRadar.EnableRadar(gameObject, transform.position, factionId, squadronId, 0, radarBlipSize); }
|
||
|
||
isRadarEnabled = radarItemIndex >= 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
|
||
{
|
||
sscRadar.DisableRadar(radarItemIndex);
|
||
}
|
||
isRadarEnabled = false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Recharge the shield if required
|
||
/// </summary>
|
||
private void CheckShieldRecharge()
|
||
{
|
||
// Is shield recharging enabled?
|
||
if (health > 0 && useShielding && shieldingRechargeRate > 0)
|
||
{
|
||
// Can the shield be recharged?
|
||
if (shieldingRechargeDelay > shieldRechargeDelayTimer)
|
||
{
|
||
shieldRechargeDelayTimer += Time.deltaTime;
|
||
}
|
||
else
|
||
{
|
||
shieldHealth += shieldingRechargeRate * Time.deltaTime;
|
||
|
||
if (shieldHealth > shieldingAmount) { shieldHealth = shieldingAmount; }
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Public API Methods
|
||
|
||
/// <summary>
|
||
/// Apply damage to the object. If Use Damage Multipliers is enabled, you can optionally pass in the DamageTye.
|
||
/// </summary>
|
||
/// <param name="damageAmount"></param>
|
||
/// <param name="damageType"></param>
|
||
public void ApplyDamage (float damageAmount, ProjectileModule.DamageType damageType = ProjectileModule.DamageType.Default)
|
||
{
|
||
float actualDamage = damageAmount;
|
||
bool objectDamaged = true;
|
||
|
||
// Modify damage dealt based on relevant damage multipliers
|
||
if (useDamageMultipliers)
|
||
{
|
||
actualDamage *= GetDamageMultiplier(damageType);
|
||
}
|
||
|
||
// Determine whether shielding is active for this object
|
||
if (useShielding && shieldHealth > 0f)
|
||
{
|
||
// Set the shielding to active
|
||
objectDamaged = false;
|
||
// Only do damage to the shield if the damage amount is above the shielding threshold
|
||
if (actualDamage >= shieldingDamageThreshold)
|
||
{
|
||
shieldHealth -= actualDamage;
|
||
shieldRechargeDelayTimer = 0f;
|
||
// If this damage destroys the shielding entirely...
|
||
if (shieldHealth <= 0f)
|
||
{
|
||
// Get the residual damage value
|
||
actualDamage = -shieldHealth;
|
||
// Set the shielding to inactive
|
||
objectDamaged = true;
|
||
shieldHealth = -0.01f;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (objectDamaged)
|
||
{
|
||
// Reduce health of object itself
|
||
Health -= actualDamage;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// This routine is called by our damage receiver when a projectile or beam hits our object
|
||
/// </summary>
|
||
/// <param name="callbackOnObjectHitParameters"></param>
|
||
public void ApplyDamage (CallbackOnObjectHitParameters callbackOnObjectHitParameters)
|
||
{
|
||
if (callbackOnObjectHitParameters.hitInfo.transform != null)
|
||
{
|
||
ProjectileModule projectile = callbackOnObjectHitParameters.projectilePrefab;
|
||
|
||
if (projectile != null)
|
||
{
|
||
ApplyDamage(projectile.damageAmount, projectile.damageType);
|
||
}
|
||
// Should have been a beam weapon that fired at the object
|
||
else
|
||
{
|
||
BeamModule beam = callbackOnObjectHitParameters.beamPrefab;
|
||
|
||
if (beam != null)
|
||
{
|
||
ApplyDamage(callbackOnObjectHitParameters.damageAmount, beam.damageType);
|
||
}
|
||
else
|
||
{
|
||
// if we don't need to know what hit the object, simply reduce the health
|
||
ApplyDamage(callbackOnObjectHitParameters.damageAmount);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Add health to the object. If isAffectShield is true, and the health reaches the maximum
|
||
/// configured, excess health will be applied to the shield.
|
||
/// To incur damage use the ApplyDamage(..).
|
||
/// </summary>
|
||
/// <param name="healthAmount"></param>
|
||
/// <param name="isAffectShield"></param>
|
||
public void AddHealth (float healthAmount, bool isAffectShield)
|
||
{
|
||
if (healthAmount > 0f)
|
||
{
|
||
if (health < 0f) { health = healthAmount; }
|
||
else { health += healthAmount; }
|
||
|
||
if (health > startingHealth)
|
||
{
|
||
if (isAffectShield && useShielding)
|
||
{
|
||
float newShieldHealth = 0f;
|
||
// When shielding is -ve (e.g. -0.01 when it has been used up) set the shielding amount rather than adding it
|
||
if (shieldHealth < 0f) { newShieldHealth = health - startingHealth; }
|
||
else { newShieldHealth = shieldHealth + health - startingHealth; }
|
||
|
||
// Cap shielding to maximum permitted.
|
||
if (newShieldHealth > shieldingAmount) { newShieldHealth = shieldingAmount; }
|
||
|
||
shieldHealth = newShieldHealth;
|
||
}
|
||
|
||
// Cap health to maximum permitted
|
||
health = startingHealth;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Disable radar for this object. If you want to change the visibility to other radar consumers,
|
||
/// consider calling SetRadarVisibility(..) rather than disabling the radar and (later)
|
||
/// calling EnableRadar() again. This will be automatically called by DestructObject().
|
||
/// </summary>
|
||
public void DisableRadar()
|
||
{
|
||
EnableOrDisableRadar(false);
|
||
}
|
||
|
||
// Enable radar for this object. It will be visible on radar to others in the scene.
|
||
public void EnableRadar()
|
||
{
|
||
EnableOrDisableRadar(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns the damage multiplier for damageType.
|
||
/// </summary>
|
||
/// <param name="damageType"></param>
|
||
/// <returns></returns>
|
||
public float GetDamageMultiplier (ProjectileModule.DamageType damageType)
|
||
{
|
||
switch ((int)damageType)
|
||
{
|
||
// Hardcoded int values for performance
|
||
// Default = 0
|
||
case 0: return 1f;
|
||
// Type A = 100
|
||
case 100: return damageMultipliersArray[0];
|
||
// Type B = 105
|
||
case 105: return damageMultipliersArray[1];
|
||
// Type C = 110
|
||
case 110: return damageMultipliersArray[2];
|
||
// Type D = 115
|
||
case 115: return damageMultipliersArray[3];
|
||
// Type E = 120
|
||
case 120: return damageMultipliersArray[4];
|
||
// Type F = 125
|
||
case 125: return damageMultipliersArray[5];
|
||
// Default case
|
||
default: return 1f;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Reinitialises variables required for Destruct Module.
|
||
/// Call after modifying the destructObject.
|
||
/// </summary>
|
||
public void ReinitialiseDestructObjects()
|
||
{
|
||
if (sscManager == null) { sscManager = SSCManager.GetOrCreateManager(); }
|
||
if (sscManager != null)
|
||
{
|
||
// Initialise destruct modules
|
||
sscManager.UpdateDestructObjects(this);
|
||
}
|
||
#if UNITY_EDITOR
|
||
else
|
||
{
|
||
Debug.LogWarning("DestructibleObjectModule.ReinitialiseDestructObjects Warning: could not find SSCManager to update effects.");
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/// <summary>
|
||
/// Reinitialises variables required for effects of the Destructible Object Module.
|
||
/// Call after modifying any effect data for this module.
|
||
/// </summary>
|
||
public void ReinitialiseEffects()
|
||
{
|
||
if (sscManager == null) { sscManager = SSCManager.GetOrCreateManager(); }
|
||
if (sscManager != null)
|
||
{
|
||
// Initialise effects objects
|
||
sscManager.UpdateEffects(this);
|
||
}
|
||
#if UNITY_EDITOR
|
||
else
|
||
{
|
||
Debug.LogWarning("DestructibleObjectModule.ReinitialiseEffects Warning: could not find SSCManager to update effects.");
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/// <summary>
|
||
/// Reset the health of the object back to initial values
|
||
/// </summary>
|
||
public void ResetHealth()
|
||
{
|
||
// Reset health value for the object
|
||
health = startingHealth;
|
||
|
||
// Reset shield health value for the object
|
||
shieldHealth = shieldingAmount;
|
||
|
||
shieldRechargeDelayTimer = 0f;
|
||
|
||
isDestructObjectActivated = false;
|
||
isDestroyed = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets the damage multiplier for damageType to damageMultiplier.
|
||
/// </summary>
|
||
/// <param name="damageType"></param>
|
||
/// <param name="damageMultiplier"></param>
|
||
public void SetDamageMultiplier (ProjectileModule.DamageType damageType, float damageMultiplier)
|
||
{
|
||
switch ((int)damageType)
|
||
{
|
||
// Hardcoded int values for performance
|
||
// Type A = 100
|
||
case 100: damageMultipliersArray[0] = damageMultiplier; break;
|
||
// Type B = 105
|
||
case 105: damageMultipliersArray[1] = damageMultiplier; break;
|
||
// Type C = 110
|
||
case 110: damageMultipliersArray[2] = damageMultiplier; break;
|
||
// Type D = 115
|
||
case 115: damageMultipliersArray[3] = damageMultiplier; break;
|
||
// Type E = 120
|
||
case 120: damageMultipliersArray[4] = damageMultiplier; break;
|
||
// Type F = 125
|
||
case 125: damageMultipliersArray[5] = damageMultiplier; break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// If radar is enabled for this object, set its visibility to radar.
|
||
/// </summary>
|
||
/// <param name="isVisible"></param>
|
||
public void SetRadarVisibility (bool isVisible)
|
||
{
|
||
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
|
||
{
|
||
sscRadar.SetVisibility(radarItemIndex, isVisible);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Set the Squadron Id for the object. If radar is enabled, this will also update the radar.
|
||
/// </summary>
|
||
/// <param name="newSquadronId"></param>
|
||
public void SetSquadronId (int newSquadronId)
|
||
{
|
||
if (squadronId != newSquadronId)
|
||
{
|
||
squadronId = newSquadronId;
|
||
|
||
// Do we need to update the radar item?
|
||
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
|
||
{
|
||
sscRadar.SetSquardronId(radarItemIndex, squadronId);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Set the Faction Id for the object. If radar is enabled, this will also update the radar.
|
||
/// </summary>
|
||
/// <param name="newFactionId"></param>
|
||
public void SetFactionId (int newFactionId)
|
||
{
|
||
if (factionId != newFactionId)
|
||
{
|
||
factionId = newFactionId;
|
||
|
||
// Do we need to update the radar item?
|
||
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
|
||
{
|
||
sscRadar.SetFactionId(radarItemIndex, factionId);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verify that the damage multiplier array is correctly sized
|
||
/// </summary>
|
||
public void VerifyMultiplierArray()
|
||
{
|
||
// Check that the damage multipliers array exists
|
||
if (damageMultipliersArray == null)
|
||
{
|
||
damageMultipliersArray = new float[] { 1f, 1f, 1f, 1f, 1f, 1f };
|
||
}
|
||
else
|
||
{
|
||
// Check that the damage multipliers array is of the correct length
|
||
int damageMultipliersArrayLength = damageMultipliersArray.Length;
|
||
if (damageMultipliersArrayLength != 6)
|
||
{
|
||
// If it is not the correct length, resize it
|
||
// Convert the array into a list
|
||
List<float> tempDamageMultipliersList = new List<float>();
|
||
tempDamageMultipliersList.AddRange(damageMultipliersArray);
|
||
if (damageMultipliersArrayLength > 6)
|
||
{
|
||
// If we have too many items in the array, remove some
|
||
for (int i = damageMultipliersArrayLength; i > 6; i--) { tempDamageMultipliersList.RemoveAt(i - 1); }
|
||
}
|
||
else
|
||
{
|
||
// If we don't have enough items in the array, add some
|
||
for (int i = damageMultipliersArrayLength; i < 6; i++) { tempDamageMultipliersList.Add(1f); }
|
||
}
|
||
// Convert the list back into an array
|
||
damageMultipliersArray = tempDamageMultipliersList.ToArray();
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Public Virtual and Protected API Methods
|
||
|
||
/// <summary>
|
||
/// Initialises the DestructibleObjectModule. If you wish to override this in a child (inherited)
|
||
/// class you almost always will want to call the base method first.
|
||
/// public override void Initialise()
|
||
/// {
|
||
/// base.Initialise();
|
||
/// // Do stuff here
|
||
/// }
|
||
/// </summary>
|
||
public virtual void Initialise()
|
||
{
|
||
if (!isInitialised)
|
||
{
|
||
damageReceiver = GetComponent<DamageReceiver>();
|
||
|
||
if (damageReceiver == null) { damageReceiver = gameObject.AddComponent<DamageReceiver>(); }
|
||
|
||
if (damageReceiver == null)
|
||
{
|
||
#if UNITY_EDITOR
|
||
Debug.LogWarning("ERROR: DestructibleOjectModule.Initialise() - could not find or add DamageReceiver component to " + name);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
VerifyMultiplierArray();
|
||
|
||
ResetHealth();
|
||
|
||
// Get a reference to the Ship Controller Manager instance
|
||
sscManager = SSCManager.GetOrCreateManager();
|
||
|
||
// Not sure if we need these or just the ReinitialiseEffects()
|
||
effectsObjectPrefabID = -1;
|
||
isDestructionEffectsObjectInstantiated = false;
|
||
destructionEffectItemKey = new SSCEffectItemKey(-1, -1, 0);
|
||
|
||
// Not sure if we need these or just the ReinitialiseDestructObjects()
|
||
destructObjectPrefabID = -1;
|
||
isDestructObjectActivated = false;
|
||
destructItemKey = new SSCDestructItemKey(-1, -1, 0);
|
||
|
||
// Initialise effects objects
|
||
ReinitialiseEffects();
|
||
|
||
// Initialise destruct modules
|
||
ReinitialiseDestructObjects();
|
||
|
||
// Get notified when the object is hit by a projectile or beam
|
||
damageReceiver.callbackOnHit = ApplyDamage;
|
||
|
||
isInitialised = true;
|
||
}
|
||
|
||
if (isInitialised)
|
||
{
|
||
EnableOrDisableRadar(isRadarEnabled);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Destroys the object.
|
||
/// If you wish to override this in a child (inherited) class you almost
|
||
/// always will want to call the base after doing your actions.
|
||
/// public override void DestructObject()
|
||
/// {
|
||
/// // Do stuff here
|
||
/// base.DestructObject();
|
||
/// }
|
||
/// </summary>
|
||
public virtual void DestructObject()
|
||
{
|
||
if (isInitialised)
|
||
{
|
||
if (isRadarEnabled) { EnableOrDisableRadar(false); }
|
||
|
||
#region Instantiate the destruction effects prefab
|
||
if (destructionEffectsObject != null)
|
||
{
|
||
InstantiateEffectsObjectParameters ieParms = new InstantiateEffectsObjectParameters
|
||
{
|
||
effectsObjectPrefabID = effectsObjectPrefabID,
|
||
position = transform.position + (transform.rotation * destructionEffectsOffset),
|
||
rotation = transform.rotation
|
||
};
|
||
|
||
sscManager.InstantiateEffectsObject(ref ieParms);
|
||
}
|
||
#endregion
|
||
|
||
#region Instantiate the destruct module prefab
|
||
if (!isDestructObjectActivated && destructObjectPrefabID >= 0 && destructObject != null)
|
||
{
|
||
// Turn off all colliders. As we are going to destroy the gameobject,
|
||
// we can simply deactivate it.
|
||
gameObject.SetActive(false);
|
||
|
||
// Instantiate the region destruct prefab
|
||
InstantiateDestructParameters dstParms = new InstantiateDestructParameters
|
||
{
|
||
destructPrefabID = destructObjectPrefabID,
|
||
position = transform.position + (transform.rotation * destructObjectOffset),
|
||
rotation = transform.rotation,
|
||
explosionPowerFactor = 1f,
|
||
explosionRadiusFactor = 1f
|
||
};
|
||
|
||
// Keep track of the DestructModule instance that was instantiated for this object
|
||
// In our case, we don't really need this as we're going to destroy this script. However,
|
||
// it may be useful if we want to do something else in the future.
|
||
if (sscManager.InstantiateDestruct(ref dstParms) != null)
|
||
{
|
||
destructItemKey = new SSCDestructItemKey(destructObjectPrefabID, dstParms.destructPoolListIndex, dstParms.destructSequenceNumber);
|
||
}
|
||
|
||
isDestructObjectActivated = true;
|
||
}
|
||
#endregion
|
||
|
||
// Destroy the original object
|
||
Destroy(gameObject);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Destroys the object after a delay period in seconds
|
||
/// </summary>
|
||
/// <param name="delayTime"></param>
|
||
public virtual void DestructObjectDelayed (float delayDuration)
|
||
{
|
||
if (delayDuration > 0f)
|
||
{
|
||
Invoke("DestructObject", delayDuration);
|
||
}
|
||
else { DestructObject(); }
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
} |