- Home /
The question is answered, right answer was accepted
How to make the bot not check the distance from itself to itself?
All AI bots using this script have the same tag. How to make the bot not check the distance from itself to itself?
using System.Collections;
using System.Collections.Generic;
using System.Data;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
public class NewBehaviourScript : MonoBehaviour
{
NavMeshAgent _navMeshAgent;
private GameObject player;
private GameObject ai;
private float aiPlayerDist;
private float aiAiDist;
void Start()
{
_navMeshAgent = this.GetComponent<NavMeshAgent>();
if(_navMeshAgent == null)
{
Debug.LogError("ERROR" + gameObject.name);
}
}
void Update()
{
SetDestination();
}
private void SetDestination()
{
player = GameObject.FindGameObjectWithTag("Player");
ai = GameObject.FindGameObjectWithTag("Ai");
aiPlayerDist = Vector3.Distance(player.transform.position, transform.position);
aiAiDist = Vector3.Distance(ai.transform.position, transform.position);
if (player != null || ai != null)
{
if (aiPlayerDist > aiAiDist)
{
Vector3 targetVector = ai.transform.position;
_navMeshAgent.SetDestination(targetVector);
}
else if (aiPlayerDist < aiAiDist)
{
Vector3 targetVector = player.transform.position;
_navMeshAgent.SetDestination(targetVector);
}
}
Debug.Log(aiAiDist);
}
}
When you're getting the AI object, using GameObject.FindGameObjectWithTag, the script may be getting the same object it exists on.
Answer by andrew-lukasik · Nov 11, 2020 at 03:10 PM
Do it this way:
foreach( var nextComponent in SomeComponentType.Instances )
{
if( nextComponent!=this )
{
/* not me */
}
}
More on how to create that SomeComponentType.Instances
in code below.
Enemy.cs:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[DisallowMultipleComponent]
[RequireComponent( typeof(NavMeshAgent) )]
public class Enemy : MonoBehaviour
{
public static List<Enemy> Instances = new List<Enemy>(1);
[SerializeField] NavMeshAgent _navMeshAgent;// just fill manually and be done with it
const float _aiTickRate = 0.1f;// [seconds]
void OnEnable ()
{
Instances.Add( this );
InvokeRepeating( nameof(AiTick) , _aiTickRate , _aiTickRate );
}
void OnDisable ()
{
Instances.Remove( this );
CancelInvoke( nameof(AiTick) );
}
void AiTick ()
{
Vector3 myPosition = transform.position;
// find nearest player:
Player nearestPlayer = null;
float nearestPlayerDistance = float.MaxValue;
Vector3 nearestPlayerPosition = Vector3.zero;
foreach( var nextPlayer in Player.Instances )
{
Vector3 nextPos = nextPlayer.transform.position;
float nextDist = Vector3.Distance( myPosition , nextPos );
if( nextDist<nearestPlayerDistance )
{
nearestPlayer = nextPlayer;
nearestPlayerDistance = nextDist;
nearestPlayerPosition = nextPos;
}
}
// find nearest enemy:
Enemy nearestOtherEnemy = null;
float nearestOtherEnemyDistance = float.MaxValue;
Vector3 nearestOtherEnemyPosition = Vector3.zero;
foreach( var nextEnemy in Enemy.Instances )
{
if( nextEnemy!=this )
{
Vector3 nextPos = nextEnemy.transform.position;
float nextDist = Vector3.Distance( myPosition , nextPos );
if( nextDist<nearestOtherEnemyDistance )
{
nearestOtherEnemy = nextEnemy;
nearestOtherEnemyDistance = nextDist;
nearestOtherEnemyPosition = nextPos;
}
}
}
// decide what to do about it:
if( nearestPlayer!=null )
{
_navMeshAgent.SetDestination( nearestPlayerPosition );
}
}
}
Player.cs:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[DisallowMultipleComponent]
[RequireComponent( typeof(NavMeshAgent) )]
public class Player : MonoBehaviour
{
public static List<Player> Instances = new List<Player>(1);
[SerializeField] NavMeshAgent _navMeshAgent;// just fill manually and be done with it
void OnEnable ()
{
Instances.Add( this );
}
void OnDisable ()
{
Instances.Remove( this );
}
void Update ()
{
}
}
I needed some time to understand the script you showed. I modified my code based on the one you uploaded. But it's still the same. For some reason, one of the bots is always not moving. And if there's only one bot, it doesn't move either
W przykładzie powyżej jest takie miejsce:
// decide what to do about it:
if( nearestPlayer!=null )
{
_nav$$anonymous$$eshAgent.SetDestination( nearestPlayerPosition );
}
Każe to iść temu nav$$anonymous$$eshAgent-owi do najbliższego Player-a. Gdy na scenie go nie ma to nic nie robi teraz. Także spróbuj wstawić na scenę Playera.
Player, Enemy
Aha, upewnij się jeszcze, że na scenie masz już Nav $$anonymous$$esh (geometria po której chodzi każdy Nav$$anonymous$$eshAgent)
Nav $$anonymous$$esh was on the scene practically from the beginning of the project, as was the player's object. Even so, some bots don't move. I went back to this code: using System; using System.Collections; using System.Collections.Generic; using System.Data; using UnityEditorInternal; using UnityEngine; using UnityEngine.AI; using UnityEngine.Scene$$anonymous$$anagement;
public class NewBehaviourScript : $$anonymous$$onoBehaviour
{
Nav$$anonymous$$eshAgent _nav$$anonymous$$eshAgent;
private GameObject player;
private GameObject ai;
private float aiPlayerDist;
private float aiAiDist;
void Start()
{
_nav$$anonymous$$eshAgent = this.GetComponent<Nav$$anonymous$$eshAgent>();
if(_nav$$anonymous$$eshAgent == null)
{
Debug.LogError("ERROR" + gameObject.name);
}
}
void Update()
{
SetDestination();
}
private void SetDestination()
{
player = GameObject.FindGameObjectWithTag("Player");
ai = GameObject.FindGameObjectWithTag("Ai");
aiPlayerDist = Vector3.Distance(player.transform.position, transform.position);
if (ai.transform.position != transform.position)
{
aiAiDist = Vector3.Distance(ai.transform.position, transform.position);
}
if (player != null || ai != null)
{
if (aiPlayerDist > aiAiDist)
{
Vector3 targetVector = ai.transform.position;
_nav$$anonymous$$eshAgent.SetDestination(targetVector);
}
else if (aiPlayerDist < aiAiDist)
{
Vector3 targetVector = player.transform.position;
_nav$$anonymous$$eshAgent.SetDestination(targetVector);
}
}
Debug.Log(aiAiDist);
}
}
Some bots work fine, some bots stop working after a few moves and some bots don't come out of spawn at all
Here is a super simple Follower.cs
script that should always work (one navmesh etc is in order):
[Disallow$$anonymous$$ultipleComponent]
[RequireComponent( typeof(Nav$$anonymous$$eshAgent) )]
public class Follower : $$anonymous$$onoBehaviour
{
[SerializeField] Nav$$anonymous$$eshAgent _nav$$anonymous$$eshAgent;
[SerializeField] GameObject _target;
void Update ()
{
if( _target!=null )
{
_nav$$anonymous$$eshAgent.SetDestination( _target.transform.position );
}
}
}
I simplified the code a bit, try it now. It's 3 scripts
Bot.cs for those bots:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[Disallow$$anonymous$$ultipleComponent]
[RequireComponent( typeof(Nav$$anonymous$$eshAgent) )]
public class Bot : Agent
{
new public static List<Bot> Instances = new List<Bot>(1);
[SerializeField] Nav$$anonymous$$eshAgent _nav$$anonymous$$eshAgent;// fill manually
const float _aiUpdateRate = 0.1f;// [seconds]
void OnEnable ()
{
Agent.Instances.Add( this );
Bot.Instances.Add( this );
InvokeRepeating( nameof(AI_update) , _aiUpdateRate , _aiUpdateRate );
}
void OnDisable ()
{
Agent.Instances.Remove( this );
Bot.Instances.Remove( this );
CancelInvoke( nameof(AI_update) );
}
void AI_update ()
{
Vector3 myPosition = transform.position;
// find nearest agent:
Agent nearestAgent = null;
float nearestAgentDist = float.$$anonymous$$axValue;
foreach( var nextAgent in Agent.Instances )
{
if( nextAgent!=this )
{
float nextDist = Vector3.Distance( myPosition , nextAgent.transform.position );
if( nextDist<nearestAgentDist )
{
nearestAgent = nextAgent;
nearestAgentDist = nextDist;
}
}
}
// decide what to do:
if( nearestAgent!=null )
{
_nav$$anonymous$$eshAgent.SetDestination( nearestAgent.transform.position );
}
}
#if UNITY_EDITOR
void OnDrawGizmos ()
{
if( Application.isPlaying && _nav$$anonymous$$eshAgent!=null && _nav$$anonymous$$eshAgent.isActiveAndEnabled )
{
Gizmos.DrawLine( transform.position , _nav$$anonymous$$eshAgent.destination );
}
}
#endif
}
Player.cs for, well, player:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[Disallow$$anonymous$$ultipleComponent]
[RequireComponent( typeof(Nav$$anonymous$$eshAgent) )]
public class Player : Agent
{
new public static List<Player> Instances = new List<Player>(1);
[SerializeField] Nav$$anonymous$$eshAgent _nav$$anonymous$$eshAgent;// fill manually
void OnEnable ()
{
Agent.Instances.Add( this );
Player.Instances.Add( this );
}
void OnDisable ()
{
Agent.Instances.Remove( this );
Player.Instances.Remove( this );
}
}
And an abstract Agent.cs class that both Bot.cs and Player.cs will use:
using System.Collections.Generic;
using UnityEngine;
public abstract class Agent : $$anonymous$$onoBehaviour
{
public static List<Agent> Instances = new List<Agent>();
}
It will make bots that do what you wrote they suppose to do - they will follow nearest agent, Player
and Bot
alike.
Thanks a lot. Everything works now. You helped me with a problem that I have been trying to solve for several days. I really don't know how to thank you. I'm very grateful. You also showed me some things that I didn't know about, thanks for that too
You're welcome.
And excuse some of my answers in Polish; your nickname seemed exactly like someone from PL would choose. Cheers.
Answer by Duckocide · Nov 11, 2020 at 02:35 PM
Check the objects you have found are not the same as the one running this script?
if (ai.transform != this.transform)
Instead of this aiAiDist = Vector3.Distance(ai.transform.position, transform.position); I wrote it if (ai.transform != this.transform) { aiAiDist = Vector3.Distance(ai.transform.position, this.transform.position); } All the code now looks like this
using System.Collections; using System.Collections.Generic; using System.Data; using UnityEditorInternal; using UnityEngine; using UnityEngine.AI; using UnityEngine.Scene$$anonymous$$anagement;
public class NewBehaviourScript : $$anonymous$$onoBehaviour
{
Nav$$anonymous$$eshAgent _nav$$anonymous$$eshAgent;
private GameObject player;
private GameObject ai;
private float aiPlayerDist;
private float aiAiDist;
void Start()
{
_nav$$anonymous$$eshAgent = this.GetComponent<Nav$$anonymous$$eshAgent>();
if(_nav$$anonymous$$eshAgent == null)
{
Debug.LogError("ERROR" + gameObject.name);
}
}
void Update()
{
SetDestination();
}
private void SetDestination()
{
player = GameObject.FindGameObjectWithTag("Player");
ai = GameObject.FindGameObjectWithTag("Ai");
aiPlayerDist = Vector3.Distance(player.transform.position, transform.position);
if (ai.transform.position != this.transform.position)
{
aiAiDist = Vector3.Distance(ai.transform.position, this.transform.position);
}
if (player != null || ai != null)
{
if (aiPlayerDist > aiAiDist)
{
Vector3 targetVector = ai.transform.position;
_nav$$anonymous$$eshAgent.SetDestination(targetVector);
}
else if (aiPlayerDist < aiAiDist)
{
Vector3 targetVector = player.transform.position;
_nav$$anonymous$$eshAgent.SetDestination(targetVector);
}
}
Debug.Log(aiAiDist);
}
}
Unity shows me such an error " NullReferenceException: Object reference not set to an instance of an object NewBehaviourScript.SetDestination () (at Assets/test/Scripts/NewBehaviourScript.cs:50) NewBehaviourScript.Update () (at Assets/test/Scripts/NewBehaviourScript.cs:40) "
Follow this Question
Related Questions
Distance thing with gameobject ? 4 Answers
EnemyAI Script help 1 Answer
Tagged Player working on one character but not the other 0 Answers
How to make multiple targets? 1 Answer
2D Enemy AI X-way only 1 Answer