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 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 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 directions = new(8); private void Init() { rb = GetComponent(); GetComponentsInChildren(Canons); rayLength = 15f; groundLayer = LayerMask.GetMask("Ground"); halfExtents = new Vector3(5, 5, 5); directions = new List(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() { base.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 OnCancel(InputValue value) //F { } private void OnInteraction(InputValue value) //E { if (IsTargeting) UiManager.Inst.CheckRadarOverlap(); else if (!IsIslandInteraction) return; UiManager.Inst.DefaultInteractionOnOff(false); //StopShipMovement(); } private void OnInteractionHold(InputValue value) //E Hold { GameManager.Inst.SwitchInShipMode(!GameManager.Inst.IsInShipMode); } #endregion private void OnZkey(InputValue value) { UiManager.Inst.AssaultCardInit(); } #region TakeAim private void OnTakeAim(InputValue value) // Space { //if (GameManager.Inst.CurrentModeState == GlobalValue.PlayerModeState.IN_SHIP) return; //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 = CameraManager.Inst.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; // 박스가 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 } }