Hi there,
I’ve completed Nathan’s 3rd Person Combat course and was wanting to expand the enemy targeting code so that if an enemy is behind a wall they’re not able to be targeted.
I’m trying to do this by using a foreach loop and Raycasting each of the potential targets that have entered our sphere collider (and therefore been added to our List of targets), and only getting the distance of those the ray touches, while discarding any that have a wall between the player and the enemy.
I’ve managed to get a fairly broken version of this up and running, but am wondering if anyone has any ideas on where exactly I’m going wrong, as I’m running into the following issues:
Figure 1) When I hit the targeting key in this position, everything works as expected, and we target the closest available target that’s not blocked by a wall
Figure 2) Again, when I hit the targeting key in this position, everything works as expected, and we target the closest available target that’s not blocked by a wall
Figure 3) Here things start to go wrong. We’ve got an available target to the East/SouthEast of the player, but we don’t seem to aim at them. Hitting the aim key does nothing until I move closer to the target, despite the raycast range being well above that distance.
Figure 4) In this position we target the wrong enemy, as they should be blocked by a wall, and therefore unavailable. In this situation we’d ideally be targeting the enemy to the south.
Here is the code in my Targeter script. It should all be quite similar to the code in the course, as I’m just adapting that for my own needs, but the relevant method is SelectTargetClosestToPlayer(), which is being called when the OnTarget event is triggered over in the FreeLookState.
public class Targeter : MonoBehaviour
{
[SerializeField] PlayerStateMachine playerStateMachine;
[SerializeField] List<Target> targets = new List<Target>();
[SerializeField] LayerMask obstructionLayerMask;
[SerializeField] LayerMask enemyLayerMask;
public Target CurrentTarget { get; private set; }
[SerializeField] CinemachineTargetGroup cinemachineTargetGroup;
void OnTriggerEnter(Collider other)
{
Target target = other.GetComponent<Target>();
if (target == null) { return; }
targets.Add(target);
target.OnDestroyed += RemoveTarget;
}
void OnTriggerExit(Collider other)
{
if (!other.TryGetComponent<Target>(out Target target)) { return; }
RemoveTarget(target);
}
// WRITE CODE THAT WILL RAYCAST EACH POTENTIAL TARGET AND GRAB THE DISTANCE OF
// ALL ENEMIES THAT AREN'T BEHIND A WALL
// DOESN'T WORK RIGHT NOW
public bool SelectTargetClosestToPlayer()
{
if (targets.Count == 0) { return false; }
Target closestTarget = null;
float closestTargetDistance = Mathf.Infinity;
foreach (Target target in targets)
{
Debug.DrawRay(transform.position, target.transform.position - transform.position, Color.red, 1f);
Vector3 TargetDistanceFromPlayer = target.transform.position - transform.position;
RaycastHit hit;
if (!Physics.Raycast(transform.position, target.transform.position - transform.position.normalized, out hit, playerStateMachine.RangeOfVision, obstructionLayerMask) && TargetDistanceFromPlayer.sqrMagnitude < closestTargetDistance)
{
closestTarget = target;
closestTargetDistance = TargetDistanceFromPlayer.sqrMagnitude;
}
}
if (closestTarget == null) { return false; }
CurrentTarget = closestTarget;
cinemachineTargetGroup.AddMember(CurrentTarget.transform, 1.0f, 2.0f);
return true;
}
public void Cancel()
{
if (CurrentTarget == null) { return; }
cinemachineTargetGroup.RemoveMember(CurrentTarget.transform);
CurrentTarget = null;
}
void RemoveTarget(Target target)
{
if (CurrentTarget == target)
{
cinemachineTargetGroup.RemoveMember(CurrentTarget.transform);
CurrentTarget = null;
}
target.OnDestroyed -= RemoveTarget;
targets.Remove(target);
}
}
I’m assuming that it’s still just targeting the closest enemy, although Figure 3 would be particularly confusing in this case.
Have been trying to solve this for days but there’s obviously something key that I’m not understanding about Raycasting or cycling through lists.
Any help would be massively appreciated!
Thanks in advance
Josh