OldBlueWater/BlueWater/Assets/02.Scripts/Player/ShipPlayer.cs
2023-10-06 14:41:16 +09:00

319 lines
9.5 KiB
C#

using System;
using System.Collections.Generic;
using Blobcreate.ProjectileToolkit;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
[SelectionBase]
public class ShipPlayer : Player
{
[Title("쉽의 기본 설정")]
private Rigidbody rb;
[Tooltip("최대 스피드")] public float maxSpeed = 10f;
[Tooltip("가속 수치")] public float acceleration = 2f;
[Tooltip("감속 수치")] public float deceleration = 2f;
[Tooltip("회전 속도")] public float turnSpeed = 10f;
[Title("레이더")]
public Collider[] radar = new Collider[10];
public List<Transform> inCameraRadar = new(10);
public Transform target;
public bool IsTargeting { get; private set; }
[Title("캐논")]
public Rigidbody projectilePrefab;
public Transform launchPoint;
public float timeOfFlight;
public Transform predictedPos;
[field: SerializeField] public List<Canon> Canons { get; private set; } = new(GlobalValue.MAX_CANON_COUNT);
[Title("Interaction")]
public bool IsIslandInteraction { get; set; }
private float rayLength;
private LayerMask groundLayer;
private Vector3 halfExtents; // 박스 크기의 절반을 나타내는 벡터값을 설정합니다.
private List<Vector3> directions = new(8);
private void Init()
{
rb = GetComponent<Rigidbody>();
GetComponentsInChildren(Canons);
rayLength = 15f;
groundLayer = LayerMask.GetMask("Ground");
halfExtents = new Vector3(5, 5, 5);
directions = new List<Vector3>(8)
{
transform.forward,
-transform.forward,
transform.right,
-transform.right,
transform.forward + transform.right,
transform.forward - transform.right,
-transform.forward + transform.right,
-transform.forward - transform.right
};
}
#region Unity Function
private void OnDrawGizmosSelected()
{
RadarDrawGizmo();
Raycast8DrawGizmo();
}
protected override void Awake()
{
Init();
}
protected override void Start()
{
GameManager.Inst.SwitchDredgeMode(true);
}
protected override void FixedUpdate()
{
HandleMovement();
}
protected override void Update()
{
FindInRadarRange();
FilterInCameraObjects();
LookAtTarget();
Raycast8Direction();
}
#endregion
#region Movement
private void MoveShipPlayer()
{
var desiredVelocity = transform.forward * (movementInput.y * maxSpeed);
var speedChange = (movementInput.y != 0 ? acceleration : deceleration) * Time.fixedDeltaTime;
rb.velocity = Vector3.MoveTowards(rb.velocity, desiredVelocity, speedChange);
}
private void RotatePlayer()
{
var turn = movementInput.x;
var turnRotation = Quaternion.Euler(0f, turn * turnSpeed, 0f);
rb.MoveRotation(rb.rotation * turnRotation);
}
private void HandleMovement()
{
if (GameManager.Inst.IsDredgeMode)
{
MoveShipPlayer();
RotatePlayer();
}
}
private void StopShipMovement()
{
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
}
#endregion
#region AssaultMode/DreadgeMode Switch
private void OnAssaultMode(InputValue value) // V
{
GameManager.Inst.SwitchAssaultMode(!GameManager.Inst.IsAssaultMode);
}
#endregion
#region Interaction Key
private void OnTargeting(InputValue value) //Q
{
if (inCameraRadar.Count == 0) return;
IsTargeting = true;
UiManager.Inst.RadarUIOnOff(IsTargeting);
FindTarget();
}
private void OnTargetingHold(InputValue value) //Q Hold
{
IsTargeting = false;
UiManager.Inst.RadarUIOnOff(IsTargeting);
}
private void OnInteractionE(InputValue value) //E
{
if (IsTargeting) UiManager.Inst.CheckRadarOverlap();
}
private void OnInteraction(InputValue value) //F
{
if (!IsIslandInteraction) return;
GameManager.Inst.SwitchAssaultMode(true);
UiManager.Inst.DefaultInteractionOnOff(false);
StopShipMovement();
}
private void OnInteractionHold(InputValue value) //F Hold
{
GameManager.Inst.SwitchInShipMode(!GameManager.Inst.IsInShipMode);
}
#endregion
private void OnZkey(InputValue value)
{
UiManager.Inst.AssaultCardInit();
}
#region TakeAim
private void OnTakeAim(InputValue value) // Space
{
GameManager.Inst.SwitchTakeAim(!GameManager.Inst.IsTakeAim);
}
#endregion
#region CanonAndRader
private void FindInRadarRange()
{
Physics.OverlapSphereNonAlloc(transform.position, GlobalValue.RADAR_RANGE, radar,
LayerMask.GetMask(GlobalValue.ENEMY_LAYER));
}
private void FilterInCameraObjects()
{
inCameraRadar.Clear();
foreach (var col in radar)
{
if (col == null) continue;
var screenPoint =
GameManager.Inst.CameraController.MainCam.WorldToViewportPoint(col.transform.position);
if (screenPoint.z > 0 && screenPoint.x >= 0 && screenPoint.x <= 1 && screenPoint.y >= 0 &&
screenPoint.y <= 1)
{
inCameraRadar.Add(col.transform);
}
}
inCameraRadar.Sort((a, b) =>
Vector3.Distance(transform.position, a.position)
.CompareTo(Vector3.Distance(transform.position, b.position)));
}
private void FindTarget()
{
var oldTarget = target;
foreach (var trans in inCameraRadar)
{
if (trans.Find("TestTarget") == null) continue;
if (target != null && trans.Find("TestTarget").transform == oldTarget) continue;
target = trans.Find("TestTarget").transform;
break;
}
if (target != oldTarget)
{
UiManager.Inst.RadarTargetInit();
}
}
private void LookAtTarget()
{
if (target == null) return;
foreach (var canon in Canons)
{
canon.predictedPos = target;
canon.LookAtTarget();
UiManager.Inst.UpdateEnemyMarker(target);
}
}
#endregion
#region Raycast 8 Direction
private void Raycast8Direction()
{
if (!GameManager.Inst.IsDredgeMode) return;
var isOn = false;
foreach (Vector3 dir in directions)
{
RaycastHit hit;
if (Physics.BoxCast(transform.position, halfExtents, dir, out hit, Quaternion.identity, rayLength,
groundLayer))
{
isOn = true;
var islandInfo = hit.transform.parent.parent.GetComponent<IslandInfo>();
if (GameManager.Inst.CameraController.AssaultCam != islandInfo.IslandCam)
GameManager.Inst.CameraController.AssaultCam = islandInfo.IslandCam;
// 박스가 Ground 레이어에 닿았을 때 빨간색으로 표시
Debug.DrawRay(transform.position, dir * rayLength, Color.red);
IsIslandInteraction = true;
break;
}
// 박스가 Ground 레이어에 닿지 않았을 때 녹색으로 표시
Debug.DrawRay(transform.position, dir * rayLength, Color.green);
IsIslandInteraction = false;
}
UiManager.Inst.DefaultInteractionOnOff(isOn);
}
#endregion
#region Gizmos
private void Raycast8DrawGizmo()
{
Gizmos.color = IsIslandInteraction ? Color.red : Color.green;
foreach (Vector3 dir in directions)
{
bool isHit = Physics.BoxCast(transform.position, halfExtents, dir, out RaycastHit hitInfo, Quaternion.identity, rayLength, groundLayer);
if (isHit)
{
// 박스가 Ground 레이어에 닿았을 때 빨간색으로 표시
Gizmos.DrawWireCube(transform.position + dir.normalized * hitInfo.distance, halfExtents * 2);
}
else
{
// 박스가 Ground 레이어에 닿지 않았을 때 녹색으로 표시
Gizmos.DrawWireCube(transform.position + dir.normalized * rayLength, halfExtents * 2);
}
}
}
private void RadarDrawGizmo()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, GlobalValue.RADAR_RANGE);
}
#endregion
}
}