158 lines
4.2 KiB
C#
158 lines
4.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Networking;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace RoR2.Projectile;
|
|
|
|
[RequireComponent(typeof(ProjectileTargetComponent))]
|
|
[RequireComponent(typeof(TeamFilter))]
|
|
public class ProjectileDirectionalTargetFinder : MonoBehaviour
|
|
{
|
|
[Tooltip("How far ahead the projectile should look to find a target.")]
|
|
public float lookRange;
|
|
|
|
[Range(0f, 180f)]
|
|
[Tooltip("How wide the cone of vision for this projectile is in degrees. Limit is 180.")]
|
|
public float lookCone;
|
|
|
|
[Tooltip("How long before searching for a target.")]
|
|
public float targetSearchInterval = 0.5f;
|
|
|
|
[Tooltip("Will not search for new targets once it has one.")]
|
|
public bool onlySearchIfNoTarget;
|
|
|
|
[Tooltip("Allows the target to be lost if it's outside the acceptable range.")]
|
|
public bool allowTargetLoss;
|
|
|
|
[Tooltip("If set, targets can only be found when there is a free line of sight.")]
|
|
public bool testLoS;
|
|
|
|
[Tooltip("Whether or not airborne characters should be ignored.")]
|
|
public bool ignoreAir;
|
|
|
|
[Tooltip("The difference in altitude at which a result will be ignored.")]
|
|
[FormerlySerializedAs("altitudeTolerance")]
|
|
public float flierAltitudeTolerance = float.PositiveInfinity;
|
|
|
|
public UnityEvent onNewTargetFound;
|
|
|
|
[FormerlySerializedAs("ontargetLost")]
|
|
public UnityEvent onTargetLost;
|
|
|
|
private new Transform transform;
|
|
|
|
private TeamFilter teamFilter;
|
|
|
|
private ProjectileTargetComponent targetComponent;
|
|
|
|
private float searchTimer;
|
|
|
|
private bool hasTarget;
|
|
|
|
private bool hadTargetLastUpdate;
|
|
|
|
private BullseyeSearch bullseyeSearch;
|
|
|
|
private HurtBox lastFoundHurtBox;
|
|
|
|
private Transform lastFoundTransform;
|
|
|
|
private void Start()
|
|
{
|
|
if (!NetworkServer.active)
|
|
{
|
|
base.enabled = false;
|
|
return;
|
|
}
|
|
bullseyeSearch = new BullseyeSearch();
|
|
teamFilter = GetComponent<TeamFilter>();
|
|
targetComponent = GetComponent<ProjectileTargetComponent>();
|
|
transform = base.transform;
|
|
searchTimer = 0f;
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
searchTimer -= Time.fixedDeltaTime;
|
|
if (!(searchTimer <= 0f))
|
|
{
|
|
return;
|
|
}
|
|
searchTimer += targetSearchInterval;
|
|
if (allowTargetLoss && (object)targetComponent.target != null && (object)lastFoundTransform == targetComponent.target && !PassesFilters(lastFoundHurtBox))
|
|
{
|
|
SetTarget(null);
|
|
}
|
|
if (!onlySearchIfNoTarget || targetComponent.target == null)
|
|
{
|
|
SearchForTarget();
|
|
}
|
|
hasTarget = targetComponent.target != null;
|
|
if (hadTargetLastUpdate != hasTarget)
|
|
{
|
|
if (hasTarget)
|
|
{
|
|
onNewTargetFound?.Invoke();
|
|
}
|
|
else
|
|
{
|
|
onTargetLost?.Invoke();
|
|
}
|
|
}
|
|
hadTargetLastUpdate = hasTarget;
|
|
}
|
|
|
|
private bool PassesFilters(HurtBox result)
|
|
{
|
|
CharacterBody body = result.healthComponent.body;
|
|
if (!body || (ignoreAir && body.isFlying))
|
|
{
|
|
return false;
|
|
}
|
|
if (body.isFlying && !float.IsInfinity(flierAltitudeTolerance) && flierAltitudeTolerance < Mathf.Abs(result.transform.position.y - transform.position.y))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void SearchForTarget()
|
|
{
|
|
bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
|
|
bullseyeSearch.teamMaskFilter.RemoveTeam(teamFilter.teamIndex);
|
|
bullseyeSearch.filterByLoS = testLoS;
|
|
bullseyeSearch.searchOrigin = transform.position;
|
|
bullseyeSearch.searchDirection = transform.forward;
|
|
bullseyeSearch.maxDistanceFilter = lookRange;
|
|
bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
|
|
bullseyeSearch.maxAngleFilter = lookCone;
|
|
bullseyeSearch.RefreshCandidates();
|
|
IEnumerable<HurtBox> source = bullseyeSearch.GetResults().Where(PassesFilters);
|
|
SetTarget(source.FirstOrDefault());
|
|
}
|
|
|
|
private void SetTarget(HurtBox hurtBox)
|
|
{
|
|
lastFoundHurtBox = hurtBox;
|
|
lastFoundTransform = hurtBox?.transform;
|
|
targetComponent.target = lastFoundTransform;
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
Gizmos.color = Color.yellow;
|
|
Transform transform = base.transform;
|
|
Vector3 position = transform.position;
|
|
Gizmos.DrawWireSphere(position, lookRange);
|
|
Gizmos.DrawRay(position, transform.forward * lookRange);
|
|
Gizmos.DrawFrustum(position, lookCone * 2f, lookRange, 0f, 1f);
|
|
if (!float.IsInfinity(flierAltitudeTolerance))
|
|
{
|
|
Gizmos.DrawWireCube(position, new Vector3(lookRange * 2f, flierAltitudeTolerance * 2f, lookRange * 2f));
|
|
}
|
|
}
|
|
}
|