Advertisement
CassataGames

Homing Missile 3/14/23

Mar 14th, 2023
575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.95 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using Sirenix.OdinInspector;
  4. using UnityEngine;
  5.  
  6. public class HomingBehavior : BulletBehavior
  7. {
  8.     public string targetTag = "Player"; // todo Move this into BulletCore
  9.     public Transform Target { get; private set; }
  10.     public bool IsTracking { get; private set; }
  11.     private bool _beyondMinimumDistance;
  12.    
  13.     [ShowInInspector] private float _minRange = 1f;
  14.     [ShowInInspector] private float _range = 15;
  15.     [ShowInInspector] private float _minTravelDistance = 3f;
  16.     [ShowInInspector] private float _changePerSecond = 6;
  17.     [ShowInInspector] private float _predictionTime = 0.75f;
  18.    
  19.     private Rigidbody _rb;
  20.     private Vector3 _storedVelocity;
  21.     private Vector3 _storedNewVelocity;
  22.     private Vector3 _storedPosition;
  23.  
  24.     private GameObject _visualPrefab;
  25.  
  26.     private BulletCore _bulletCore;
  27.     private TargetCore _targetPositionHistory;
  28.  
  29.     private bool TrackTarget(float distance)
  30.     {
  31.         if (distance >= _range || distance <= _minRange) return false;
  32.         if (!HasLineOfSight(_rb.position, Target, targetTag)) return false;
  33.  
  34.         var predictedPosition = InterpolatePosition(_targetPositionHistory.GetPositionHistory(), Time.deltaTime * _predictionTime);
  35.  
  36.         var directionToTarget = (predictedPosition - _rb.position).normalized;
  37.         var forwardRatio = Mathf.Clamp01(Vector3.Dot(directionToTarget, _rb.velocity.normalized));
  38.  
  39.         var rangeIntensity = Mathf.InverseLerp(10, 5, distance);
  40.         var maxVelocity = _bulletCore.speed;
  41.  
  42.         _rb.velocity = Vector3.Lerp(_rb.velocity, directionToTarget * maxVelocity, Time.deltaTime * _changePerSecond * forwardRatio * rangeIntensity);
  43.  
  44.         return forwardRatio > 0.1f;
  45.     }
  46.  
  47.     private static bool HasLineOfSight(Vector3 originPosition, Transform target, string tag)
  48.     {
  49.         var direction = target.position - originPosition;
  50.         var ray = new Ray(originPosition, direction);
  51.         return Physics.Raycast(ray, out var hitInfo, 100, int.MaxValue, QueryTriggerInteraction.Collide) && hitInfo.transform.CompareTag(tag);
  52.     }
  53.  
  54.     private static Vector3 InterpolatePosition(List<Vector3> positions, float time)
  55.     {
  56.         // Find the two positions in the history that are closest to the time we want to predict
  57.         var startIndex = Mathf.FloorToInt((positions.Count - 1) * time);
  58.         var endIndex = Mathf.CeilToInt((positions.Count - 1) * time);
  59.         var start = positions[startIndex];
  60.         var end = positions[endIndex];
  61.  
  62.         // Interpolate between the two positions based on how far we are between them
  63.         var t = (time - startIndex / (float)(positions.Count - 1)) * (positions.Count - 1);
  64.         return Vector3.Lerp(start, end, t);
  65.     }
  66.    
  67.     private static float FacingTarget(Transform originTransform, Vector3 targetPosition, float minAngle, float maxAngle)
  68.     {
  69.         var targetDirection = targetPosition - originTransform.position;
  70.         var angle = Vector3.Angle(originTransform.GetComponent<Rigidbody>().velocity.normalized, targetDirection);
  71.         var forwardFacingRatio = Mathf.InverseLerp(maxAngle, minAngle, angle);
  72.         return forwardFacingRatio;
  73.     }
  74.  
  75.     private void FixedUpdate()
  76.     {
  77.         var acquisitionDistance = Vector3.Distance(transform.position, _storedPosition);
  78.         if (acquisitionDistance >= _minTravelDistance)
  79.             _beyondMinimumDistance = true;
  80.        
  81.         if (!_beyondMinimumDistance) return;
  82.         IsTracking = TrackTarget(Vector3.Distance(_rb.position, Target.position));
  83.         FindTarget();
  84.     }
  85.  
  86.     private void OnEnable()
  87.     {
  88.         _rb = GetComponent<Rigidbody>();
  89.         _visualPrefab = Resources.Load<GameObject>("Visual Prefabs/HomingVisuals");
  90.         var v = Instantiate(_visualPrefab, transform, false);
  91.         v.transform.localPosition = new Vector3();
  92.  
  93.         FindTarget();
  94.         _storedPosition = transform.position;
  95.         _bulletCore = GetComponent<BulletCore>();
  96.     }
  97.  
  98. private void FindTarget()
  99. {
  100.     var rb = GetComponent<Rigidbody>();
  101.     var targetCores = FindObjectsOfType<TargetCore>();
  102.  
  103.     Transform bestTarget = null;
  104.     var smallestAngle = Mathf.Infinity;
  105.  
  106.     foreach (var targetCore in targetCores)
  107.     {
  108.         var directionToTarget = targetCore.transform.position - transform.position;
  109.         var angleToTarget = Vector3.Angle(directionToTarget, rb.velocity);
  110.        
  111.         if (!(angleToTarget < smallestAngle)) continue;
  112.         smallestAngle = angleToTarget;
  113.         bestTarget = targetCore.transform;
  114.     }
  115.  
  116.     if (bestTarget != null)
  117.         _targetPositionHistory = bestTarget.GetComponent<TargetCore>();
  118.     Target = bestTarget;
  119. }
  120.  
  121.     private void OnCollisionEnter()
  122.     {
  123.         FindTarget();
  124.         _beyondMinimumDistance = true;
  125.     }
  126.  
  127.     private void OnDrawGizmos()
  128.     {
  129.         if (!Application.isPlaying) return;
  130.         Gizmos.color = Color.green;
  131.         Gizmos.DrawRay(_rb.position, _rb.velocity);
  132.     }
  133. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement