How to sync movement speed properly in my case?

The whole answer can be found below.

Please note: The Photon forum is closed permanently. After many dedicated years of service we have made the decision to retire our forum and switch to read-only: we've saved the best to last! And we offer you support through these channels:

Try Our
Documentation

Please check if you can find an answer in our extensive documentation.

Join Us
on Discord

Meet and talk to our staff and the entire Photon-Community via Discord.

Read More on
Stack Overflow

Find more information on Stack Overflow (for Circle members only).

Write Us
an E-Mail

Feel free to send your question directly to our developers.

How to sync movement speed properly in my case?

Animatronic
2017-02-19 00:32:12

Hey guys!

Took another look at movement in my game and found out that it only works smoothly when using a constant speed - super happy that I found it out though and got to experience the smoothness now. : )

Could use some help on how to get the client predicted movement working properly with constantly changing speed caused by different character movement states like idle, walking and running mainly at this point.

Currently, when using a variable speed, the character makes a bit choppy transition from idle to running especially. It feels like the player gets quickly corrected by the server before being able to properly make the quick change from idle to running, so basically from zero to full speed.

My setup:

  • 3D top-down view
  • Server authorized and client predicted movement
  • Character faces mouse cursor and uses it as the targeting pointer for skills and attacks
  • Related input commands include cursor position (XZ) and two booleans for moving/not and running/walking
  • Related resulting commands include Position (XZ, with smooth corrections on, tp threshold 3 and no compression) and Speed (smooth corrections on, compression 0-25 with 0.1 accuracy) (not sure if 0.1 accuracy means it is rounded to 1 digits or not btw, so have to look into that at some point)
  • Tried different correction interpolation frames between 1 and 30 and did not notice much difference there for some reason (might need to give it another look later on, though, the main problem is probably elsewhere in this case)
  • ExecuteCommand function: https://gist.github.com/Animatronic/9dd35b0fd7502731f3639bd8ad5d0dab
  • Character state example: https://gist.github.com/Animatronic/6572418f63b7d01e5661608dc0bae5d5
  • Move function: https://gist.github.com/Animatronic/22841eb07e20b70aa04e14c70a47258e

TotalSpeed is updated on both controller and owner separately whenever the simulation is run and the movement state (idle, walking, running etc) changes. Once I move on to testing speed mods caused by status effects I might add a speed modifier as a state property but have to see about that later on.

I have noticed most of the cases seem to be using velocity as a resulting command that includes both direction and speed. I currently let players control the direction completely as the character rotation is instantaneous and it also affects the targeting so I think I would only need to send speed as the result in addition to position.

So it would be really cool to get some ideas on what would be the best way to correctly sync the speed variable in a game with this kind of mouse oriented targeting and movement system and different character states that affect the speed. It seems to work smoothly when just using a constant speed. I am also interested in hearing about any potential other improvements.

One thing that came to my mind while writing, and I remember thinking about it when working on the movement system, is that I do not have a resulting command for the movement state itself. I might need that as well but I think I am probably doing something else wrong as well. Gotta go do some logging as well still ->

Any thoughts are much appreciated! Thanks!

Comments

stanchion
2017-02-19 01:24:00

I believe you need the speed in reset state, but no way to know for sure without your code.

Animatronic
2017-02-19 14:00:35

Hey stanchion! I edited the post with more code snippets included.

stanchion
2017-02-19 16:16:45

I don't see any movement in your execute command.

How do commands work?

First, let's break down how SimulateController/ExecuteCommand works. SimulateController is only invoked on the host which is in control of the entity, this can be both the owner (if it calls TakeControl() for itself) or a proxy (if the owner calls GiveControl(connection)).

SimulateController is used for collecting input state from your game and putting it into a command, and other tasks specific to the controller. SimulateController executes one time per frame only.

ExecuteCommand runs on both the owner and the controller of an entity, so if you have a player character which the server spawns and then gives control of it to a client, ExecuteCommand will run on both the server and the controlling client. It will not run on any other clients.

The next question usually is: so how does the input/state work on the command, and what does resetState do?

So, first of - input is very obvious, this is set on the command in SimulateController and polls the local state of whatever input scheme you are using for that specific frame. When you call QueueCommand(cmd); the command is scheduled both for local execute on the client and is sent to the server for remote execution. This is what lets Bolt do client side prediction: the command will execute on both the server and client.

The state on the command, is the resulting state movement state of executing the input, this is why you copy the state of whatever character motor you are using to the command.

When the server executes a command, it will send the State of the command back to the client which created the command, and override the state of that specific command on the client with its own correct state.

So how does resetState fit into all of this? resetState asks you to reset the state of the character motor to the state of the command passed in when resetState is true. This will only happen on remote controlling clients, never on the server. This happens once at the beginning of every frame, and the command which is passed in is the command which has received its correct state from the server.

After the command with resetState has execute, Bolt will execute all other commands again on the client, to "catch up" to the current state. This happens every frame.

Animatronic
2017-02-19 17:30:54

@stanchion wrote:

I don't see any movement in your execute command

The movement code is there if you follow the function call paths to the other snippets. MyStateMachine.Update() is the function call, the Update() function can be found within the example state snippet and the Move() function is in the third snippet.

So as I said, the movement works super smoothly with speed as constant but when you switch to using a variable as the speed and try to sync the speed changes, for example, transitioning from speed 0 to 8 (idle to running), it gets choppy on the client at the start of it. So basically all I want is to sync the speed properly so that the client moves as smoothly as it does when using a constant speed of 7f for example instead of context.StatManager.TotalSpeed.

I'm kinda leaning towards it being just caused by the fact that I don't have a resulting command for the movement state itself (like an integer for whether the character is idle/walking/running). Just not sure if I can explain the underlying reasons for it.

stanchion
2017-02-19 17:32:22

You should read through my comment above on how commands work, all movement needs to be called in execute command, not update or anywhere else

Animatronic
2017-02-19 18:03:09

@stanchion wrote:

You should read through my comment above on how commands work, all movement needs to be called in execute command, not update or anywhere else

Daamn man, Stanchion, seriously. Are you effing kidding with me right now? : D

It's a custom method in my state machine, not Unity's Update method lol. Are you saying you can't have function calls to other scripts from within ExecuteCommand since that's what I'm doing there.

Stanchion, I seriously feel like you did not read any of my posts with any thought at all and I was the one who read your posts thoroughly at least twice before replying. I mean I'm usually very cool with all kinds of people and very relaxed but everyone has their limits.

In any case, I thank you for actually responding and doing it quickly. I just hope you would actually read through the stuff before wasting anyone's time by posting nonsense.

stanchion
2017-02-19 18:18:11

I skimmed through the several scripts you posted and said what came to mind, naming functions confusing things like "Update" doesn't help. If you want someone to take a serious look at the code you can always email it to [email protected] , all I can do with snippets of different scripts is guess.

We both agree that the issue is not setting the speed in cmd.Result and ResetState.

Back to top