Hello, I’m making a multiplayer game and I wan’t my enemys to target the closest player, I’ve tried a few ways of doing this but I’m getting mixed results as the enemys often don’t go for the closest player and I believe it’s because there is an issue with how the paths are being calculated or my code is wrong
ATTEMPT 1:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
using RootMotion.FinalIK;
using Unity.Netcode;
public class ClosestObjectByPath : NetworkBehaviour
{
public string targetTag = "Player";
public float updateRate = 2f; // Time between target updates
public LookAtIK lookAtIK;
private GameObject[] targets;
void Start()
{
if(isServer)
{
targets = GameObject.FindGameObjectsWithTag(targetTag);
StartCoroutine(FindClosestTargetByPath());
}
}
IEnumerator FindClosestTargetByPath()
{
while (true)
{
float shortestDistance = Mathf.Infinity;
GameObject closest = null;
Seeker seeker = GetComponent<Seeker>();
foreach (GameObject target in targets)
{
ABPath p = ABPath.Construct(transform.position, target.transform.position, null);
AstarPath.StartPath(p);
yield return StartCoroutine(p.WaitForPath()); // Wait for the path to finish calculating
if (!p.error)
{
float pathLength = p.GetTotalLength();
if (pathLength < shortestDistance)
{
shortestDistance = pathLength;
closest = target;
}
}
yield return null; // Spread out path calculations over multiple frames
}
AIDestinationSetter destinationSetter = GetComponent<AIDestinationSetter>();
if (destinationSetter != null && closest != null)
{
//get the first child of closest
Transform lookAt = closest.transform.GetChild(0);
lookAtIK.solver.target = lookAt;
destinationSetter.target = closest.transform;
}
yield return new WaitForSeconds(updateRate);
}
}
}
I then came on to this form to see if I could find any other ways I could get enemys to target the closest player and I tried this code which is semi complicated and does not work (I prefer attempt 1)
ATTEMPT #2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
using Unity.Netcode;
public class ClosestObjectByPath : NetworkBehaviour
{
public float updateRate = 2f; // Time between path updates
private Seeker seeker;
private Dictionary<Vector3, Transform> positionToTransform;
GameObject[] playerObjects;
void Start()
{
if(IsServer)
{
seeker = GetComponent<Seeker>();
InitializePositionToTransformMap();
StartCoroutine(UpdatePath());
}
}
private void InitializePositionToTransformMap()
{
positionToTransform = new Dictionary<Vector3, Transform>();
playerObjects = GameObject.FindGameObjectsWithTag("Player");
foreach (var player in playerObjects)
{
// Using the player's position as the key for the dictionary
positionToTransform[player.transform.position] = player.transform;
}
}
IEnumerator UpdatePath()
{
while (true)
{
foreach (var player in playerObjects)
{
UpdatePlayerPosition(player.transform);
}
Vector3[] positions = new Vector3[positionToTransform.Count];
positionToTransform.Keys.CopyTo(positions, 0);
seeker.StartMultiTargetPath(transform.position, positions, false, OnPathComplete);
yield return new WaitForSeconds(updateRate);
}
}
void OnPathComplete(Path p)
{
if (p.error)
{
Debug.LogError("Path error: " + p.errorLog);
}
else
{
// The closest point is the last point on the path vector
Vector3 closestPoint = p.vectorPath[p.vectorPath.Count - 1]; // This is the corrected line
// Now find the transform associated with this position
if (positionToTransform.TryGetValue(closestPoint, out Transform closestTransform))
{
AIDestinationSetter destinationSetter = GetComponent<AIDestinationSetter>();
if (destinationSetter != null)
{
destinationSetter.target = closestTransform;
}
}
}
}
// This method should be called whenever a player moves to update the mapping.
public void UpdatePlayerPosition(Transform playerTransform)
{
// Remove the old position entry
if (positionToTransform.ContainsValue(playerTransform))
{
Vector3 oldPosition = Vector3.zero;
foreach (var pair in positionToTransform)
{
if (pair.Value == playerTransform)
{
oldPosition = pair.Key;
break;
}
}
positionToTransform.Remove(oldPosition);
}
// Add the new position with the associated transform
positionToTransform[playerTransform.position] = playerTransform;
}
}
If anyone has any idea how to get this working that would be great thanks :))))))