TCleard / PredictionReconciliationNetwork

MIT License
53 stars 2 forks source link

Jitter in movement #5

Open SireNiklas opened 1 year ago

SireNiklas commented 1 year ago

Hello!

Unsure if your still working on this, but I don't have enough information to fix this myself it seems. The player seems to have some kind of jitter when moving. I am unsure if that is just the way I have it setup or if this is something to do with the library, but if you have time a response would be well appreciated.

The Unity demo does have it as well. I wonder if its possible the problem could be with the tick rate because it seems its when the player transform is updated, if there is a way to up the value maybe that could fix it?

This video is from the editor demonstrating that when the player moves, there is a jitter when the camera moves there is none. https://github.com/TCleard/PredictionReconciliationNetwork/assets/100490847/06160168-95fe-4ca2-9a32-4563adf5bddc

Thank you in advance for your time! Nicholas.

TCleard commented 1 year ago

Hey !

Thank you for your feedback. I'm always working on this project, as I use it for a multiplayer game I'm working on. I improve it when I need it, or when people like you find a bug or need something !

I think it's sort of a known issue. To implement prediction and reconciliation, the server and all the client needs to process input and create state at the same rate, hence the looper that drives the frequency of the Processor.Process method. The looper has to know how the time passes, that's why you need to call looper.Tick(TimeSpan.FromSeconds(Time.fixedDeltaTime)); in a FixedUpdate method. And I guess that's where the jitter comes from. As you try to move your character in a FixedUpdate (which is totally logical), if you attach a camera to the body you're moving, the camera will move acordingly but wont refresh as fast as the body is moving, creating the jitter.

I had kindof a hack to work around that, but no permanent solution for now:

private Vector3 direction, targetDirection; private Vector3 directionVelocity; private float directionSmoothTime;

public void SetTargetPosition(Vector3 targetPosition) { this.targetPosition = targetPosition; }

public void SetTargetDirection(Vector3 targetDirection) { this.targetDirection = targetDirection; }

private void Update() { position = Vector3.SmoothDamp(position, targetPosition, ref positionVelocity, positionSmoothTime); direction = Vector3.SmoothDamp(direction, targetDirection, ref directionVelocity, directionSmoothTime);

transform.position = position;
transform.rotation = Quaternion.LookRotation(direction);

}


- On the **OnState** callback, you call the UpdateTargetPosition and UpdateTargetDirection

Again, it's not the best way to do it, but the only way I found.
I don't have much time today to try and find a better solution, but I'll give it a try later this week.
Let me know if it works for you or if you find something ! And feel free to pull and modify the code, and to create a PR afterward ;)
SireNiklas commented 1 year ago

Okay! I will try this as soon as possible! Glad there is a work around for it. :D

SireNiklas commented 1 year ago

So maybe I got confused, maybe I don't know enough to do this.

I have created a new script with the code you sent, I have another gameobject that is set active on spawn with this script on it, but I don't understand where and what UpdateTargetPosition is.

private void OnState(PlayerState state) {

        // Do whatever you need
        // This method is called on the server or the host when they generate a state
        // on the owner when it predicts a state and during its reconciliation
        // on the client when it receives a state from the server

        _playerBetterMovement.transform.position = state.position;
        _playerBetterMovement.transform.rotation = state.rotation;
}

This is my thought about your explanation for the On State portion.

The video seen has the OnState code commented out, as I got errors. :D https://github.com/TCleard/PredictionReconciliationNetwork/assets/100490847/54721b22-65b0-4152-9b03-96d9ade6a2fe Here is another video, I just wanted to see if it gives better idea. :'D May not be needed, but better to be safe than sorry! (Man that framerate is bad! Github doesn't want me to give a good demonstration)

TCleard commented 1 year ago

I tried to play a bit with the sample, and I indeed noticed the jitter. I tried to implement what I sent you (in the feature/smoothUpdate branch if you wanna look it up) but it doesn't seem to correct it that much. However, I did notice that in the Unity editor the jitter is way more noticeable than in a build, but I get that it is not acceptable for a multiplayer game. I even tried to tweak the Looper value (1/120f and 1/240f) and in the NetworkManager the Tick Rate (120 and 240), as I though it would do something, but not that much. I don't really know how to imprive this... I feel like it has something to do with the refresh rate and the way the datas are shared from the server to the clients, but I definitely could be wrong.

SireNiklas commented 1 year ago

I will check that out. I'll keep toying with it, and if I find something, I will surely let you know. Thank you for your your input!

SireNiklas commented 1 year ago

Haha sorry thought I was done! But I thought instead of making a new issue I would continue.

Do you have a way to use Update with your lib? I know its because if FixedUpdate, but I was wondering if instead of FixedUpdate I could try swapping Update.

EDIT: Found it, I know FixedUpdate is better, but currently Update seems to fix the Jitter I will try it networked here in a second and will update this post again soon.

EDIT 3: It works fine for now, but if I start having issue later and I remember I will comeback and let you know, but so far Update has fixed my issue, also the lag within that video I am unsure if it is update or not, maybe just shitty wifi. :'D | Wasn't lagging till I decided to record it... :P

Please do let me know if there is a reason I should not do this. ( did checkout Ajaxes video, I am still unsure why it needs to be fixed. He does also have the same issue I am complaining about, so I am unsure now. :P)

https://github.com/TCleard/PredictionReconciliationNetwork/assets/100490847/85d4a837-02ef-4fc3-b38e-6bfb326d6b13

TCleard commented 1 year ago

You can definitly call Looper.Tick in the Update method (just remember to pass Time.deltaTimeand not Time.fixedDeltaTime) so the Processor.Process method is performed on the Update. I just find it more logical to do Looper.Tick in the FixedUpdate method as it is supposed to run more frequently, at a fixed rate (every 0.02 seconds by default, check into Project Settings -> Time -> Fixed Timestep) and it is usually used to perform physics stuff, whereas Update is supposed to be for visual purposes and has a bit more random call frenquency. But keep in mind that is you use the Update method for the Looper, the methodsProcessor.Process, NetworkHandler.onSendInputToServer, networkHandler.onSendStateToClient and networkHandler.onState method will be performed way less frequently than with the FixedUpdate, so you might not get the best syncing from other players. I will try and play a bit more with the Looper, ProjectSettings.Time and NetworkManager.TickRate to see if there's a way to get the best out of it for sync and non-jitter movement purposes

SireNiklas commented 1 year ago

Awesome! Keep me updated! Everything that I understand it may just need to be lerped/smoothed on Fixed Update, so if you find a way to lerp it that I can add I will try it out!

SireNiklas commented 1 year ago

I thought I would add this, after a couple of days I came back to the project, and the jitter seems to be unnoticeable. Unsure why but it definitely still there its just not as noticeable.