153 lines
4.8 KiB
C#
153 lines
4.8 KiB
C#
using UnityEngine;
|
|
|
|
namespace Code.Lab5
|
|
{
|
|
public class Projectile : MonoBehaviour
|
|
{
|
|
private bool _set;
|
|
private Vector3 _firePos;
|
|
private Vector3 _direction;
|
|
private float _speed;
|
|
private float _timeElapsed;
|
|
|
|
private void Update()
|
|
{
|
|
if (!_set)
|
|
return;
|
|
|
|
_timeElapsed += Time.deltaTime;
|
|
|
|
transform.position = _firePos + _direction * (_speed * _timeElapsed);
|
|
transform.position += Physics.gravity * (_timeElapsed * _timeElapsed) / 2.0f;
|
|
|
|
if (transform.position.y < -1.0f)
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
public void Set(Vector3 firePos, Vector3 direction, float speed)
|
|
{
|
|
_firePos = firePos;
|
|
_direction = direction.normalized;
|
|
_speed = speed;
|
|
transform.position = firePos;
|
|
_set = true;
|
|
_timeElapsed = 0f;
|
|
}
|
|
|
|
private float GetLandingTime(float height = 0.0f)
|
|
{
|
|
var position = transform.position;
|
|
|
|
var valueInt = _direction.y * _direction.y * (_speed * _speed);
|
|
valueInt -= Physics.gravity.y * 2 * (position.y - height);
|
|
|
|
if (valueInt < 0)
|
|
return -1.0f;
|
|
|
|
valueInt = Mathf.Sqrt(valueInt);
|
|
|
|
var valueAdd = -_direction.y * _speed;
|
|
var valueSub = -_direction.y * _speed;
|
|
|
|
valueAdd = (valueAdd + valueInt) / Physics.gravity.y;
|
|
valueSub = (valueSub - valueInt) / Physics.gravity.y;
|
|
|
|
if (float.IsNaN(valueAdd) && !float.IsNaN(valueSub))
|
|
return valueSub;
|
|
if (!float.IsNaN(valueAdd) && float.IsNaN(valueSub))
|
|
return valueAdd;
|
|
if (float.IsNaN(valueAdd) && float.IsNaN(valueSub))
|
|
return -1.0f;
|
|
|
|
var time = Mathf.Max(valueAdd, valueSub);
|
|
return time;
|
|
}
|
|
|
|
public Vector3 GetLandingPos(float height = 0.0f)
|
|
{
|
|
var landingPos = Vector3.zero;
|
|
var time = GetLandingTime(height);
|
|
|
|
if (time < 0.0f)
|
|
return landingPos;
|
|
|
|
landingPos.y = height;
|
|
landingPos.x = _firePos.x + _direction.x * _speed * time;
|
|
landingPos.z = _firePos.z + _direction.z * _speed * time;
|
|
|
|
return landingPos;
|
|
}
|
|
|
|
public static Vector3 GetFireDirection(Vector3 startPos, Vector3 endPos, float speed, bool useHighTrajectory = false)
|
|
{
|
|
var direction = Vector3.zero;
|
|
var delta = endPos - startPos;
|
|
|
|
var a = Vector3.Dot(Physics.gravity, Physics.gravity);
|
|
var b = -4 * (Vector3.Dot(Physics.gravity, delta) + speed * speed);
|
|
var c = 4 * Vector3.Dot(delta, delta);
|
|
|
|
var discriminant = b * b - 4 * a * c;
|
|
if (discriminant < 0)
|
|
return direction;
|
|
|
|
var sqrtDiscriminant = Mathf.Sqrt(discriminant);
|
|
|
|
var time0 = Mathf.Sqrt((-b + sqrtDiscriminant) / (2 * a));
|
|
var time1 = Mathf.Sqrt((-b - sqrtDiscriminant) / (2 * a));
|
|
|
|
float time;
|
|
|
|
switch (time0)
|
|
{
|
|
case < 0.0f when time1 < 0.0f:
|
|
return direction;
|
|
case < 0.0f:
|
|
time = time1;
|
|
break;
|
|
default:
|
|
{
|
|
if (time1 < 0.0f)
|
|
time = time0;
|
|
else
|
|
{
|
|
time = useHighTrajectory ? Mathf.Max(time0, time1) : Mathf.Min(time0, time1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
direction = 2 * delta - Physics.gravity * (time * time);
|
|
direction /= 2 * speed * time;
|
|
|
|
return direction.normalized;
|
|
}
|
|
|
|
public static bool IsTargetReachable(Vector3 startPos, Vector3 endPos, float speed)
|
|
{
|
|
var delta = endPos - startPos;
|
|
|
|
var a = Vector3.Dot(Physics.gravity, Physics.gravity);
|
|
var b = -4 * (Vector3.Dot(Physics.gravity, delta) + speed * speed);
|
|
var c = 4 * Vector3.Dot(delta, delta);
|
|
|
|
return b * b - 4 * a * c >= 0;
|
|
}
|
|
|
|
public static float GetMinimumSpeed(Vector3 startPos, Vector3 endPos)
|
|
{
|
|
var delta = endPos - startPos;
|
|
|
|
var gravityMagnitude = Physics.gravity.magnitude;
|
|
var deltaMagnitude = delta.magnitude;
|
|
var deltaY = delta.y;
|
|
|
|
var minSpeedSqr = gravityMagnitude * (deltaY + Mathf.Sqrt(deltaY * deltaY + deltaMagnitude * deltaMagnitude));
|
|
|
|
return Mathf.Sqrt(minSpeedSqr);
|
|
}
|
|
}
|
|
} |