Saving System Upgrade: issue by loading the player position

I start the tutorial about Saving System Upgrade: I get stuck at the end of part two “save and loading the Mover”
When I loading several times the save file, the position of the player not always load correct.
Sometimes it’s load correct, the next time not, than again correct a few times, ten again false. I mean false, the player jump to default instead to the saved point.
I don’t have some errors.
Anyone an idea?

Let’s take a look at your Mover’s CaptureAsJToken and RestoreFromJToken methods for a start.

    public JToken CaptureAsJToken()
    {
        return transform.position.ToToken();
    }

    public void RestoreFromJToken(JToken state)
    {
        GetComponent<NavMeshAgent>().enabled = true;
        transform.position = state.ToVector3();
        GetComponent<NavMeshAgent>().enabled = false;
    }

I move the player with a Gamepad in my own project, thats why no ActionScheduler.

I use Unity 2021.3.16f1
In the beginning when start play (editor or build), it starts always with correct loading.
Just in case the hole mover script:
/
/

using GameDevTV.Saving;

using Newtonsoft.Json.Linq;

using UnityEngine;

using UnityEngine.AI;

namespace BS.Movement

{

    public class Mover : MonoBehaviour,IJsonSaveable

    {

        [SerializeField] private float speed;

        private CharacterController characterController;

        private PlayerInput playerInput;

        private BodyRotation bodyRotation;

        private Vector3 lookDirection;

        private float gravity = 9.81f;

        private bool menuIsOpen =false;

        private void Awake()

        {

            playerInput = new PlayerInput();

        }

        private void OnEnable()

        {

            playerInput.Enable();

        }

        private void OnDisable()

        {

            playerInput.Disable();

        }

        void Start()

        {

            characterController = GetComponent<CharacterController>();

            bodyRotation = GameObject.Find("Body").GetComponent<BodyRotation>();

           

            GetComponent<NavMeshAgent>().enabled = false;

        }

        void Update()

        {

            CalculateMovement();

        }

        private void CalculateMovement()

        {

            if (!menuIsOpen)

            {

                Vector2 input = playerInput.Player.Move.ReadValue<Vector2>();

                float xInput = (input.x);

                float zInput = (input.y);

                Vector3 direction = new Vector3(xInput, 0f, zInput);

                direction = transform.transform.TransformDirection(direction);

                Vector3 velocity = direction * speed;

                velocity.y -= gravity;

                characterController.Move(velocity * Time.deltaTime);

                bodyRotation.Rotation(direction);

                lookDirection = direction;

            }

        }

        public Vector3 GetLookDirektion()

        {

            return lookDirection;

        }

        public void SetMenuIsOpen(bool menu)

        {

            menuIsOpen = menu;

        }


        public JToken CaptureAsJToken()

        {

            return transform.position.ToToken();

        }

        public void RestoreFromJToken(JToken state)

        {

            GetComponent<NavMeshAgent>().enabled = true;

            transform.position = state.ToVector3();

            GetComponent<NavMeshAgent>().enabled = false;

        }

    }

}

I find out somthing:
Always when I load the save file the console gives out the same position data.

But the players position are somtimes wrong sometimes correct.

Player Capture BS.Movement.Mover = {
“x”: 4.959992,
“y”: 1.0553956,
“z”: -231.711319
}

Player Restore BS.Movement.Mover =>{
“x”: 4.959992,
“y”: 1.0553956,
“z”: -231.711319
}

These are reversed… You should be disabling the NavMesh, then setting the position, the re-enabling the NavMesh… When the NavMesh is enabled, it is going to fight any changes to transform.position.
Except that if you are doing direct input instead of NavMesh based input, you don’t actually want to turn the NavMeshAgent on at all…

I’ve changed the code. Now the NavMeshAgent is alway .enable = false. Only for the Portals I enable and re-disabling them.
But still I have the same issue.

Hi Brian, thanks for helping.
I’ll carry on with the tutorial Saving Upgrade and comme back later.

Greetings

If your character is moving with WASD, you really don’t want to ever turn the NavMeshAgent on, even when transferring via portals. The NavMeshAgent will absolutely 100% mess with WASD movement.
In the Portals, if you’re ENABLING the navMeshAgent then moving, you’ll have the same problem as in the saves…

Hi Brian
I tried out many things. I find out, that the player goes first to the correct position and jumps than immediately to default position.
Yes I use for inputs the keyboard & gamepad.
I realized that is an problem I had before the upgrade of the saving system too. I examine an old version. Sorry, my problem has a false topic.
But I tested a new scene without portals and without NavMeshAgent and I have still the same problem. I think its not the problem of the NavMeshAgent who I activate and deactivate just for the portals.

Zip up your project and upload it to https://gdev.tv/projectupload and I’ll take a closer look. Be sure to remove the Library folder to conserve space.

I think i found the problem but I don’t know how to solve.
If I comment out in the mover script:
/
characterController.Move(velocity * Time.deltaTime);
/
The loading work always perfekt. And wrote the line:
/
transform.Translate((direction + velocity) * Time.deltaTime);
/
but then the PLayer goes throw the Terrain.
namespace BS.Movement

{

public class Mover : MonoBehaviour, IJsonSaveable

{

    [SerializeField] private float speed;

    private CharacterController characterController;

    private PlayerInput playerInput;

    private BodyRotation bodyRotation;

    private Vector3 lookDirection;

    private float gravity = 9.81f;

    private bool menuIsOpen = false;

    private void Awake()

    {

        playerInput = new PlayerInput();

    }

    private void OnEnable()

    {

        playerInput.Enable();

    }

    private void OnDisable()

    {

        playerInput.Disable();

    }

    void Start()

    {

        characterController = GetComponent<CharacterController>();

        bodyRotation = GameObject.Find("Body").GetComponent<BodyRotation>();            

    }

    void Update()

    {

        CalculateMovement();

    }

    private void CalculateMovement()

    {

        if (!menuIsOpen)

        {

            Vector2 input = playerInput.Player.Move.ReadValue<Vector2>();

            float xInput = (input.x);

            float zInput = (input.y);

            Vector3 direction = new Vector3(xInput, 0f, zInput);

            direction = transform.transform.TransformDirection(direction);

            Vector3 velocity = direction * speed;

            velocity.y -= gravity;

            //characterController.Move(velocity * Time.deltaTime);

            transform.Translate((direction + velocity) * Time.deltaTime);

            bodyRotation.Rotation(direction);

            lookDirection = direction;

        }

    }

    public Vector3 GetLookDirektion()

    {

        return lookDirection;

    }

    public void SetMenuIsOpen(bool menu)

    {

        menuIsOpen = menu;

    }

    public JToken CaptureAsJToken()

    {            

        return transform.position.ToToken();

    }

    public void RestoreFromJToken(JToken state)

    {

        GetComponent<NavMeshAgent>().enabled = false;                      

        transform.position = state.ToVector3();                        

    }        

}

}

I should have thought of this… CharacterController is like NavMeshAgent… it doesn’t like other scripts mucking about with the transform.

Try this in your Mover script’s RestoreFromJToken:

public JToken RestoreFromJToken(JToken state)
{
     characterController.enabled=false;
     transform.position = state.ToVector3();
     characterController.enabled=true;
}

When I start the screen gets black from the Fader und stays black.
An error commes:
NullReferenceException: Object reference not set to an instance of an object
BS.Movement.Mover.RestoreFromJToken (Newtonsoft.Json.Linq.JToken state) (at Assets/Scripts/Movement/Mover.cs:90)
image

This is likely a race condition. RestoreState happens after Awake(), but before Start(). Move the contents of Start() into your Awake() method.

As a rule of thumb, all component caching that’s on the same GameObject should be in Awake() to avoid these sorts of situations.

I solve it like this:
public void RestoreFromJToken(JToken state)
{
//GetComponent().enabled = false;
GetComponent().enabled = false;
transform.position = state.ToVector3();
GetComponent().enabled = true;
}
But your solution works perfect too. :slight_smile:
Brian, Very very thousand thanks spending time for me.

I mean
image

Sorry it took so long… with it being the RPG course, my mind immediately springs to the RPG codebase, even though I’m also the TA for the Third Person course.

A little help with Code Formatting:

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

Privacy & Terms