134 lines
4.2 KiB
C#
134 lines
4.2 KiB
C#
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Events;
|
|||
|
|
|||
|
namespace BNG {
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// An object than do damage and play hit FX
|
|||
|
/// </summary>
|
|||
|
public class Projectile : MonoBehaviour {
|
|||
|
|
|||
|
public GameObject HitFXPrefab;
|
|||
|
private bool _checkRaycast;
|
|||
|
public float Damage = 25;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add force to rigidbody on impact
|
|||
|
/// </summary>
|
|||
|
public float AddRigidForce = 5;
|
|||
|
|
|||
|
public LayerMask ValidLayers;
|
|||
|
|
|||
|
public bool StickToObject = false;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Minimum Z velocity required to register as an impact
|
|||
|
/// </summary>
|
|||
|
public float MinForceHit = 0.02f;
|
|||
|
|
|||
|
[Tooltip("Unity Event called when the projectile damages something")]
|
|||
|
public UnityEvent onDealtDamageEvent;
|
|||
|
|
|||
|
private void OnCollisionEnter(Collision collision) {
|
|||
|
OnCollisionEvent(collision);
|
|||
|
}
|
|||
|
|
|||
|
public virtual void OnCollisionEvent(Collision collision) {
|
|||
|
// Ignore Triggers
|
|||
|
if (collision.collider.isTrigger) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Rigidbody rb = GetComponent<Rigidbody>();
|
|||
|
if (rb && MinForceHit != 0) {
|
|||
|
float zVel = System.Math.Abs(transform.InverseTransformDirection(rb.velocity).z);
|
|||
|
|
|||
|
// Minimum Force not achieved
|
|||
|
if (zVel < MinForceHit) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Vector3 hitPosition = collision.contacts[0].point;
|
|||
|
Vector3 normal = collision.contacts[0].normal;
|
|||
|
Quaternion hitNormal = Quaternion.FromToRotation(Vector3.forward, normal);
|
|||
|
|
|||
|
// FX - Particles, Decals, etc.
|
|||
|
DoHitFX(hitPosition, hitNormal, collision.collider);
|
|||
|
|
|||
|
// Damage if possible
|
|||
|
Damageable d = collision.collider.GetComponent<Damageable>();
|
|||
|
if (d) {
|
|||
|
d.DealDamage(Damage, hitPosition, normal, true, gameObject, collision.collider.gameObject);
|
|||
|
|
|||
|
if (onDealtDamageEvent != null) {
|
|||
|
onDealtDamageEvent.Invoke();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (StickToObject) {
|
|||
|
// tryStickToObject
|
|||
|
}
|
|||
|
else {
|
|||
|
// Done with this projectile
|
|||
|
Destroy(this.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public virtual void DoHitFX(Vector3 pos, Quaternion rot, Collider col) {
|
|||
|
|
|||
|
// Create FX at impact point / rotation
|
|||
|
if(HitFXPrefab) {
|
|||
|
GameObject impact = Instantiate(HitFXPrefab, pos, rot) as GameObject;
|
|||
|
BulletHole hole = impact.GetComponent<BulletHole>();
|
|||
|
if (hole) {
|
|||
|
hole.TryAttachTo(col);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// push object if rigidbody
|
|||
|
Rigidbody hitRigid = col.attachedRigidbody;
|
|||
|
if (hitRigid != null) {
|
|||
|
hitRigid.AddForceAtPosition(transform.forward * AddRigidForce, pos, ForceMode.VelocityChange);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// A projectile can be converted into a raycast if time reverts to full speed (or more)
|
|||
|
/// </summary>
|
|||
|
public virtual void MarkAsRaycastBullet() {
|
|||
|
_checkRaycast = true;
|
|||
|
StartCoroutine(CheckForRaycast());
|
|||
|
}
|
|||
|
|
|||
|
public virtual void DoRayCastProjectile() {
|
|||
|
|
|||
|
// Raycast to hit
|
|||
|
RaycastHit hit;
|
|||
|
if (Physics.Raycast(transform.position, transform.forward, out hit, 25f, ValidLayers, QueryTriggerInteraction.Ignore)) {
|
|||
|
Quaternion decalRotation = Quaternion.FromToRotation(Vector3.forward, hit.normal);
|
|||
|
DoHitFX(hit.point, decalRotation, hit.collider);
|
|||
|
}
|
|||
|
|
|||
|
_checkRaycast = false;
|
|||
|
|
|||
|
// Done with this projectile
|
|||
|
Destroy(this.gameObject);
|
|||
|
}
|
|||
|
|
|||
|
IEnumerator CheckForRaycast() {
|
|||
|
while(this.gameObject.activeSelf && _checkRaycast) {
|
|||
|
// Switch to raycast
|
|||
|
if (Time.timeScale >= 1) {
|
|||
|
DoRayCastProjectile();
|
|||
|
}
|
|||
|
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|