projectEli/Assets/NeoFPS/Core/Weapons/ThrownWeapons/BaseThrownWeapon.cs

507 lines
18 KiB
C#
Raw Normal View History

2022-11-07 01:28:33 +00:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using NeoFPS.Constants;
using NeoSaveGames.Serialization;
using NeoSaveGames;
namespace NeoFPS
{
[RequireComponent(typeof(AudioSource))]
public abstract class BaseThrownWeapon : MonoBehaviour, IThrownWeapon, IWieldable, IDamageSource, ICrosshairDriver, IPoseHandler, INeoSerializableComponent
{
[SerializeField, NeoObjectInHierarchyField(true, required = true), Tooltip("A proxy transform for setting the position and rotation of the spawned projectile (weak throw).")]
private Transform m_ProjectileSpawnPointWeak = null;
[SerializeField, NeoObjectInHierarchyField(true, required = true), Tooltip("A proxy transform for setting the position and rotation of the spawned projectile (strong throw).")]
private Transform m_ProjectileSpawnPointStrong = null;
[SerializeField, NeoPrefabField(typeof(ThrownWeaponProjectile)), Tooltip("The prefab to throw.")]
private PooledObject m_SpawnedProjectile = null;
[SerializeField, NeoObjectInHierarchyField(false), Tooltip("The weapon game object. This is deactivated and swapped with the pooled object during the throw animation.")]
private GameObject m_HeldObject = null;
[SerializeField, Range(0f, 1f), Tooltip("How much of the character velocity does the thrown weapon inherit (think Counter Strike).")]
private float m_InheritVelocity = 0.5f;
[SerializeField, Tooltip("The point in the animation (seconds) to swap the animated weapon with the pooled physics weapon (weak throw).")]
private float m_SpawnTimeWeak = 0.5f;
[SerializeField, Tooltip("The point in the animation (seconds) to swap the animated weapon with the pooled physics weapon (strong throw).")]
private float m_SpawnTimeStrong = 0.5f;
[SerializeField, Tooltip("The throw speed of the projectile (weak throw).")]
private float m_ThrowSpeedWeak = 5f;
[SerializeField, Tooltip("The throw speed of the projectile (strong throw).")]
private float m_ThrowSpeedStrong = 7.5f;
[SerializeField, Tooltip("The full duration of the weak throw animation.")]
private float m_ThrowDurationWeak = 3f;
[SerializeField, Tooltip("The full duration of the strong throw animation.")]
private float m_ThrowDurationStrong = 3f;
[SerializeField, Tooltip("The crosshair to show when the weapon is drawn.")]
private FpsCrosshair m_Crosshair = FpsCrosshair.Default;
[Header("Audio")]
[SerializeField, Tooltip("The audio clip when raising the weapon.")]
private AudioClip m_AudioSelect = null;
[SerializeField, Tooltip("The audio clip for a weak throw.")]
private AudioClip m_AudioThrowLight = null;
[SerializeField, Tooltip("The audio clip for a strong throw.")]
private AudioClip m_AudioThrowHeavy = null;
[Header("Animation")]
[SerializeField, Tooltip("The animator component of the weapon.")]
private Animator m_Animator = null;
[SerializeField, AnimatorParameterKey("m_Animator", AnimatorControllerParameterType.Trigger), Tooltip("The key for the AnimatorController trigger property that triggers the draw animation.")]
private string m_AnimKeyDraw = "Draw";
[SerializeField, AnimatorParameterKey("m_Animator", AnimatorControllerParameterType.Trigger), Tooltip("The key for the AnimatorController trigger property that triggers the light throw animation.")]
private string m_AnimKeyLightThrow = "ThrowLight";
[SerializeField, AnimatorParameterKey("m_Animator", AnimatorControllerParameterType.Trigger), Tooltip("The key for the AnimatorController trigger property that triggers the heavy throw animation.")]
private string m_AnimKeyHeavyThrow = "ThrowHeavy";
[SerializeField, AnimatorParameterKey("m_Animator", AnimatorControllerParameterType.Trigger), Tooltip("The trigger for the weapon lower animation (blank = no animation).")]
private string m_AnimKeyLower = string.Empty;
[SerializeField, Tooltip("The time it takes to raise the weapon.")]
private float m_DrawDuration = 0.5f;
[SerializeField, Tooltip("The time taken to lower the item on deselection.")]
private float m_LowerDuration = 0f;
private DeselectionWaitable m_DeselectionWaitable = null;
private int m_AnimHashDraw = 0;
private int m_AnimHashLower = 0;
private int m_AnimHashThrowLight = 0;
private int m_AnimHashThrowHeavy = 0;
private AudioSource m_AudioSource = null;
private Coroutine m_BlockingCoroutine = null;
private ICharacter m_Wielder = null;
private float m_DrawTimer = 0f;
private float m_ThrowDelay = 0f;
private bool m_Strong = false;
public event UnityAction onThrowLight;
public event UnityAction onThrowHeavy;
public event UnityAction<ICharacter> onWielderChanged;
public class DeselectionWaitable : Waitable
{
private float m_Duration = 0f;
private float m_StartTime = 0f;
public DeselectionWaitable(float duration)
{
m_Duration = duration;
}
public void ResetTimer()
{
m_StartTime = Time.time;
}
protected override bool CheckComplete()
{
return (Time.time - m_StartTime) > m_Duration;
}
}
public ICharacter wielder
{
get { return m_Wielder; }
private set
{
if (m_Wielder != value)
{
m_Wielder = value;
if (onWielderChanged != null)
onWielderChanged(m_Wielder);
}
}
}
public float durationLight
{
get { return m_ThrowDurationWeak; }
}
public float durationHeavy
{
get { return m_ThrowDurationStrong; }
}
#if UNITY_EDITOR
void OnValidate()
{
if (m_Animator == null)
m_Animator = GetComponentInChildren<Animator>();
m_SpawnTimeWeak = Mathf.Clamp(m_SpawnTimeWeak, 0f, 5f);
m_SpawnTimeStrong = Mathf.Clamp(m_SpawnTimeStrong, 0f, 5f);
m_ThrowSpeedWeak = Mathf.Clamp(m_ThrowSpeedWeak, 1f, 50f);
m_ThrowSpeedStrong = Mathf.Clamp(m_ThrowSpeedStrong, 1f, 50f);
m_ThrowDurationWeak = Mathf.Clamp(m_ThrowDurationWeak, 0.1f, 10f);
m_ThrowDurationStrong = Mathf.Clamp(m_ThrowDurationStrong, 0.1f, 10f);
m_DrawDuration = Mathf.Clamp(m_DrawDuration, 0f, 5f);
m_LowerDuration = Mathf.Clamp(m_LowerDuration, 0f, 5f);
}
#endif
protected virtual void Awake()
{
m_AnimHashDraw = Animator.StringToHash(m_AnimKeyDraw);
m_AnimHashLower = Animator.StringToHash(m_AnimKeyLower);
m_AnimHashThrowLight = Animator.StringToHash(m_AnimKeyLightThrow);
m_AnimHashThrowHeavy = Animator.StringToHash(m_AnimKeyHeavyThrow);
// Get the audio source
m_AudioSource = GetComponent<AudioSource>();
// Set up deselection waitable
if (m_LowerDuration > 0.001f)
m_DeselectionWaitable = new DeselectionWaitable(m_LowerDuration);
// Set up pose handler
m_PoseHandler = new PoseHandler(transform, Vector3.zero, Quaternion.identity);
}
protected virtual void Start()
{
if (wielder == null)
Destroy(gameObject);
}
void OnEnable()
{
wielder = GetComponentInParent<ICharacter>();
m_Animator.SetTrigger(m_AnimHashDraw);
if (m_DrawDuration > 0f)
m_BlockingCoroutine = StartCoroutine(DrawCoroutine(m_DrawDuration));
if (m_AudioSelect != null)
m_AudioSource.PlayOneShot(m_AudioSelect);
}
void OnDisable()
{
m_BlockingCoroutine = null;
// Reset pose
m_PoseHandler.OnDisable();
}
public void Select()
{
// Play lower animation
if (m_AnimHashDraw != -1 && m_Animator != null)
m_Animator.SetTrigger(m_AnimHashDraw);
}
public void DeselectInstant()
{ }
public Waitable Deselect()
{
// Play lower animation
if (m_AnimHashLower != 0 && m_Animator != null)
m_Animator.SetTrigger(m_AnimHashLower);
// Wait for deselection
if (m_DeselectionWaitable != null)
m_DeselectionWaitable.ResetTimer();
return m_DeselectionWaitable;
}
public void ThrowLight()
{
if (m_BlockingCoroutine == null)
{
m_Strong = false;
m_Animator.SetTrigger(m_AnimHashThrowLight);
m_BlockingCoroutine = StartCoroutine(ThrowCoroutine(m_ThrowDurationWeak, m_SpawnTimeWeak, m_ThrowSpeedWeak, m_ProjectileSpawnPointWeak));
if (m_AudioThrowLight != null)
m_AudioSource.PlayOneShot(m_AudioThrowLight, FpsCharacterAudioSource.Head);
if (onThrowLight != null)
onThrowLight();
}
}
public void ThrowHeavy()
{
if (m_BlockingCoroutine == null)
{
m_Strong = true;
m_Animator.SetTrigger(m_AnimHashThrowHeavy);
m_BlockingCoroutine = StartCoroutine(ThrowCoroutine(m_ThrowDurationStrong, m_SpawnTimeStrong, m_ThrowSpeedStrong, m_ProjectileSpawnPointStrong));
if (m_AudioThrowHeavy != null)
m_AudioSource.PlayOneShot(m_AudioThrowHeavy, FpsCharacterAudioSource.Head);
if (onThrowHeavy != null)
onThrowHeavy();
}
}
protected abstract void DecrementQuantity();
IEnumerator DrawCoroutine(float timer)
{
m_DrawTimer = timer;
while (m_DrawTimer > 0f)
{
yield return null;
m_DrawTimer -= Time.deltaTime;
}
m_BlockingCoroutine = null;
}
IEnumerator ThrowCoroutine(float duration, float delay, float speed, Transform spawnPoint)
{
m_DrawTimer = 0f;
if (delay > 0f)
{
m_ThrowDelay = delay;
while (m_ThrowDelay > 0f)
{
yield return null;
m_ThrowDelay -= Time.deltaTime;
}
}
m_HeldObject.SetActive(false);
ThrownWeaponProjectile projectile = PoolManager.GetPooledObject<ThrownWeaponProjectile>(m_SpawnedProjectile, spawnPoint.position, spawnPoint.rotation);
Vector3 velocity = spawnPoint.forward * speed;
if (m_InheritVelocity > 0f)
{
Vector3 inherited = wielder.motionController.characterController.velocity;
velocity += inherited * m_InheritVelocity;
}
projectile.Throw(velocity, this);
DecrementQuantity();
if (duration > delay)
{
m_DrawTimer = m_DrawDuration + duration - delay;
while (m_DrawTimer > m_DrawDuration)
{
yield return null;
m_DrawTimer -= Time.deltaTime;
}
}
m_HeldObject.SetActive(true);
m_BlockingCoroutine = StartCoroutine(DrawCoroutine(m_DrawTimer));
}
#region POSE
private PoseHandler m_PoseHandler = null;
public void SetPose(Vector3 position, Quaternion rotation, float duration)
{
m_PoseHandler.SetPose(position, rotation, duration);
}
public void SetPose(Vector3 position, CustomPositionInterpolation posInterp, Quaternion rotation, CustomRotationInterpolation rotInterp, float duration)
{
m_PoseHandler.SetPose(position, posInterp, rotation, rotInterp, duration);
}
public void ResetPose(float duration)
{
m_PoseHandler.ResetPose(duration);
}
public void ResetPose(CustomPositionInterpolation posInterp, CustomRotationInterpolation rotInterp, float duration)
{
m_PoseHandler.ResetPose(posInterp, rotInterp, duration);
}
void Update()
{
m_PoseHandler.UpdatePose();
}
#endregion
#region IDamageSource implementation
private DamageFilter m_OutDamageFilter = DamageFilter.AllDamageAllTeams;
public DamageFilter outDamageFilter
{
get
{
return m_OutDamageFilter;
}
set
{
m_OutDamageFilter = value;
}
}
public IController controller
{
get
{
if (wielder != null)
return wielder.controller;
else
return null;
}
}
public Transform damageSourceTransform
{
get
{
return transform;
}
}
public string description
{
get
{
return name;
}
}
#endregion
#region ICrosshairDriver IMPLEMENTATION
private bool m_HideCrosshair = false;
public FpsCrosshair crosshair
{
get { return m_Crosshair; }
//private set
//{
// m_Crosshair = value;
// if (onCrosshairChanged != null)
// onCrosshairChanged(m_Crosshair);
//}
}
private float m_Accuracy = 1f;
public float accuracy
{
get { return m_Accuracy; }
private set
{
m_Accuracy = value;
if (onAccuracyChanged != null)
onAccuracyChanged(m_Accuracy);
}
}
public event UnityAction<FpsCrosshair> onCrosshairChanged;
public event UnityAction<float> onAccuracyChanged;
public void HideCrosshair()
{
if (!m_HideCrosshair)
{
bool triggerEvent = (onCrosshairChanged != null && crosshair == FpsCrosshair.None);
m_HideCrosshair = true;
if (triggerEvent)
onCrosshairChanged(FpsCrosshair.None);
}
}
public void ShowCrosshair()
{
if (m_HideCrosshair)
{
// Reset
m_HideCrosshair = false;
// Fire event
if (onCrosshairChanged != null && crosshair != FpsCrosshair.None)
onCrosshairChanged(crosshair);
}
}
#endregion
#region INeoSerializableComponent IMPLEMENTATION
private static readonly NeoSerializationKey k_DrawTimerKey = new NeoSerializationKey("drawTimer");
private static readonly NeoSerializationKey k_ThrowDelayKey = new NeoSerializationKey("throwDelay");
private static readonly NeoSerializationKey k_AccuracyKey = new NeoSerializationKey("accuracy");
private static readonly NeoSerializationKey k_StrongKey = new NeoSerializationKey("strong");
public virtual void WriteProperties(INeoSerializer writer, NeoSerializedGameObject nsgo, SaveMode saveMode)
{
if (saveMode == SaveMode.Default)
{
// Write coroutine if relevant
if (m_BlockingCoroutine != null)
{
if (m_DrawTimer > 0f)
writer.WriteValue(k_DrawTimerKey, m_DrawTimer);
else
writer.WriteValue(k_ThrowDelayKey, m_ThrowDelay);
}
// Write properties
writer.WriteValue(k_AccuracyKey, accuracy);
writer.WriteValue(k_StrongKey, m_Strong);
}
}
public virtual void ReadProperties(INeoDeserializer reader, NeoSerializedGameObject nsgo)
{
// Read properties
float floatResult = 0f;
if (reader.TryReadValue(k_AccuracyKey, out floatResult, 1f))
accuracy = floatResult;
// Read and start coroutines if relevant
if (reader.TryReadValue(k_DrawTimerKey, out floatResult, 0f))
m_BlockingCoroutine = StartCoroutine(DrawCoroutine(floatResult));
if (reader.TryReadValue(k_ThrowDelayKey, out floatResult, 0f))
{
reader.TryReadValue(k_StrongKey, out m_Strong, false);
if (m_Strong)
{
// Calculate duration based on how far along it is
float duration = m_ThrowDurationStrong - m_SpawnTimeStrong + floatResult;
// Strong throw with new delay
m_BlockingCoroutine = StartCoroutine(ThrowCoroutine(duration, floatResult, m_ThrowSpeedStrong, m_ProjectileSpawnPointStrong));
}
else
{
// Calculate duration based on how far along it is
float duration = m_ThrowDurationWeak - m_SpawnTimeWeak + floatResult;
// Weak throw with new delay
m_BlockingCoroutine = StartCoroutine(ThrowCoroutine(duration, floatResult, m_ThrowSpeedWeak, m_ProjectileSpawnPointWeak));
}
}
}
#endregion
}
}