ThrowBall/Assets/Plugins/RayFire/Scripts/Components/RayfireBlade.cs

424 lines
12 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RayFire
{
[AddComponentMenu ("RayFire/Rayfire Blade")]
[HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-blade-component/")]
public class RayfireBlade : MonoBehaviour
{
/// <summary>
/// Rayfire Blade cut type.
/// </summary>
public enum CutType
{
Enter = 0,
Exit = 1,
EnterExit = 2
}
/// <summary>
/// Rayfire Blade action type.
/// </summary>
public enum ActionType
{
Slice = 0,
Demolish = 1
}
// UI
public ActionType actionType = ActionType.Slice;
public CutType onTrigger = CutType.Exit;
public PlaneType sliceType = PlaneType.XY;
public float damage;
public bool skin;
public float force = 1f;
public bool affectInactive;
public float cooldown = 2f;
public string tagFilter = "Untagged";
public int mask = -1;
public List<GameObject> targets;
public RayfireRigid rigid;
public Transform transForm;
public Vector3[] enterPlane;
public Vector3[] exitPlane;
public Collider colLider;
// Non serialized
[NonSerialized] public bool coolDownState;
[NonSerialized] Vector3 posEnter;
[NonSerialized] Vector3 posExit;
// Event
public RFSliceEvent sliceEvent = new RFSliceEvent();
// TODO
// RFSliceData sliceData;
// check if one slice creates two halfs in one take
// do not precap, but slice with cap (precap:true, removeCap:true)
// plane to bound intersection check first `Plane.GetSide`.
/// /////////////////////////////////////////////////////////
/// Common
/// /////////////////////////////////////////////////////////
// Awake
void Awake()
{
// Set components
DefineComponents();
}
// Define components
void DefineComponents()
{
transForm = GetComponent<Transform>();
// Check collider
colLider = GetComponent<Collider>();
// No collider. Add own
if (colLider == null)
colLider = gameObject.AddComponent<MeshCollider>();
// Set convex for mesh collider
if (colLider is MeshCollider)
((MeshCollider)colLider).convex = true;
// Set trigger state
colLider.isTrigger = true;
// Set rigidbody for skinned mesh
if (skin == true)
{
Rigidbody rb = GetComponent<Rigidbody>();
if (rb == null)
{
rb = gameObject.AddComponent<Rigidbody>();
rb.isKinematic = true;
rb.useGravity = false;
}
}
coolDownState = false;
}
/// /////////////////////////////////////////////////////////
/// Triggers
/// /////////////////////////////////////////////////////////
// Check for trigger
void OnTriggerEnter (Collider col)
{
TriggerEnter (col);
}
// Exit trigger
void OnTriggerExit (Collider col)
{
TriggerExit (col);
}
// Trigger enter
void TriggerEnter (Collider col)
{
// Skip trigger colliders
if (col.isTrigger == true)
return;
// Save enter position
posEnter = transForm.position;
// Enter
if (onTrigger == CutType.Enter)
{
if (actionType == ActionType.Slice)
Slice (col.gameObject, GetSlicePlane());
else
Demolish (col.gameObject);
}
// Remember enter plane
else if (onTrigger == CutType.EnterExit)
{
// Set enter plane
if (actionType == ActionType.Slice)
enterPlane = GetSlicePlane();
}
}
// Trigger exit
void TriggerExit (Collider col)
{
// Skip trigger colliders
if (col.isTrigger == true)
return;
// Save exit position
posExit = transForm.position;
// Exit
if (onTrigger == CutType.Exit)
{
if (actionType == ActionType.Slice)
Slice (col.gameObject, GetSlicePlane());
else
Demolish (col.gameObject);
}
// Remember exit plane and calculate average plane
else if (onTrigger == CutType.EnterExit)
{
if (actionType == ActionType.Slice)
{
// Get exit plane
exitPlane = GetSlicePlane();
// Get slice plane by enter plane and exit plane
Vector3[] slicePlane = new Vector3[2];
slicePlane[0] = (enterPlane[0] + exitPlane[0]) / 2f;
slicePlane[1] = (enterPlane[1] + exitPlane[1]) / 2f;
// Slice
Slice (col.gameObject, slicePlane);
}
else
Demolish (col.gameObject);
}
}
/// /////////////////////////////////////////////////////////
/// Demolition
/// /////////////////////////////////////////////////////////
// Demolish
void Demolish(GameObject targetObject)
{
// Filter check
if (FilterCheck(targetObject) == false)
return;
// Get RayFire script
rigid = targetObject.GetComponent<RayfireRigid>();
// No Rayfire Rigid script
if (rigid == null)
return;
// No demolition allowed
if (rigid.dmlTp == DemolitionType.None)
return;
// Available for demolition
if (rigid.State() == false)
return;
// Apply damage
if (ApplyDamage (rigid, damage) == false)
return;
// Start Cooldown
StartCoroutine (CooldownCor());
// Demolish
rigid.limitations.demolitionShould = true;
RayfireMan.inst.AddToDemolitionCor (rigid);
}
/// /////////////////////////////////////////////////////////
/// Cooldown
/// /////////////////////////////////////////////////////////
// Cache physics data for fragments
IEnumerator CooldownCor ()
{
if (cooldown > 0 && coolDownState == false)
{
SetCooldown(true);
yield return new WaitForSeconds (cooldown);
SetCooldown(false);
}
}
// Set cooldown state
void SetCooldown(bool state)
{
coolDownState = state;
}
// Filter check
bool FilterCheck(GameObject targetObject)
{
// Cooldown check
if (coolDownState == true)
return false;
// Check tag
if (tagFilter != "Untagged" && !targetObject.CompareTag (tagFilter))
return false;
// Check layer
if (LayerCheck (targetObject.layer) == false)
return false;
return true;
}
/// /////////////////////////////////////////////////////////
/// Slicing
/// /////////////////////////////////////////////////////////
// Slice target
public void SliceTarget()
{
if (targets != null && targets.Count > 0)
for (int i = 0; i < targets.Count; i++)
if (targets[i] != null)
Slice (targets[i], GetSlicePlane());
}
// Slice collider by blade
void Slice (GameObject targetObject, Vector3[] slicePlane)
{
// Filter check
if (FilterCheck(targetObject) == false)
return;
// Get RayFire script
rigid = targetObject.GetComponent<RayfireRigid>();
// No Rayfire Rigid script
if (rigid == null)
return;
// No demolition allowed
if (rigid.dmlTp == DemolitionType.None)
return;
// Object can't be cut
if (rigid.limitations.bld == false)
return;
// Global demolition state check
if (rigid.State() == false)
return;
// Apply damage
if (damage > 0)
if (ApplyDamage (rigid, damage) == false)
return;
// Set slice data
// sliceData = GetSliceData();
// Slice object
rigid.AddSlicePlane (slicePlane);
// Set slice force
if (force > 0)
{
rigid.limitations.sliceForce = force;
rigid.limitations.affectInactive = affectInactive;
}
// Event
sliceEvent.InvokeLocalEvent (this);
RFSliceEvent.InvokeGlobalEvent (this);
// Start Cooldown
StartCoroutine (CooldownCor());
}
// Apply damage and return True if damage limit reached
bool ApplyDamage(RayfireRigid scr, float damageValue)
{
// Damage collection disabled
if (scr.damage.en == false)
return true;
// No damage
if (damageValue == 0)
return false;
// Add damage
return RFDamage.ApplyToRigid (scr, damageValue);
}
// Get two points or slice
Vector3[] GetSlicePlane()
{
// Get position and normal
Vector3[] points = new Vector3[2];
points[0] = transForm.position;
// Slice plane direction
if (sliceType == PlaneType.XY)
points[1] = transForm.forward;
else if (sliceType == PlaneType.XZ)
points[1] = transForm.up;
else if (sliceType == PlaneType.YZ)
points[1] = transForm.right;
return points;
}
public bool HasTargets { get { return targets != null && targets.Count > 0; } }
/// /////////////////////////////////////////////////////////
/// Other
/// /////////////////////////////////////////////////////////
// Check if object layer is in layer mask
bool LayerCheck (int layerId)
{
return mask == (mask | (1 << layerId));
}
}
}
/*
public class RFSliceData
{
public Vector3 planePos;
public Vector3 planeDir;
public Vector3 swingDir;
public float swingStr;
public float force;
public float damage;
// Get two points or slice
RFSliceData GetSliceData()
{
RFSliceData data = new RFSliceData();
// Plane position and direction
data.planePos = transForm.position;
if (sliceType == PlaneType.XY)
data.planeDir = transForm.forward;
else if (sliceType == PlaneType.XZ)
data.planeDir = transForm.up;
else if (sliceType == PlaneType.YZ)
data.planeDir = transForm.right;
// Swing direction and strength
data.swingDir = (posExit - posEnter).normalized;
data.swingStr = (posExit - posEnter).magnitude;
// Blade props
data.force = force;
data.damage = damage;
return data;
}
}
*/