lab5
This commit is contained in:
1 parent
8302032c9f
commit
1b564e47e9
16 files changed
+1990
-1
No files matched your search
@@ -0,0 +1,153 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 061a9f303af54c5c976f1aeaa6581a23
|
||||
timeCreated: 1771338965
|
||||
@@ -0,0 +1,158 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Lab5
|
||||
{
|
||||
public class ProjectileLauncher : MonoBehaviour
|
||||
{
|
||||
public GameObject projectilePrefab;
|
||||
public Transform target;
|
||||
public float launchSpeed = 20f;
|
||||
public bool useHighTrajectory;
|
||||
|
||||
public float randomRadius = 10f;
|
||||
public Vector2 centerOffset = Vector2.zero;
|
||||
public GameObject targetCirclePrefab;
|
||||
public bool showTargetCircle = true;
|
||||
public float circleLifetime = 2f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
CreateNewRandomTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Space))
|
||||
{
|
||||
LaunchProjectile();
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.R))
|
||||
{
|
||||
CreateNewRandomTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateNewRandomTarget()
|
||||
{
|
||||
var center = new Vector3(
|
||||
transform.position.x + centerOffset.x,
|
||||
0.1f,
|
||||
transform.position.z + centerOffset.y
|
||||
);
|
||||
|
||||
var randomCircle = Random.insideUnitCircle * randomRadius;
|
||||
|
||||
var randomPosition = new Vector3(
|
||||
center.x + randomCircle.x,
|
||||
0.1f,
|
||||
center.z + randomCircle.y
|
||||
);
|
||||
|
||||
if (target)
|
||||
{
|
||||
target.position = randomPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
var newTarget = new GameObject("RandomTarget")
|
||||
{
|
||||
transform =
|
||||
{
|
||||
position = randomPosition
|
||||
}
|
||||
};
|
||||
target = newTarget.transform;
|
||||
}
|
||||
|
||||
if (showTargetCircle && targetCirclePrefab)
|
||||
{
|
||||
SpawnTargetCircle(randomPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnTargetCircle(Vector3 position)
|
||||
{
|
||||
var circle = Instantiate(targetCirclePrefab, position, Quaternion.identity);
|
||||
var circlePos = circle.transform.position;
|
||||
circlePos.y = 0.05f;
|
||||
circle.transform.position = circlePos;
|
||||
|
||||
if (circleLifetime > 0)
|
||||
{
|
||||
Destroy(circle, circleLifetime);
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchProjectile()
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
var direction = Projectile.GetFireDirection(
|
||||
transform.position,
|
||||
target.position,
|
||||
launchSpeed,
|
||||
useHighTrajectory
|
||||
);
|
||||
|
||||
if (direction == Vector3.zero) return;
|
||||
|
||||
var projObj = Instantiate(projectilePrefab, transform.position, Quaternion.identity);
|
||||
var projectile = projObj.GetComponent<Projectile>();
|
||||
projectile.Set(transform.position, direction, launchSpeed);
|
||||
|
||||
CreateNewRandomTarget();
|
||||
}
|
||||
|
||||
public void SetTargetAtPosition(Vector3 position)
|
||||
{
|
||||
var targetPos = position;
|
||||
targetPos.y = 0.1f;
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
target.position = targetPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
var newTarget = new GameObject("ManualTarget")
|
||||
{
|
||||
transform =
|
||||
{
|
||||
position = targetPos
|
||||
}
|
||||
};
|
||||
target = newTarget.transform;
|
||||
}
|
||||
|
||||
if (showTargetCircle && targetCirclePrefab != null)
|
||||
{
|
||||
SpawnTargetCircle(targetPos);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = new Color(1f, 0f, 0f, 0.2f);
|
||||
var center = new Vector3(
|
||||
transform.position.x + centerOffset.x,
|
||||
0.1f,
|
||||
transform.position.z + centerOffset.y
|
||||
);
|
||||
Gizmos.DrawWireSphere(center, randomRadius);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
var reachable = Projectile.IsTargetReachable(transform.position, target.position, launchSpeed);
|
||||
Gizmos.color = reachable ? Color.green : Color.red;
|
||||
Gizmos.DrawLine(transform.position, target.position);
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawSphere(target.position, 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b27a3f528aa34fda91c0941bcdecaa7b
|
||||
timeCreated: 1771338982
|
||||
Reference in new issue
Block a user