- Home /
Navmesh agent teleporting
I've run into a rather irritating issue with my AI enemies. what's happening is that in the single frame after spawning, some (and only some) enemies will instantly change their position.
ive made sure that they are spawning within the nav mesh, and that the position is definitely not being set in code. it seems like the problem is coming from the navmesh agents path finding, as if they are trying to resume their old path even though ive definitely called both Stop() and ResetPath() and even giving them new targets upon spawning.
i assume that the solution is something obvious, and im simply using the nav mesh system wrong. any help would be greatly appreciated.
here is a screenshot of the scenario:
also here is the Spawn() and Kill() methods that are used for resetting the enemies. very little of it is relevant though.
void Kill(){
//variable resets
rigidbody.mass = 10;
dead = true;
canMove = false;
targeting = false;
targetArrow.renderer.enabled = false;
mesh.renderer.materials = new Material[] {deadMat, deadMat};
track1.emissionRate = 0;
track2.emissionRate = 0;
CameraManager.Shake(20f, 20);
if(navMesh.enabled){
navMesh.ResetPath();
navMesh.Stop();
}
//death effects
if(Network.isServer){
Network.Instantiate(deathExplosion, transform.position, Quaternion.identity, 0);
GM.MM.networkView.RPC("SetDead", RPCMode.All, new Vector3(Stg.Get<int>("index", settings), 1, 0));
}
else{
Instantiate(deathExplosion, transform.position, Quaternion.identity);
Instantiate(deathExplosion2, transform.position, Quaternion.identity);
}
//versus extra
if(Stg.mode == 1){
Stg.IncreaseStat("kills", 1, damageOwner.stats);
Stg.IncreaseStat("score", 10, damageOwner.stats);
Stg.IncreaseStat("deaths", 1, stats);
HUDManager.HM.hudM.showKillInfo(Stg.GetString("name", settings) + " was killed by " + Stg.GetString("name", damageOwner.settings));
respawnReset = Stg.Get<float>("respawnTime", Stg.gameS);
if(Stg.Get<int>("index", settings) == GM.masterPlayerIndex){
GM.cam.SetTarget(Stg.Get<int>("index", damageOwner.settings));
GM.hud.hudM.showDeathScreen = true;
}
}
//survival extra
if(Stg.Get<bool>("useMobDensity", Stg.gameS)){
GM.mobDensity -= Stg.Get<int>("densityValue", settings);
}
if(Stg.mode == 2){
GM.SrM.waveProgress += Stg.Get<int>("waveProgressValue", settings);
}
}
void Spawn(){
//variable resets
respawnReset = -10;
moveSpeedChange = 1;
rigidbody.mass = 1;
canFire = true;
dead = false;
canMove = true;
canDamage = true;
if(Stg.Get<bool>("useMaxHealth", settings))
Stg.Set("maxHealth", "" + Stg.Get<int>("startingHealth", Stg.gameS), settings);
health = Stg.Get<int>("maxHealth", settings) * Stg.Get<float>("healthModifier", Stg.gameS);
maxHealth = health;
SetMaterials();
if(navMesh.enabled){
navMesh.ResetPath();
navMesh.Resume();
}
//versus extra
transform.position = GM.GetSpawn(settings);
if(Stg.Get<int>("index", settings) == GM.masterPlayerIndex){
GM.cam.SetTarget(Stg.Get<int>("index", settings));
GM.hud.hudM.showDeathScreen = false;
}
//survival extra
if(Stg.Get<bool>("useMobDensity", Stg.gameS)){
GM.mobDensity += Stg.Get<int>("densityValue", settings);
}
//effects
Instantiate(spawnEff, transform.position + Vector3.up*1, Quaternion.identity);
}
I had the exact same problem. As jakethehuman mentioned, using 'Warp()' fixed the issue for me.
Example:
public void teleportTo(Vector3 point) {
//Change the position
transform.position = point;
// Warp should always be used when a Nav$$anonymous$$eshAgent is moved to keep them in-sync
if (GetComponent<AICharacterControl>()) {
GetComponent<AICharacterControl>().agent.Warp(point);
}
}
From what I found, the agent was updating the position with very little regards to what you set it to. 'Warp' appears to keep the agent informed as to what you want.
Answer by jakethehuman · Dec 15, 2015 at 09:49 PM
You can do that or use Warp().
This is the best solution for teleporting while using a nav mesh.
Warp is the correct solution. The other one did not work for me.
Answer by Curb · Sep 29, 2014 at 11:48 AM
I had a similar issue not too long ago.. What worked for me was making sure to turn off the gameobject before moving it, even if you're instancing the object and positioning it in the same frame. In hindsight, it would probably also work by disabling the agent component, or perhaps even by setting agent.updateposition to false before moving..
As to why that worked for me my guess would be that when you're instancing an object it spawns it at world coordinate zero, and then tries to move it to the proper position, but because the agent is active during the positioning, it'll have trouble getting across a gap and get stuck somewhere.
disabling the navmesh component works aswell like this guy said and then reenable after a certain time.
thank you! disabling the nav$$anonymous$$esh agent and then using a coroutine to enable a few frames later seems to have worked.
on a side note, what would be the best way to temporarily pause enemies on a path? e.g. i need my enemies to stay frozen for a couple of seconds when a round stars, and then again when the round is over (similar to games like TF2 or any CoD). what would be the best way of doing this?
if you move enemies with nav$$anonymous$$eshAgent you can do something like at the begin of the round: agent.Stop(); yield WaitForSeconds(number_of_second_before_begin); agent.Resume();
if you use simple moving with a speed variable you can do in script: speed=0; yield WaitForSeconds(number_of_second_before_begin); speed=15 (for example)
Your answer
Follow this Question
Related Questions
Spawning System 1 Answer
How to make something happen over time? 1 Answer
transform.position sends object to wrong position 1 Answer
How to increment value of axis when something happens 2 Answers
transform position player teleport 0 Answers