Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using Sirenix.OdinInspector;
- using UnityEngine;
- public class HomingBehavior : BulletBehavior
- {
- public string targetTag = "Player"; // todo Move this into BulletCore
- public Transform Target { get; private set; }
- public bool IsTracking { get; private set; }
- private bool _beyondMinimumDistance;
- [ShowInInspector] private float _minRange = 1f;
- [ShowInInspector] private float _range = 15;
- [ShowInInspector] private float _minTravelDistance = 3f;
- [ShowInInspector] private float _changePerSecond = 6;
- [ShowInInspector] private float _predictionTime = 0.75f;
- private Rigidbody _rb;
- private Vector3 _storedVelocity;
- private Vector3 _storedNewVelocity;
- private Vector3 _storedPosition;
- private GameObject _visualPrefab;
- private BulletCore _bulletCore;
- private TargetCore _targetPositionHistory;
- private bool TrackTarget(float distance)
- {
- if (distance >= _range || distance <= _minRange) return false;
- if (!HasLineOfSight(_rb.position, Target, targetTag)) return false;
- var predictedPosition = InterpolatePosition(_targetPositionHistory.GetPositionHistory(), Time.deltaTime * _predictionTime);
- var directionToTarget = (predictedPosition - _rb.position).normalized;
- var forwardRatio = Mathf.Clamp01(Vector3.Dot(directionToTarget, _rb.velocity.normalized));
- var rangeIntensity = Mathf.InverseLerp(10, 5, distance);
- var maxVelocity = _bulletCore.speed;
- _rb.velocity = Vector3.Lerp(_rb.velocity, directionToTarget * maxVelocity, Time.deltaTime * _changePerSecond * forwardRatio * rangeIntensity);
- return forwardRatio > 0.1f;
- }
- private static bool HasLineOfSight(Vector3 originPosition, Transform target, string tag)
- {
- var direction = target.position - originPosition;
- var ray = new Ray(originPosition, direction);
- return Physics.Raycast(ray, out var hitInfo, 100, int.MaxValue, QueryTriggerInteraction.Collide) && hitInfo.transform.CompareTag(tag);
- }
- private static Vector3 InterpolatePosition(List<Vector3> positions, float time)
- {
- // Find the two positions in the history that are closest to the time we want to predict
- var startIndex = Mathf.FloorToInt((positions.Count - 1) * time);
- var endIndex = Mathf.CeilToInt((positions.Count - 1) * time);
- var start = positions[startIndex];
- var end = positions[endIndex];
- // Interpolate between the two positions based on how far we are between them
- var t = (time - startIndex / (float)(positions.Count - 1)) * (positions.Count - 1);
- return Vector3.Lerp(start, end, t);
- }
- private static float FacingTarget(Transform originTransform, Vector3 targetPosition, float minAngle, float maxAngle)
- {
- var targetDirection = targetPosition - originTransform.position;
- var angle = Vector3.Angle(originTransform.GetComponent<Rigidbody>().velocity.normalized, targetDirection);
- var forwardFacingRatio = Mathf.InverseLerp(maxAngle, minAngle, angle);
- return forwardFacingRatio;
- }
- private void FixedUpdate()
- {
- var acquisitionDistance = Vector3.Distance(transform.position, _storedPosition);
- if (acquisitionDistance >= _minTravelDistance)
- _beyondMinimumDistance = true;
- if (!_beyondMinimumDistance) return;
- IsTracking = TrackTarget(Vector3.Distance(_rb.position, Target.position));
- FindTarget();
- }
- private void OnEnable()
- {
- _rb = GetComponent<Rigidbody>();
- _visualPrefab = Resources.Load<GameObject>("Visual Prefabs/HomingVisuals");
- var v = Instantiate(_visualPrefab, transform, false);
- v.transform.localPosition = new Vector3();
- FindTarget();
- _storedPosition = transform.position;
- _bulletCore = GetComponent<BulletCore>();
- }
- private void FindTarget()
- {
- var rb = GetComponent<Rigidbody>();
- var targetCores = FindObjectsOfType<TargetCore>();
- Transform bestTarget = null;
- var smallestAngle = Mathf.Infinity;
- foreach (var targetCore in targetCores)
- {
- var directionToTarget = targetCore.transform.position - transform.position;
- var angleToTarget = Vector3.Angle(directionToTarget, rb.velocity);
- if (!(angleToTarget < smallestAngle)) continue;
- smallestAngle = angleToTarget;
- bestTarget = targetCore.transform;
- }
- if (bestTarget != null)
- _targetPositionHistory = bestTarget.GetComponent<TargetCore>();
- Target = bestTarget;
- }
- private void OnCollisionEnter()
- {
- FindTarget();
- _beyondMinimumDistance = true;
- }
- private void OnDrawGizmos()
- {
- if (!Application.isPlaying) return;
- Gizmos.color = Color.green;
- Gizmos.DrawRay(_rb.position, _rb.velocity);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement