2024-01-31 06:18:27 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections;
|
2023-12-15 07:19:02 +00:00
|
|
|
using Sirenix.OdinInspector;
|
|
|
|
using UnityEngine;
|
2024-01-31 06:18:27 +00:00
|
|
|
using UnityEngine.InputSystem;
|
|
|
|
using UnityEngine.Serialization;
|
2024-01-14 17:24:48 +00:00
|
|
|
using Random = UnityEngine.Random;
|
2023-12-15 07:19:02 +00:00
|
|
|
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
|
|
namespace BlueWaterProject
|
|
|
|
{
|
|
|
|
public class Cannon : MonoBehaviour
|
|
|
|
{
|
2024-01-31 06:18:27 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* Variables
|
|
|
|
***********************************************************************/
|
|
|
|
#region Variables
|
|
|
|
|
2023-12-17 19:50:44 +00:00
|
|
|
[Title("초기화 방식")]
|
|
|
|
[SerializeField] private bool autoInit = true;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
[Title("컴포넌트")]
|
|
|
|
[SerializeField] private PlayerInput playerInput;
|
2023-12-15 07:19:02 +00:00
|
|
|
[SerializeField] private GameObject projectileObj;
|
|
|
|
[SerializeField] private Transform firePos;
|
2024-01-31 06:18:27 +00:00
|
|
|
[SerializeField] private GameObject directionIndicator;
|
|
|
|
[SerializeField] private ProcessBar cannonProcessBar;
|
|
|
|
|
|
|
|
[Title("대포 변수")]
|
|
|
|
[SerializeField] private float cannonCooldown = 1f;
|
|
|
|
[SerializeField] private float chargingSpeed = 1f;
|
2024-01-14 17:24:48 +00:00
|
|
|
[Range(0f, 0.5f)]
|
|
|
|
[SerializeField] private float fireAngle = 0.2f;
|
2024-01-31 06:18:27 +00:00
|
|
|
[SerializeField] private float launchSpeed = 75f;
|
|
|
|
[SerializeField] private float launchAngle = 30f;
|
2024-01-02 21:39:53 +00:00
|
|
|
[SerializeField] private Vector2 randomCatch = new(1, 4);
|
2024-01-31 06:18:27 +00:00
|
|
|
[SerializeField] private LayerMask waterLayer;
|
|
|
|
[SerializeField] private LayerMask targetLayer;
|
2023-12-15 07:19:02 +00:00
|
|
|
|
2023-12-17 19:50:44 +00:00
|
|
|
[Title("캐논 발사 카메라 효과")]
|
2024-01-14 17:24:48 +00:00
|
|
|
[SerializeField] private float cameraShakePower = 2f;
|
|
|
|
[SerializeField] private float cameraShakeDuration = 0.3f;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
[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;
|
2023-12-17 19:50:44 +00:00
|
|
|
|
2024-01-02 21:39:53 +00:00
|
|
|
private float cannonRadius;
|
2024-01-18 07:21:07 +00:00
|
|
|
private Collider[] hitColliders = new Collider[3];
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Unity Events
|
|
|
|
***********************************************************************/
|
|
|
|
#region Unity Events
|
2024-01-02 21:39:53 +00:00
|
|
|
|
2023-12-17 19:50:44 +00:00
|
|
|
private void Awake()
|
|
|
|
{
|
|
|
|
if (autoInit)
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
}
|
2023-12-15 07:19:02 +00:00
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
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
|
|
|
|
|
2023-12-15 07:19:02 +00:00
|
|
|
[Button("셋팅 초기화")]
|
|
|
|
private void Init()
|
|
|
|
{
|
2024-01-31 06:18:27 +00:00
|
|
|
playerInput = GetComponentInParent<PlayerInput>();
|
2023-12-15 07:19:02 +00:00
|
|
|
projectileObj = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs/Particles/GrenadeFire", "GrenadeFireOBJ", ".prefab");
|
|
|
|
firePos = transform.Find("FirePos");
|
2024-01-31 06:18:27 +00:00
|
|
|
directionIndicator = transform.parent.Find("DirectionIndicator").gameObject;
|
|
|
|
directionIndicator.SetActive(false);
|
|
|
|
|
2024-01-02 21:39:53 +00:00
|
|
|
cannonRadius = projectileObj.GetComponent<SphereCollider>()?.radius ??
|
|
|
|
projectileObj.GetComponent<ParticleWeapon>().colliderRadius;
|
2024-01-31 06:18:27 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
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)
|
2023-12-15 07:19:02 +00:00
|
|
|
{
|
2023-12-17 19:50:44 +00:00
|
|
|
VisualFeedbackManager.Inst.CameraShake(CameraManager.Inst.OceanCamera.BaseShipCam, cameraShakePower, cameraShakeDuration);
|
2024-01-14 17:24:48 +00:00
|
|
|
var addAngle = chargingGauge * fireAngle;
|
|
|
|
var firePosRotation = firePos.rotation.eulerAngles;
|
|
|
|
firePosRotation.x -= addAngle;
|
|
|
|
var projectile = Instantiate(projectileObj, firePos.position, Quaternion.Euler(firePosRotation));
|
2024-01-02 21:39:53 +00:00
|
|
|
var particleWeapon = projectile.GetComponent<ParticleWeapon>();
|
|
|
|
particleWeapon.onHitAction.AddListener(HandleCannonHit);
|
2024-01-31 06:18:27 +00:00
|
|
|
projectile.GetComponent<Rigidbody>().velocity = projectile.transform.forward * launchSpeed;
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
2024-01-02 21:39:53 +00:00
|
|
|
|
|
|
|
private void HandleCannonHit(RaycastHit hit, float power)
|
|
|
|
{
|
|
|
|
if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Water"))
|
|
|
|
{
|
2024-01-31 06:18:27 +00:00
|
|
|
var maxSize = Physics.OverlapSphereNonAlloc(hit.point, cannonRadius, hitColliders, targetLayer,
|
2024-01-18 07:21:07 +00:00
|
|
|
QueryTriggerInteraction.Collide);
|
2024-01-02 21:39:53 +00:00
|
|
|
|
2024-01-18 07:21:07 +00:00
|
|
|
for (var i = 0; i < maxSize; i++)
|
2024-01-02 21:39:53 +00:00
|
|
|
{
|
2024-01-18 07:21:07 +00:00
|
|
|
var hitBoids = hitColliders[i].GetComponentInParent<Boids>();
|
|
|
|
var catchSize = Random.Range((int)randomCatch.x, (int)randomCatch.y);
|
2024-01-21 17:42:31 +00:00
|
|
|
hitBoids.CatchBoid(hitColliders[i], catchSize);
|
2024-01-02 21:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hit.transform.GetComponent<IDamageable>()?.TakeDamage(power);
|
|
|
|
}
|
|
|
|
}
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
#endregion
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
|
|
|
}
|