OldBlueWater/BlueWater/Assets/02.Scripts/Player/Cannon.cs

297 lines
11 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;
using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
public class Cannon : MonoBehaviour
{
/***********************************************************************
* Variables
***********************************************************************/
#region Variables
[Title("초기화 방식")]
[SerializeField] private bool autoInit = true;
[Title("컴포넌트")]
[SerializeField] private PlayerInput playerInput;
[SerializeField] private GameObject projectileObj;
[SerializeField] private Transform firePos;
[SerializeField] private GameObject directionIndicator;
[SerializeField] private ProcessBar cannonProcessBar;
[Title("대포 변수")]
[SerializeField] private float cannonCooldown = 1f;
[SerializeField] private float chargingSpeed = 1f;
[Range(0f, 0.5f)]
[SerializeField] private float fireAngle = 0.2f;
[SerializeField] private float launchSpeed = 75f;
[SerializeField] private float launchAngle = 30f;
[SerializeField] private Vector2 randomCatch = new(1, 4);
[SerializeField] private LayerMask waterLayer;
[SerializeField] private LayerMask targetLayer;
[Title("캐논 발사 카메라 효과")]
[SerializeField] private float cameraShakePower = 2f;
[SerializeField] private float cameraShakeDuration = 0.3f;
[Title("실시간 상태")]
[DisableIf("@true")]
[SerializeField] private bool isFireMode;
[DisableIf("@true")]
[SerializeField] private bool chargingCannon;
[DisableIf("@true")]
[SerializeField] private bool isReloading;
[DisableIf("@true")]
[SerializeField] private float chargingGauge;
[DisableIf("@true")]
[SerializeField] private float previousGauge;
private float cannonRadius;
private Collider[] hitColliders = new Collider[3];
#endregion
/***********************************************************************
* Unity Events
***********************************************************************/
#region Unity Events
private void Awake()
{
if (autoInit)
{
Init();
}
}
private void Start()
{
cannonProcessBar = UiManager.Inst.OceanUi.ProcessBar;
}
private void OnEnable()
{
playerInput.actions.FindAction("ToggleCannon").started += _ => ToggleCannon();
playerInput.actions.FindAction("FireCannon").started += _ => ChargeCannon();
playerInput.actions.FindAction("FireCannon").canceled += _ => FireCannon();
}
private void OnDisable()
{
playerInput.actions.FindAction("ToggleCannon").started += _ => ToggleCannon();
playerInput.actions.FindAction("FireCannon").started -= _ => ChargeCannon();
playerInput.actions.FindAction("FireCannon").canceled -= _ => FireCannon();
}
private void Update()
{
HandleFireCannon();
}
#endregion
/***********************************************************************
* Init Methods
***********************************************************************/
#region Init Methods
[Button("셋팅 초기화")]
private void Init()
{
playerInput = GetComponentInParent<PlayerInput>();
projectileObj = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs/Particles/GrenadeFire", "GrenadeFireOBJ", ".prefab");
firePos = transform.Find("FirePos");
directionIndicator = transform.parent.Find("DirectionIndicator").gameObject;
directionIndicator.SetActive(false);
cannonRadius = projectileObj.GetComponent<SphereCollider>()?.radius ??
projectileObj.GetComponent<ParticleWeapon>().colliderRadius;
waterLayer = LayerMask.GetMask("Water");
targetLayer = LayerMask.GetMask("Boids");
}
#endregion
/***********************************************************************
* PlayerInput
***********************************************************************/
#region PlayerInput
private void ToggleCannon()
{
isFireMode = !isFireMode;
directionIndicator.SetActive(isFireMode);
cannonProcessBar.SetActive(isFireMode);
if (!isFireMode)
{
chargingCannon = false;
chargingGauge = 0f;
previousGauge = chargingGauge;
cannonProcessBar.SetFillAmount(0f);
cannonProcessBar.SetRotateZ(previousGauge * -360f);
cannonProcessBar.SetRotateZ(0f);
cannonProcessBar.SetSliderValue(0f);
}
}
private void ChargeCannon()
{
if (!isFireMode) return;
if (isReloading)
{
StartCoroutine(UiManager.Inst.OceanUi.ProcessBar.ShakeProcessBarCoroutine());
}
else
{
chargingCannon = true;
chargingGauge = 0f;
}
}
private void FireCannon()
{
if (!isFireMode || !chargingCannon) return;
chargingCannon = false;
// previousGauge = 0f ~ 1f
previousGauge = chargingGauge;
chargingGauge = 0f;
cannonProcessBar.SetFillAmount(0f);
cannonProcessBar.SetRotateZ(previousGauge * -360f);
Fire(previousGauge * 100);
isReloading = true;
StartCoroutine(CannonCoolDown(cannonCooldown));
}
#endregion
/***********************************************************************
* Methods
***********************************************************************/
#region Methods
private void HandleFireCannon()
{
if (!isFireMode) return;
var ray = CameraManager.Inst.MainCam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit, Mathf.Infinity, waterLayer))
{
var directionToMouse = hit.point - directionIndicator.transform.position;
directionToMouse.y = 0f;
var lookRotation = Quaternion.LookRotation(directionToMouse);
var indicatorRotationDirection = Quaternion.Euler(0f, lookRotation.eulerAngles.y, 0f);
var cannonRotationDirection = Quaternion.Euler(transform.rotation.eulerAngles.x, lookRotation.eulerAngles.y, 0f);
directionIndicator.transform.rotation = indicatorRotationDirection;
transform.rotation = cannonRotationDirection;
}
if (!chargingCannon) return;
if (chargingGauge < 1f)
{
chargingGauge += chargingSpeed * Time.deltaTime;
chargingGauge = Mathf.Clamp(chargingGauge, 0f, 1f);
}
else
{
chargingGauge = 1f;
}
cannonProcessBar.SetFillAmount(chargingGauge);
// if (!isFireMode) return;
//
// var ray = CameraManager.Inst.MainCam.ScreenPointToRay(Input.mousePosition);
//
// if (Physics.Raycast(ray, out var hit, Mathf.Infinity, waterLayer))
// {
// var directionToMouse = hit.point - directionIndicator.transform.position;
// directionToMouse.y = 0f;
//
// var lookRotation = Quaternion.LookRotation(directionToMouse);
// var indicatorRotationDirection = Quaternion.Euler(0f, lookRotation.eulerAngles.y, 0f);
// var cannonRotationDirection = Quaternion.Euler(cannon.transform.rotation.eulerAngles.x, lookRotation.eulerAngles.y, 0f);
// directionIndicator.transform.rotation = indicatorRotationDirection;
// cannon.transform.rotation = cannonRotationDirection;
// }
//
// if (!chargingCannon) return;
//
// if (chargingGauge < 1f)
// {
// chargingGauge += chargingSpeed * Time.deltaTime;
// chargingGauge = Mathf.Clamp(chargingGauge, 0f, 1f);
// }
// else
// {
// chargingGauge = 1f;
// }
// UiManager.Inst.OceanUi.ProcessBar.SetFillAmount(chargingGauge);
}
private IEnumerator CannonCoolDown(float waitTime)
{
var time = 0f;
cannonProcessBar.SetSliderValue(0f);
cannonProcessBar.SetActiveReloadSlider(true);
while (time <= waitTime)
{
time += Time.deltaTime;
var sliderValue = time > 0 ? time / waitTime : 0f;
cannonProcessBar.SetSliderValue(sliderValue);
yield return null;
}
isReloading = false;
cannonProcessBar.SetActiveReloadSlider(false);
}
private void Fire(float chargingGauge)
{
VisualFeedbackManager.Inst.CameraShake(CameraManager.Inst.OceanCamera.BaseShipCam, cameraShakePower, cameraShakeDuration);
var addAngle = chargingGauge * fireAngle;
var firePosRotation = firePos.rotation.eulerAngles;
firePosRotation.x -= addAngle;
var projectile = Instantiate(projectileObj, firePos.position, Quaternion.Euler(firePosRotation));
var particleWeapon = projectile.GetComponent<ParticleWeapon>();
particleWeapon.onHitAction.AddListener(HandleCannonHit);
projectile.GetComponent<Rigidbody>().velocity = projectile.transform.forward * launchSpeed;
}
private void HandleCannonHit(RaycastHit hit, float power)
{
if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Water"))
{
var maxSize = Physics.OverlapSphereNonAlloc(hit.point, cannonRadius, hitColliders, targetLayer,
QueryTriggerInteraction.Collide);
for (var i = 0; i < maxSize; i++)
{
var hitBoids = hitColliders[i].GetComponentInParent<Boids>();
var catchSize = Random.Range((int)randomCatch.x, (int)randomCatch.y);
hitBoids.CatchBoid(hitColliders[i], catchSize);
}
}
else
{
hit.transform.GetComponent<IDamageable>()?.TakeDamage(power);
}
}
#endregion
}
}