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;
|
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-02-02 12:48:28 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* Definitions
|
|
|
|
***********************************************************************/
|
|
|
|
#region Definitions
|
|
|
|
|
|
|
|
private enum LaunchType
|
|
|
|
{
|
|
|
|
NONE = -1,
|
|
|
|
FIXED_ANGLE,
|
|
|
|
FIXED_SPEED
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* Variables
|
|
|
|
***********************************************************************/
|
|
|
|
#region Variables
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
// 컴포넌트
|
2024-02-28 00:30:58 +00:00
|
|
|
[TitleGroup("컴포넌트"), BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private PlayerInput playerInput;
|
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private GameObject projectileObject;
|
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private Transform visualLook;
|
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private Transform launchTransform;
|
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private LineRenderer predictedLine;
|
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private GameObject hitMarker;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
2024-01-31 06:18:27 +00:00
|
|
|
[SerializeField] private GameObject directionIndicator;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private ProcessBar launchProcessBar;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("컴포넌트/컴포넌트", ShowLabel = false)]
|
|
|
|
[Required, SerializeField] private Transform instantiateObjects;
|
|
|
|
|
|
|
|
// 대포 기본 설정
|
|
|
|
[TitleGroup("대포 기본 설정")]
|
|
|
|
|
|
|
|
// 게이지
|
|
|
|
[BoxGroup("대포 기본 설정/게이지")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[Range(0.1f, 5f), Tooltip("게이지가 모두 차는데 걸리는 시간\n게이지는 0 ~ 1의 값을 가짐")]
|
|
|
|
[SerializeField] private float gaugeChargingTime = 1f;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
// 발사 기능
|
|
|
|
[BoxGroup("대포 기본 설정/발사 기능")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[Range(0f, 3f), Tooltip("발사 재사용 시간")]
|
|
|
|
[SerializeField] private float launchCooldown = 1f;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/발사 기능")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[Range(1f, 100f), Tooltip("발사될 거리 계수\nchargingGauge * 변수값")]
|
|
|
|
[SerializeField] private float distanceCoefficient = 40f;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/발사 기능")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[Tooltip("발사 방식")]
|
|
|
|
[SerializeField] private LaunchType launchType = LaunchType.FIXED_ANGLE;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/발사 기능")]
|
|
|
|
[ShowIf("@launchType == LaunchType.FIXED_SPEED"), Range(0f, 100f), Tooltip("발사 속도")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private float launchSpeed = 20f;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/발사 기능")]
|
|
|
|
[ShowIf("@launchType == LaunchType.FIXED_ANGLE"), Range(0f, 60f), Tooltip("발사 각도")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private float launchAngle = 10f;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
// 예측 기능
|
|
|
|
[BoxGroup("대포 기본 설정/예측 기능")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private bool isUsingPredictLine;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/예측 기능")]
|
|
|
|
[ShowIf("@isUsingPredictLine"), Range(1, 300), Tooltip("발사 예측선 갯수")]
|
|
|
|
[SerializeField] private int lineMaxPoint = 200;
|
2024-02-02 12:48:28 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/예측 기능")]
|
|
|
|
[ShowIf("@isUsingPredictLine"), Range(0.001f, 1f), Tooltip("발사 예측선 간격")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private float lineInterval = 0.025f;
|
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
// 기타
|
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
|
|
|
[Tooltip("랜덤으로 잡힐 물고기 마릿수 x, y를 포함하는 사이의 값")]
|
2024-01-02 21:39:53 +00:00
|
|
|
[SerializeField] private Vector2 randomCatch = new(1, 4);
|
2024-02-02 12:48:28 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private float mouseRayDistance = 500f;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
|
|
|
[SerializeField] private float rayDistance = 100f;
|
|
|
|
|
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private LayerMask hitLayer;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
2024-01-31 06:18:27 +00:00
|
|
|
[SerializeField] private LayerMask waterLayer;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("대포 기본 설정/기타")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private LayerMask boidsLayer;
|
2023-12-15 07:19:02 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
// 카메라 효과 옵션
|
2024-02-28 00:30:58 +00:00
|
|
|
[TitleGroup("카메라"), BoxGroup("카메라/카메라 흔들림 효과", ShowLabel = false)]
|
2024-01-14 17:24:48 +00:00
|
|
|
[SerializeField] private float cameraShakePower = 2f;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
[BoxGroup("카메라/카메라 흔들림 효과", ShowLabel = false)]
|
2024-01-14 17:24:48 +00:00
|
|
|
[SerializeField] private float cameraShakeDuration = 0.3f;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
// 실시간 상태
|
|
|
|
[TitleGroup("실시간 상태")]
|
2024-01-31 06:18:27 +00:00
|
|
|
[DisableIf("@true")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private bool isLaunchMode;
|
2024-01-31 06:18:27 +00:00
|
|
|
[DisableIf("@true")]
|
2024-02-02 12:48:28 +00:00
|
|
|
[SerializeField] private bool isCharging;
|
2024-01-31 06:18:27 +00:00
|
|
|
[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-02-02 12:48:28 +00:00
|
|
|
private Vector3 launchVelocity;
|
|
|
|
private Collider[] hitColliders;
|
|
|
|
private GameObject newHitMarker;
|
2024-02-28 00:30:58 +00:00
|
|
|
private RaycastHit endPositionHit;
|
2024-02-02 12:48:28 +00:00
|
|
|
|
|
|
|
private const int MAX_HIT_SIZE = 8;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Unity Events
|
|
|
|
***********************************************************************/
|
|
|
|
#region Unity Events
|
2024-01-02 21:39:53 +00:00
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
private void Start()
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
cannonRadius = projectileObject.GetComponent<SphereCollider>()?.radius ??
|
|
|
|
projectileObject.GetComponent<ParticleWeapon>().colliderRadius;
|
|
|
|
|
|
|
|
launchProcessBar = UiManager.Inst.OceanUi.ProcessBar;
|
|
|
|
hitColliders = new Collider[MAX_HIT_SIZE];
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void OnEnable()
|
|
|
|
{
|
|
|
|
playerInput.actions.FindAction("ToggleCannon").started += _ => ToggleCannon();
|
|
|
|
playerInput.actions.FindAction("FireCannon").started += _ => ChargeCannon();
|
|
|
|
playerInput.actions.FindAction("FireCannon").canceled += _ => FireCannon();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
playerInput.actions.FindAction("ToggleCannon").started -= _ => ToggleCannon();
|
2024-01-31 06:18:27 +00:00
|
|
|
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>();
|
2024-02-02 12:48:28 +00:00
|
|
|
projectileObject = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs/Particles/GrenadeFire", "GrenadeFireOBJ", ".prefab");
|
|
|
|
visualLook = transform.Find("VisualLook");
|
|
|
|
launchTransform = transform.Find("LaunchPosition");
|
|
|
|
predictedLine = transform.Find("CannonLineRenderer").GetComponent<LineRenderer>();
|
|
|
|
if (predictedLine)
|
|
|
|
{
|
|
|
|
predictedLine.gameObject.SetActive(false);
|
|
|
|
}
|
|
|
|
hitMarker = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs", "HitMarker", ".prefab");
|
2024-02-28 00:30:58 +00:00
|
|
|
// directionIndicator = transform.parent.Find("DirectionIndicator")?.gameObject;
|
|
|
|
// if (directionIndicator)
|
|
|
|
// {
|
|
|
|
// directionIndicator.SetActive(false);
|
|
|
|
// }
|
2024-02-02 12:48:28 +00:00
|
|
|
instantiateObjects = GameObject.Find("InstantiateObjects").transform;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
waterLayer = LayerMask.GetMask("Water");
|
2024-02-02 12:48:28 +00:00
|
|
|
boidsLayer = LayerMask.GetMask("Boids");
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* PlayerInput
|
|
|
|
***********************************************************************/
|
|
|
|
#region PlayerInput
|
|
|
|
|
|
|
|
private void ToggleCannon()
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
isLaunchMode = !isLaunchMode;
|
|
|
|
if (directionIndicator)
|
|
|
|
{
|
|
|
|
directionIndicator.SetActive(isLaunchMode);
|
|
|
|
}
|
|
|
|
launchProcessBar.SetActive(isLaunchMode);
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
if (!isLaunchMode)
|
2024-01-31 06:18:27 +00:00
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
isCharging = false;
|
2024-02-28 00:30:58 +00:00
|
|
|
predictedLine.gameObject.SetActive(false);
|
|
|
|
if (newHitMarker)
|
|
|
|
{
|
|
|
|
Destroy(newHitMarker);
|
|
|
|
}
|
2024-01-31 06:18:27 +00:00
|
|
|
chargingGauge = 0f;
|
|
|
|
previousGauge = chargingGauge;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetFillAmount(0f);
|
|
|
|
launchProcessBar.SetRotateZ(previousGauge * -360f);
|
|
|
|
launchProcessBar.SetRotateZ(0f);
|
|
|
|
launchProcessBar.SetSliderValue(0f);
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
private void ChargeCannon()
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
if (!isLaunchMode) return;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
if (isReloading)
|
|
|
|
{
|
|
|
|
StartCoroutine(UiManager.Inst.OceanUi.ProcessBar.ShakeProcessBarCoroutine());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
predictedLine.gameObject.SetActive(true);
|
|
|
|
if (hitMarker)
|
|
|
|
{
|
|
|
|
newHitMarker = Instantiate(hitMarker, Vector3.zero, hitMarker.transform.rotation, instantiateObjects);
|
|
|
|
newHitMarker.transform.localScale *= cannonRadius * 2f;
|
|
|
|
hitMarker.SetActive(true);
|
|
|
|
}
|
|
|
|
isCharging = true;
|
2024-01-31 06:18:27 +00:00
|
|
|
chargingGauge = 0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void FireCannon()
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
if (!isLaunchMode || !isCharging) return;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
isCharging = false;
|
|
|
|
predictedLine.gameObject.SetActive(false);
|
2024-01-31 06:18:27 +00:00
|
|
|
previousGauge = chargingGauge;
|
|
|
|
chargingGauge = 0f;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetFillAmount(0f);
|
|
|
|
launchProcessBar.SetRotateZ(previousGauge * -360f);
|
|
|
|
Launch();
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
StartCoroutine(LaunchCoolDown(launchCooldown));
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Methods
|
|
|
|
***********************************************************************/
|
|
|
|
#region Methods
|
|
|
|
|
|
|
|
private void HandleFireCannon()
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
if (!isLaunchMode) return;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
var ray = CameraManager.Inst.MainCam.ScreenPointToRay(Input.mousePosition);
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
if (Physics.Raycast(ray, out var hit, mouseRayDistance, waterLayer, QueryTriggerInteraction.Collide))
|
2024-01-31 06:18:27 +00:00
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
var directionToMouse = (hit.point - transform.position).normalized;
|
2024-01-31 06:18:27 +00:00
|
|
|
directionToMouse.y = 0f;
|
|
|
|
|
|
|
|
var lookRotation = Quaternion.LookRotation(directionToMouse);
|
2024-02-28 00:30:58 +00:00
|
|
|
var cannonRotationDirection = Quaternion.Euler(0f, lookRotation.eulerAngles.y, 0f);
|
2024-02-02 12:48:28 +00:00
|
|
|
if (directionIndicator)
|
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
directionIndicator.transform.rotation = cannonRotationDirection;
|
2024-02-02 12:48:28 +00:00
|
|
|
}
|
2024-02-28 00:30:58 +00:00
|
|
|
|
2024-01-31 06:18:27 +00:00
|
|
|
transform.rotation = cannonRotationDirection;
|
|
|
|
}
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
if (!isCharging) return;
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
if (chargingGauge < 1f)
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
if (gaugeChargingTime == 0f)
|
|
|
|
{
|
|
|
|
gaugeChargingTime = 1f;
|
|
|
|
}
|
|
|
|
|
|
|
|
chargingGauge += 1 / gaugeChargingTime * Time.deltaTime;
|
2024-01-31 06:18:27 +00:00
|
|
|
chargingGauge = Mathf.Clamp(chargingGauge, 0f, 1f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
chargingGauge = 1f;
|
|
|
|
}
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetFillAmount(chargingGauge);
|
2024-01-31 06:18:27 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
CalculateLaunchTrajectory();
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
private void CalculateLaunchTrajectory()
|
|
|
|
{
|
|
|
|
var startPosition = launchTransform.position;
|
|
|
|
var endPosition = CalculateEndPosition();
|
2024-02-28 00:30:58 +00:00
|
|
|
var d = Vector3.Distance(new Vector3(endPosition.x, 0, endPosition.z), new Vector3(startPosition.x, 0, startPosition.z));
|
|
|
|
var h = endPosition.y - startPosition.y;
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
switch (launchType)
|
|
|
|
{
|
|
|
|
case LaunchType.NONE:
|
|
|
|
break;
|
|
|
|
case LaunchType.FIXED_ANGLE:
|
2024-02-28 00:30:58 +00:00
|
|
|
var currentEulerX = Utils.NormalizeEulerAngle(visualLook.eulerAngles.x);
|
2024-02-02 12:48:28 +00:00
|
|
|
launchTransform.localRotation = Quaternion.Euler(currentEulerX + launchAngle, 0, 0);
|
2024-02-28 00:30:58 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
var theta = launchAngle * Mathf.Deg2Rad;
|
|
|
|
var g = Physics.gravity.magnitude;
|
|
|
|
var v0 = Mathf.Sqrt((g * d * d) / (2 * Mathf.Cos(theta) * Mathf.Cos(theta) * (d * Mathf.Tan(theta) - h)));
|
|
|
|
|
|
|
|
launchVelocity = CalculateVelocityFromAngleAndSpeed(startPosition, theta, v0);
|
|
|
|
break;
|
|
|
|
case LaunchType.FIXED_SPEED:
|
2024-02-28 00:30:58 +00:00
|
|
|
var targetDirection = (endPosition - startPosition).normalized;
|
|
|
|
targetDirection.y = 0;
|
|
|
|
var angle = CalculateAngleForFixedSpeed(d, h, launchSpeed);
|
2024-02-02 12:48:28 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
var launchDirection = Quaternion.LookRotation(targetDirection) * Quaternion.Euler(-angle, 0, 0);
|
|
|
|
launchTransform.rotation = launchDirection;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchVelocity = launchTransform.forward * launchSpeed;
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
// var angle = CalculateAngleForFixedSpeed(d, h, launchSpeed);
|
|
|
|
//
|
|
|
|
// launchTransform.localRotation = Quaternion.Euler(-angle, 0, 0);
|
|
|
|
// launchVelocity = launchTransform.forward * launchSpeed;
|
2024-02-02 12:48:28 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
}
|
|
|
|
|
|
|
|
PredictLine(startPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
private float CalculateAngleForFixedSpeed(float x, float y, float speed)
|
|
|
|
{
|
|
|
|
var g = Physics.gravity.magnitude;
|
|
|
|
var speedSq = speed * speed;
|
|
|
|
var underRoot = speedSq * speedSq - g * (g * x * x + 2 * y * speedSq);
|
|
|
|
|
|
|
|
if (underRoot < 0)
|
|
|
|
{
|
|
|
|
Debug.LogError("Unreachable target with given speed.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
var root = Mathf.Sqrt(underRoot);
|
|
|
|
var angle1 = Mathf.Atan((speedSq + root) / (g * x));
|
|
|
|
var angle2 = Mathf.Atan((speedSq - root) / (g * x));
|
|
|
|
|
|
|
|
var selectedAngle = Mathf.Min(angle1, angle2) * Mathf.Rad2Deg;
|
|
|
|
return selectedAngle;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Vector3 CalculateEndPosition()
|
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
var direction = transform.forward;
|
|
|
|
direction.y = 0f;
|
|
|
|
var startPosition = launchTransform.position + direction.normalized * (chargingGauge * distanceCoefficient);
|
|
|
|
Debug.DrawRay(startPosition, Vector3.down * rayDistance, Color.blue, 3f);
|
2024-02-02 12:48:28 +00:00
|
|
|
|
2024-02-28 00:30:58 +00:00
|
|
|
if (Physics.Raycast(startPosition, Vector3.down, out endPositionHit, rayDistance, hitLayer, QueryTriggerInteraction.Collide))
|
2024-02-02 12:48:28 +00:00
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
Debug.DrawRay(endPositionHit.point, Vector3.down * rayDistance, Color.red, 3f);
|
|
|
|
return endPositionHit.point;
|
2024-02-02 12:48:28 +00:00
|
|
|
}
|
|
|
|
print("?");
|
2024-02-28 00:30:58 +00:00
|
|
|
return startPosition;
|
2024-02-02 12:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private Vector3 CalculateVelocityFromAngleAndSpeed(Vector3 startPosition, float angleRad, float speed)
|
|
|
|
{
|
|
|
|
var direction = launchTransform.forward;
|
|
|
|
direction.y = 0;
|
|
|
|
direction.Normalize();
|
|
|
|
var vx = speed * Mathf.Cos(angleRad);
|
|
|
|
var vy = speed * Mathf.Sin(angleRad);
|
|
|
|
|
|
|
|
var velocity = new Vector3(direction.x * vx, vy, direction.z * vx);
|
|
|
|
return velocity;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PredictLine(Vector3 startPosition)
|
|
|
|
{
|
|
|
|
if (!isUsingPredictLine) return;
|
|
|
|
|
|
|
|
UpdateLineRender(lineMaxPoint, (0, launchTransform.position));
|
|
|
|
|
|
|
|
var currentVelocity = launchVelocity;
|
|
|
|
var predictPosition = startPosition;
|
|
|
|
for (var i = 0; i < lineMaxPoint; i++)
|
|
|
|
{
|
|
|
|
currentVelocity = GetNextPredictedPosition(currentVelocity, 0f, lineInterval);
|
|
|
|
var nextPosition = predictPosition + currentVelocity * lineInterval;
|
|
|
|
|
|
|
|
predictPosition = nextPosition;
|
|
|
|
UpdateLineRender(lineMaxPoint, (i, predictPosition));
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
if (Physics.Raycast(predictPosition - currentVelocity.normalized * lineInterval, currentVelocity.normalized, out var hit, cannonRadius * 2, hitLayer, QueryTriggerInteraction.Collide))
|
2024-02-02 12:48:28 +00:00
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
UpdateLineRender(i + 1, (i, predictPosition));
|
|
|
|
|
|
|
|
if (newHitMarker)
|
2024-02-02 12:48:28 +00:00
|
|
|
{
|
2024-02-28 00:30:58 +00:00
|
|
|
newHitMarker.transform.position = predictPosition;
|
2024-02-02 12:48:28 +00:00
|
|
|
var hitRotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
|
|
|
|
newHitMarker.transform.rotation = Quaternion.Euler(90, 0, 0) * hitRotation;
|
|
|
|
}
|
2024-02-28 00:30:58 +00:00
|
|
|
|
|
|
|
return;
|
2024-02-02 12:48:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Vector3 GetNextPredictedPosition(Vector3 currentVelocity, float drag, float increment)
|
|
|
|
{
|
|
|
|
currentVelocity += Physics.gravity * increment;
|
|
|
|
currentVelocity *= Mathf.Clamp01(1f - drag * increment);
|
|
|
|
return currentVelocity;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateLineRender(int count, (int point, Vector3 pos) pointPos)
|
|
|
|
{
|
|
|
|
predictedLine.positionCount = count;
|
|
|
|
predictedLine.SetPosition(pointPos.point, pointPos.pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerator LaunchCoolDown(float waitTime)
|
2024-01-31 06:18:27 +00:00
|
|
|
{
|
|
|
|
var time = 0f;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetSliderValue(0f);
|
|
|
|
launchProcessBar.SetActiveReloadSlider(true);
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
while (time <= waitTime)
|
|
|
|
{
|
|
|
|
time += Time.deltaTime;
|
|
|
|
var sliderValue = time > 0 ? time / waitTime : 0f;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetSliderValue(sliderValue);
|
2024-01-31 06:18:27 +00:00
|
|
|
yield return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
isReloading = false;
|
2024-02-02 12:48:28 +00:00
|
|
|
launchProcessBar.SetActiveReloadSlider(false);
|
2024-01-31 06:18:27 +00:00
|
|
|
}
|
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
private void Launch()
|
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-02-02 12:48:28 +00:00
|
|
|
var projectile = Instantiate(projectileObject, launchTransform.position, Quaternion.identity);
|
2024-01-02 21:39:53 +00:00
|
|
|
var particleWeapon = projectile.GetComponent<ParticleWeapon>();
|
2024-02-02 12:48:28 +00:00
|
|
|
particleWeapon.SetHitMarker(newHitMarker);
|
|
|
|
particleWeapon.onHitAction.AddListener(HitAction);
|
|
|
|
particleWeapon.Rb.AddForce(launchVelocity, ForceMode.VelocityChange);
|
|
|
|
|
|
|
|
isReloading = true;
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
2024-01-02 21:39:53 +00:00
|
|
|
|
2024-02-02 12:48:28 +00:00
|
|
|
private void HitAction(RaycastHit hit, float power, GameObject marker = null)
|
2024-01-02 21:39:53 +00:00
|
|
|
{
|
|
|
|
if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Water"))
|
|
|
|
{
|
2024-02-02 12:48:28 +00:00
|
|
|
var maxSize = Physics.OverlapSphereNonAlloc(hit.point, cannonRadius, hitColliders, boidsLayer,
|
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>();
|
2024-02-02 12:48:28 +00:00
|
|
|
var catchSize = Random.Range((int)randomCatch.x, (int)randomCatch.y + 1);
|
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-02-02 12:48:28 +00:00
|
|
|
|
|
|
|
if (marker)
|
|
|
|
{
|
|
|
|
Destroy(marker);
|
|
|
|
}
|
2024-01-02 21:39:53 +00:00
|
|
|
}
|
2024-01-31 06:18:27 +00:00
|
|
|
|
|
|
|
#endregion
|
2023-12-15 07:19:02 +00:00
|
|
|
}
|
|
|
|
}
|