OldBlueWater/BlueWater/Assets/02.Scripts/Player/CannonController.cs
NTG 86f9d2607e Closes #213 #214 해적선 Ai 추가 및 항해 씬 취합
+ 해적선 Ai 추가
  ㄴ 패트롤, 추격, 공격 등의 패턴 적용
+ Cannon 클래스 분리
  ㄴ 캐논 자체의 기능만 남기고, Player는 CannonController와 연결해서 사용
+ Player, Pirate 용 cannon projectile 분리
+ New input system 네이밍 변경
  ㄴ ToggleCannon -> ToggleLaunchMode
  ㄴ FireCannon -> LaunchCannon
+ 해적선 Ai에 Rayfire(파괴) 기능 테스트용 추가
2024-03-05 12:47:17 +09:00

266 lines
9.4 KiB
C#

using System;
using System.Collections;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
public class CannonController : MonoBehaviour
{
/***********************************************************************
* Variables
***********************************************************************/
#region Variables
// 컴포넌트
[TitleGroup("컴포넌트"), BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
[Required, SerializeField] private Cannon cannon;
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
[Required, SerializeField] private PlayerInput playerInput;
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
[SerializeField] private ProcessBar launchProcessBar;
// 대포 기본 설정
[TitleGroup("대포 기본 설정")]
// 게이지
[BoxGroup("대포 기본 설정/게이지")]
[Range(0.1f, 5f), Tooltip("게이지가 모두 차는데 걸리는 시간\n게이지는 0 ~ 1의 값을 가짐")]
[SerializeField] private float gaugeChargingTime = 1f;
// 기타
[BoxGroup("대포 기본 설정/기타")]
[Tooltip("랜덤으로 잡힐 물고기 마릿수 x, y를 포함하는 사이의 값")]
[SerializeField] private Vector2 randomCatch = new(1, 4);
[BoxGroup("대포 기본 설정/기타")]
[SerializeField] private float mouseRayDistance = 500f;
[BoxGroup("대포 기본 설정/기타")]
[SerializeField] private LayerMask waterLayer;
[BoxGroup("대포 기본 설정/기타")]
[SerializeField] private LayerMask boidsLayer;
// 카메라 효과 옵션
[TitleGroup("카메라"), BoxGroup("카메라/카메라 흔들림 효과", ShowLabel = false)]
[SerializeField] private float cameraShakePower = 2f;
[BoxGroup("카메라/카메라 흔들림 효과", ShowLabel = false)]
[SerializeField] private float cameraShakeDuration = 0.3f;
// 실시간 상태
[TitleGroup("실시간 상태")]
[DisableIf("@true")]
[SerializeField] private bool isLaunchMode;
[DisableIf("@true")]
[SerializeField] private bool isCharging;
[DisableIf("@true")]
[SerializeField] private float chargingGauge;
[DisableIf("@true")]
[SerializeField] private float previousGauge;
private Collider[] hitColliders;
private const int MAX_HIT_SIZE = 8;
#endregion
/***********************************************************************
* Unity Events
***********************************************************************/
#region Unity Events
private void Start()
{
launchProcessBar = UiManager.Inst.OceanUi.ProcessBar;
hitColliders = new Collider[MAX_HIT_SIZE];
}
private void OnEnable()
{
playerInput.actions.FindAction("ToggleLaunchMode").started += _ => ToggleLaunchMode();
playerInput.actions.FindAction("LaunchCannon").started += _ => ChargeCannon();
playerInput.actions.FindAction("LaunchCannon").canceled += _ => LaunchCannon();
}
private void OnDisable()
{
playerInput.actions.FindAction("ToggleLaunchMode").started -= _ => ToggleLaunchMode();
playerInput.actions.FindAction("LaunchCannon").started -= _ => ChargeCannon();
playerInput.actions.FindAction("LaunchCannon").canceled -= _ => LaunchCannon();
}
private void Update()
{
HandleLaunchCannon();
}
#endregion
/***********************************************************************
* Init Methods
***********************************************************************/
#region Init Methods
[Button("셋팅 초기화")]
private void Init()
{
cannon = GetComponent<Cannon>();
playerInput = GetComponentInParent<PlayerInput>();
}
#endregion
/***********************************************************************
* PlayerInput
***********************************************************************/
#region PlayerInput
private void ToggleLaunchMode()
{
isLaunchMode = !isLaunchMode;
launchProcessBar.SetActive(isLaunchMode);
if (!isLaunchMode)
{
isCharging = false;
chargingGauge = 0f;
previousGauge = chargingGauge;
launchProcessBar.SetFillAmount(0f);
launchProcessBar.SetRotateZ(previousGauge * -360f);
launchProcessBar.SetRotateZ(0f);
launchProcessBar.SetSliderValue(0f);
cannon.ExitLaunchMode();
}
}
private void ChargeCannon()
{
if (!isLaunchMode) return;
if (cannon.IsReloading)
{
StartCoroutine(UiManager.Inst.OceanUi.ProcessBar.ShakeProcessBarCoroutine());
}
else
{
isCharging = true;
chargingGauge = 0f;
cannon.StartChargeCannon();
}
}
private void LaunchCannon()
{
if (!isLaunchMode || !isCharging) return;
isCharging = false;
previousGauge = chargingGauge;
chargingGauge = 0f;
launchProcessBar.SetFillAmount(0f);
launchProcessBar.SetRotateZ(previousGauge * -360f);
cannon.SetActivePredictLine(false);
cannon.Launch();
StartCoroutine(LaunchCoolDown(cannon.LaunchCooldown));
VisualFeedbackManager.Inst.CameraShake(CameraManager.Inst.OceanCamera.BaseShipCam, cameraShakePower, cameraShakeDuration);
}
#endregion
/***********************************************************************
* Methods
***********************************************************************/
#region Methods
private void HandleLaunchCannon()
{
if (!isLaunchMode) return;
var ray = CameraManager.Inst.MainCam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit, mouseRayDistance, waterLayer, QueryTriggerInteraction.Collide))
{
var directionToMouse = (hit.point - transform.position).normalized;
directionToMouse.y = 0f;
var lookRotation = Quaternion.LookRotation(directionToMouse);
var cannonRotationDirection = Quaternion.Euler(0f, lookRotation.eulerAngles.y, 0f);
transform.rotation = cannonRotationDirection;
}
if (!isCharging) return;
if (chargingGauge < 1f)
{
if (gaugeChargingTime == 0f)
{
gaugeChargingTime = 1f;
}
chargingGauge += 1 / gaugeChargingTime * Time.deltaTime;
chargingGauge = Mathf.Clamp(chargingGauge, 0f, 1f);
}
else
{
chargingGauge = 1f;
}
launchProcessBar.SetFillAmount(chargingGauge);
cannon.CalculateLaunchTrajectory(cannon.CalculateEndPosition(chargingGauge), true);
}
private IEnumerator LaunchCoolDown(float waitTime)
{
var time = 0f;
launchProcessBar.SetSliderValue(0f);
launchProcessBar.SetActiveReloadSlider(true);
while (time <= waitTime)
{
time += Time.deltaTime;
var sliderValue = time > 0 ? time / waitTime : 0f;
launchProcessBar.SetSliderValue(sliderValue);
yield return null;
}
cannon.IsReloading = false;
launchProcessBar.SetActiveReloadSlider(false);
}
public void HitAction(RaycastHit hit, float power, GameObject marker = null)
{
if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Water"))
{
var maxSize = Physics.OverlapSphereNonAlloc(hit.point, cannon.CannonRadius, hitColliders, boidsLayer,
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 + 1);
hitBoids.CatchBoid(hitColliders[i], catchSize);
}
}
else
{
hit.transform.GetComponent<IDamageable>()?.TakeDamage(power);
}
if (marker)
{
Destroy(marker);
}
}
#endregion
}
}