SanAndreasUnity/Assets/Scripts/Behaviours/Vehicles/Vehicle_Damage.cs

171 lines
5.4 KiB
C#
Raw Normal View History

using System.Linq;
using SanAndreasUnity.Utilities;
2020-06-09 16:34:15 +00:00
using UnityEngine;
namespace SanAndreasUnity.Behaviours.Vehicles
{
public partial class Vehicle
{
public Damageable Damageable { get; private set; }
2020-06-09 17:45:25 +00:00
public float Health { get; set; } = 1000;
2020-06-09 16:34:15 +00:00
public float MaxHealth { get; set; } = 1000;
public bool IsUnderFlame { get; private set; } = false;
public bool IsUnderSmoke { get; private set; } = false;
2020-06-09 17:45:25 +00:00
bool m_alreadyExploded = false;
2020-06-09 16:34:15 +00:00
public float TimeWhenBecameUnderFlame { get; private set; } = float.NegativeInfinity;
void Awake_Damage()
{
2020-06-09 17:45:25 +00:00
}
void SetupDamagable()
{
this.Damageable = this.HighDetailMeshesParent.gameObject.AddComponent<Damageable>();
2020-06-09 16:34:15 +00:00
this.Damageable.OnDamageEvent.AddListener(() => this.OnDamaged());
}
void OnDamaged()
{
var damageInfo = this.Damageable.LastDamageInfo;
if (this.Health <= 0)
return;
this.Health -= damageInfo.amount;
if (this.Health <= 0)
{
this.Explode();
}
}
void Update_Damage()
{
bool shouldBeUnderSmoke = this.MaxHealth * 0.33f >= this.Health;
if (shouldBeUnderSmoke != this.IsUnderSmoke)
{
// smoke status changed
this.IsUnderSmoke = shouldBeUnderSmoke;
// update vfx
}
bool shouldBeUnderFlame = this.MaxHealth * 0.1f >= this.Health;
if (shouldBeUnderFlame != this.IsUnderFlame)
{
// flame status changed
this.IsUnderFlame = shouldBeUnderFlame;
if (this.IsUnderFlame)
this.TimeWhenBecameUnderFlame = Time.time;
// update vfx
}
if (this.IsUnderFlame && Time.time - this.TimeWhenBecameUnderFlame >= 5)
{
// enough time passed since vehicle flamed - explode it
this.Explode();
}
}
public void Explode()
2020-06-20 18:17:22 +00:00
{
F.RunExceptionSafe(() => this.ExplodeInternal());
}
private void ExplodeInternal()
2020-06-09 16:34:15 +00:00
{
2020-06-09 17:45:25 +00:00
if (m_alreadyExploded)
return;
m_alreadyExploded = true;
2020-06-20 15:56:17 +00:00
// destroy this game object before doing anything else
2020-06-09 17:45:25 +00:00
Object.Destroy(this.gameObject);
2020-06-09 16:34:15 +00:00
2020-06-20 18:15:29 +00:00
// detach vehicle parts and apply explosion force on them
string[] startingNames = new string[] { "door_", "wheel_", "bonnet_", "boot_", "windscreen_", "exhaust_" };
Vector3 explosionCenter = this.transform.position;
float explosionForce = Mathf.Sqrt(this.HandlingData.Mass) * VehicleManager.Instance.explosionForceMultiplier;
float explosionRadius = 10f;
foreach (var frame in _frames)
{
if (!frame.gameObject.activeInHierarchy)
continue;
if (!startingNames.Any(n => frame.gameObject.name.StartsWith(n)))
continue;
2020-06-20 16:05:12 +00:00
DetachFrameDuringExplosion(
frame, explosionCenter, explosionForce, explosionRadius, VehicleManager.Instance.explosionLeftoverPartsMass);
2020-06-20 15:56:17 +00:00
}
2020-06-20 15:56:17 +00:00
// chassis need to be handled after all other objects are detached, because chassis can sometimes
// have other objects as children
2020-06-20 15:56:17 +00:00
Frame chassisFrame = _frames.FirstOrDefault(f => f.Name == "chassis");
2020-06-20 15:56:17 +00:00
if (null == chassisFrame)
{
Debug.LogError($"Chassis object not found on vehicle {this.DescriptionForLogging}");
}
else
{
2020-06-20 16:05:12 +00:00
DetachFrameDuringExplosion(
chassisFrame,
explosionCenter,
Mathf.Sqrt(this.HandlingData.Mass) * VehicleManager.Instance.explosionChassisForceMultiplier,
explosionRadius,
this.HandlingData.Mass * 0.9f);
2020-06-20 15:56:17 +00:00
}
// create explosion effect
2020-06-09 16:34:15 +00:00
}
2020-06-20 16:05:12 +00:00
void DetachFrameDuringExplosion(
Frame frame, Vector3 explosionCenter, float explosionForce, float explosionRadius, float mass)
2020-06-20 15:56:17 +00:00
{
var meshFilter = frame.GetComponentInChildren<MeshFilter>();
if (null == meshFilter)
return;
if (!meshFilter.gameObject.activeInHierarchy)
return;
meshFilter.transform.SetParent(null, true);
meshFilter.gameObject.name = "vehicle_part_" + meshFilter.gameObject.name;
meshFilter.gameObject.layer = UnityEngine.LayerMask.NameToLayer("Default");
var meshCollider = meshFilter.gameObject.GetOrAddComponent<MeshCollider>();
meshCollider.convex = true;
meshCollider.sharedMesh = meshFilter.sharedMesh;
var rigidBody = meshFilter.gameObject.GetOrAddComponent<Rigidbody>();
2020-06-20 16:05:12 +00:00
rigidBody.mass = mass;
2020-06-20 15:56:17 +00:00
rigidBody.drag = 0.05f;
rigidBody.maxDepenetrationVelocity = VehicleManager.Instance.explosionLeftoverPartsMaxDepenetrationVelocity;
rigidBody.AddExplosionForce(explosionForce, explosionCenter, explosionRadius);
2020-06-20 16:06:24 +00:00
Object.Destroy(meshFilter.gameObject, VehicleManager.Instance.explosionLeftoverPartsLifetime * Random.Range(0.8f, 1.2f));
2020-06-20 15:56:17 +00:00
}
2020-06-09 16:34:15 +00:00
}
}