+ UiManager의 CombatUi, OceanUi 모두 분리 각각의 씬에서 CombatUiManager, OceanUiManager로 변경 + Ocean, OceanUi input action map 추가 및 변경 input action map, uiManager 변경에 따른 Player input 로직 변경 + CombatPlayer가 죽으면 GameOverUi 추가 + 재시작 기능 추가 + 인벤토리 Ui 수정 + 슬라임 보스 로직 및 애니메이션 수정
257 lines
9.0 KiB
C#
257 lines
9.0 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 = OceanUiManager.Inst.ProcessBar;
|
|
hitColliders = new Collider[MAX_HIT_SIZE];
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
HandleLaunchCannon();
|
|
}
|
|
|
|
#endregion
|
|
|
|
/***********************************************************************
|
|
* Init Methods
|
|
***********************************************************************/
|
|
#region Init Methods
|
|
|
|
[Button("셋팅 초기화")]
|
|
private void Init()
|
|
{
|
|
cannon = GetComponent<Cannon>();
|
|
playerInput = GetComponentInParent<PlayerInput>();
|
|
}
|
|
|
|
#endregion
|
|
|
|
/***********************************************************************
|
|
* PlayerInput
|
|
***********************************************************************/
|
|
#region PlayerInput
|
|
|
|
public void OnToggleLaunchMode(InputAction.CallbackContext context)
|
|
{
|
|
if (context.started)
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnHandleCannonLaunch(InputAction.CallbackContext context)
|
|
{
|
|
if (context.performed)
|
|
{
|
|
if (!isLaunchMode) return;
|
|
|
|
if (cannon.IsReloading)
|
|
{
|
|
StartCoroutine(OceanUiManager.Inst.ProcessBar.ShakeProcessBarCoroutine());
|
|
}
|
|
else
|
|
{
|
|
isCharging = true;
|
|
chargingGauge = 0f;
|
|
cannon.StartChargeCannon();
|
|
}
|
|
}
|
|
else if (context.canceled)
|
|
{
|
|
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
|
|
}
|
|
}
|