"Failed to create agent because it is not close enough to NavMesh"

I was working on the game in the “Core Combat Creator” course and had finished all the lessons up to “Configurable Cursors”. Now, though, when I click “play” and try to go to the next scene, it kicks me back to the first one and displays the following warning message in the console:

“Failed to create agent because it is not close enough to the NavMesh”.

After that, it kicks the game back to the first scene and sets it back to its original state as if I didn’t move around or anything. That’s when I stop the game to figure out what’s wrong. After that, I try to start it again, but it freezes and I’m forced to end the program with the task manager.
I noticed that when I tried to enter the second scene, it created a save file based in there anyway even though it wouldn’t allow me to go in, and when I try to play it freezes the game when it tries to load the character into that scene. I’ve had a number of issues related to the saving system and the second scene that I’ve tried to squish, but this one is the latest and worst.

In case it might help, below are several files that I’ve had trouble with.

SaveableEntity:

using System;
using System.Collections.Generic;
using RPG.Core;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;

namespace RPG.Saving
{
    [ExecuteAlways]
    public class SaveableEntity : MonoBehaviour
    {
        [SerializeField] string uniqueIdentifier = "";
        static Dictionary<string, SaveableEntity> globalLookup = new Dictionary<string, SaveableEntity>();

        public string GetUniqueIdentifier()
        {
            return uniqueIdentifier;
        }

        public object CaptureState()
        {
            Dictionary<string, object> state = new Dictionary<string, object>();
            foreach (ISaveable saveable in GetComponents<ISaveable>())
            {
                state[saveable.GetType().ToString()] = saveable.CaptureState();
            }
            return state;
        }

        public void RestoreState(object state)
        {
            Dictionary<string, object> stateDict = (Dictionary<string, object>)state;
            foreach (ISaveable saveable in GetComponents<ISaveable>())
            {
                string typeString = saveable.GetType().ToString();
                if (stateDict.ContainsKey(typeString))
                {
                    saveable.RestoreState(stateDict[typeString]);
                }
            }
        }

#if UNITY_EDITOR
        private void Update()
        {
            if (Application.IsPlaying(gameObject)) return;
            if (string.IsNullOrEmpty(gameObject.scene.path)) return;

            SerializedObject serializedObject = new SerializedObject(this);
            SerializedProperty property = serializedObject.FindProperty("uniqueIdentifier");

            if (string.IsNullOrEmpty(property.stringValue) || !IsUnique(property.stringValue))
            {
                property.stringValue = System.Guid.NewGuid().ToString();
                serializedObject.ApplyModifiedProperties();
            }
            
            globalLookup[property.stringValue] = this;
        }
#endif

        private bool IsUnique(string candidate)
        {
            if (!globalLookup.ContainsKey(candidate)) return true;

            if (globalLookup[candidate] == this) return true;

            if (globalLookup[candidate] == null)
            {
                globalLookup.Remove(candidate);
                return true;
            }

            if (globalLookup[candidate].GetUniqueIdentifier() != candidate)
            {
                globalLookup.Remove(candidate);
                return true;
            }

            return false;
        }
    }
}

SavingSystem:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace RPG.Saving
{
    public class SavingSystem : MonoBehaviour
    {
        public IEnumerator LoadLastScene(string saveFile)
        {
            Dictionary<string, object> state = LoadFile(saveFile);
            int buildIndex = SceneManager.GetActiveScene().buildIndex;
            if (state.ContainsKey("lastSceneBuildIndex"))
            {
                buildIndex = (int)state["lastSceneBuildIndex"];
            }
            yield return SceneManager.LoadSceneAsync(buildIndex);
            RestoreState(state);
        }        
        
        public void Save(string saveFile)
        {
            Dictionary<string, object> state = LoadFile(saveFile);
            CaptureState(state);
            SaveFile(saveFile, state);
        }

        public void Load(string saveFile)
        {
            RestoreState(LoadFile(saveFile));
        }              
        
        private void SaveFile(string saveFile, object state)
        {
            string path = GetPathFromSaveFile(saveFile);
            print("Saving to " + path);
            using (FileStream stream = File.Open(path, FileMode.Create))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, state);      
            }
        }

        private Dictionary<string, object> LoadFile(string saveFile)
        {
            string path = GetPathFromSaveFile(saveFile);
            if (!File.Exists(path))
            {
                return new Dictionary<string, object>();
            } 

            using (FileStream stream = File.Open(path, FileMode.Open))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                return (Dictionary<string, object>)formatter.Deserialize(stream);
            }
        }   

        private void CaptureState(Dictionary<string, object> state)
        {

            foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>())
            {
                state[saveable.GetUniqueIdentifier()] = saveable.CaptureState();
            }
            
            state["lastSceneBuildIndex"] = SceneManager.GetActiveScene().buildIndex;
        }

        private void RestoreState(Dictionary<string, object> state)
        {
            foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>())
            {
                string id = saveable.GetUniqueIdentifier();
                if (state.ContainsKey(id))
                {
                    saveable.RestoreState(state[id]);
                }
            }
        }
        
        private string GetPathFromSaveFile(string saveFile)
        {
            return Path.Combine(Application.persistentDataPath, saveFile + ".sav");
        }   

        public void Delete(string saveFile)
        {
            string path = GetPathFromSaveFile(saveFile);
            print("Deleting save at " + path);
            File.Delete(GetPathFromSaveFile(saveFile));
        }
    }
}

SavingWrapper:

using System;
using System.Collections;
using System.Collections.Generic;
using RPG.Saving;
using UnityEngine;

namespace RPG.SceneManagement
{
    public class SavingWrapper : MonoBehaviour
    {
        const string defaultSaveFile = "save";

        [SerializeField] float fadeInTime = 0.2f;

        private void Awake()
        {
            StartCoroutine(LoadLastScene());
        }

        private IEnumerator LoadLastScene()
        {
            yield return GetComponent<SavingSystem>().LoadLastScene(defaultSaveFile);
            Fader fader = FindObjectOfType<Fader>();
            fader.FadeOutImmediate();
            yield return fader.FadeIn(fadeInTime); 
        }

        void Update()
        {
            if (Input.GetKeyDown(KeyCode.S))
            {
                Save();
            }
            if (Input.GetKeyDown(KeyCode.L))
            {
                Load();
            }
            if (Input.GetKeyDown(KeyCode.Delete))
            {
                Delete();
            }
        }
        public void Save()
        {
            GetComponent<SavingSystem>().Save(defaultSaveFile);
        } 
        public void Load()
        {
            GetComponent<SavingSystem>().Load(defaultSaveFile);
        }
        public void Delete()
        {
            GetComponent<SavingSystem>().Delete(defaultSaveFile);
        }
    }
}

Portal:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.AI;
using RPG.Saving;

namespace RPG.SceneManagement
{
    public class Portal : MonoBehaviour
    {
        enum DestinationIdentifier
        {
            A, B, C, D, E, F, G
        }

        [SerializeField] int sceneToLoad = -1;
        [SerializeField] Transform spawnPoint;
        [SerializeField] DestinationIdentifier destination;
        [SerializeField] float fadeOutTime = 1f;
        [SerializeField] float fadeInTime = 2f;
        [SerializeField] float fadeWaitTime = 0.5f;

        private void OnTriggerEnter(Collider other)
        {
            if (other.tag == "Player")
            {
                StartCoroutine(Transition());
            }
        }
        
        private IEnumerator Transition()
        {
            if (sceneToLoad < 0)
            {
                Debug.LogError("Scene to load not set.");
                yield break; 
            }

            DontDestroyOnLoad(gameObject);

            Fader fader = FindObjectOfType<Fader>();
            SavingWrapper savingWrapper = FindObjectOfType<SavingWrapper>();

            yield return fader.FadeOut(fadeOutTime);

            savingWrapper.Save();

            yield return SceneManager.LoadSceneAsync(sceneToLoad);

            savingWrapper.Load();            

            Portal otherPortal = GetOtherPortal();
            UpdatePlayer(otherPortal);

            savingWrapper.Save();
            
            yield return new WaitForSeconds(fadeWaitTime);
            yield return fader.FadeIn(fadeInTime);

            Destroy(gameObject);
        }

        private void UpdatePlayer(Portal otherPortal)
        {
            GameObject player = GameObject.FindWithTag("Player");
            player.GetComponent<NavMeshAgent>().enabled = false;
            //player.GetComponent<NavMeshAgent>().Warp(otherPortal.spawnPoint.position);
            player.transform.position = otherPortal.spawnPoint.position;
            player.transform.rotation = otherPortal.spawnPoint.rotation;
            player.GetComponent<NavMeshAgent>().enabled = true;
        }

        private Portal GetOtherPortal()
        {
            foreach (Portal portal in FindObjectsOfType<Portal>())
            {
                if (portal == this) continue;
                if (portal.destination != destination) continue;

                return portal;
            }

            return null;
        }
    }
}

Sorry that was lengthy, but I can’t figure out what’s wrong. If there’s any other file you need to see, let me know.

I was having this issue early and usually resetting the core object prefab in the scene helped.

As far as the saving stuff if you have an existing save and add more stuff you now have a broken save, so just delete the save and create a new one and it should work again.

First thing to check in both scenes:
Are there any SavingSystem, SavingWrapper, or Fader items in the scene (There should be none, the proper place for these items is in the PersistentObjectsPrefab). This is the number one cause of the neverending reloads.

You’ll likely need to delete the save file no matter what. Once one of these cycles starts, it never ends well.

The NavMesh warning is just a distraction. It’s only a warning, and on the very next frame, all should be well.

1 Like

Thanks to both of you for responding so quickly!

I tried removing and then putting back in the Core object prefab, but it had no visible effect on the problem.

There are not SavingSystem, SavingWrapper, or Fader items in the scene. They only seem to be called when the PersistantObjects prefab is.

As for the save files, I noticed a some new weirdness. Currently when I play without an existing save file and try to enter Scene 2, it loads the fader, briefly displays “Sandbox 2 (not loaded)” (“Sandbox” being the name given to the scenes) on the game’s hierarchy and then proceeds to set me back where I started.
If I save, exit the game, and then play it again without deleting the save file, it sets me in Scene 1 on top of the portal but without triggering it, after which I can run around a bit before trying to enter Scene 2.
When I enter the portal the fader mostly triggers, but I can still partly see my character and the rest of the scene not doing anything. After that I move around a bit to make it go, and then I actually load into Scene 2. After that I’ve managed to find two issues: the first time it almost immediately sent me back to the first scene and I’m back to square one, but the second time it froze the controls and frantically displayed “Sandbox 2” and two instances of “Sandbox 2 (not loaded)” on the hierarchy, after which I can exit the game, but when I try to start it again without deleting the save it freezes and I have to crash it with the task manager.

Now what do I do?

Zip and upload your project to https://gdev.tv/projectupload. Be sure to remove the Library folder fromthe zip to save space, and to fill out the form, linking this forum post and select me as the instructor. I’ll take a look at it as soon as I can.

Done. You should see it soon, and if I didn’t do something right, please let me know.

image
The Persistent Objects are still in the Sandbox2 scene file. Delete these and enjoy wistfully travelling between your scenes like a true adventurer.

Sorry for taking so long to respond!

I deleted those, and now it works like a charm. Thanks so much!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms