Rewaz said:
Hmm, what do u think is a good tick rate (each tick it's the packet movement sync), because I read that for MMORPG 10 ticks per second it's just fine.
For a slow paced MMO probably yes, but I wouldn't play an FPS or probably even duel someone in WoW with 10 updates/second.
At the end of the day it all comes down to bandwidth. Realistically, you have to look at what's available on your server end (which probably has a fiber connection; e.g. - for most intents you're uncapped), but you probably should make (heavy) provisions in case your client is playing on the toilet over WiFi, in which case you might be looking at speeds to the tune of tens to hundreds of kilobits per second and considerable packet loss. Now multiply that with the number of players on your server.
Leveraging between all of this is tricky and unfortunately there are no one-size-fits-all answers. However- you can ask yourself questions like: “What is the minimal amount of data I need to send every update? What can I drop/calculate locally/compress? What do I do when there's a spike in packet loss/delay?”.
In an FPS your update payload might be very small - maybe hundreds or even tens of bytes -, so you can send it literally hundreds of times per second to minimize potential lag without fear of saturating most connections. In an RTS you might be looking at datasets that are an order of magnitude, or two, or three larger than that (in the latter case you could look into how Starcraft does its networking - it's fascinating stuff).
In any case - realistically you're not writing an MMO server here. At least not yet ?. For starters, as you probably know, the initialism itself literally contains the word “massively”. If you're having trouble interpolating one player, then dealing with synchronizing thousands or tens of thousands of players will probably have to wait a bit. BUT - many of the core problems do remain the same, so you can certainly stress-test your network code with tens or hundreds of simulated players and see how it fares.
Rewaz said:
For example, if I press W + D ( foward + rotate right ), how can I interpoltate that? I can't do linear interpolation.
This no longer has anything to do with networking. ?
You most likely already store your player's position, direction (as something like a quaternion) and velocity, etc. somewhere. And you probably also already update them by a some amount in every logic step.
As it happens - in most cases you'd employ exactly the same one-step-behind or predictive logic locally to make player movement look smooth, but instead of dealing with network delays, your synchronization happens between the logic and render threads.
Let's say you update your world at 30fps (every ~33ms) in your logic thread (where you probably also process any user input accumulated since the last tick). It's here where you set the player's linear and angular velocities according to input. Let's say the player pressed W and D, so you set the player's linearspeed = dir * somespeed (somespeed could be the player's max speed or some adaptive acceleration factor or whatnot) and rotationspeed = something like quat(0, 1, 0, turnspeed) (the player is now rotation around the Y-axis at turnspeed radians/second). Assuming your engine is multithreaded, you then lock your player's render state and copy this data to a buffer that the render thread can read each frame (if your code is single-threaded, then everything remains the same, but you can forget about synchronization between threads).
In your logic thread, during the next step you simply do: playerposition = collide(playerposition, linearspeed), and update linearspeed and rotationspeed according to collision response/new inputs, etc.
Meanwhile, in your render thread, every time you draw a frame, you lock the player's state and calculate curdrawposition = playerposition + linearspeed * dtSinceLastLogicUpdate, etc. (you do this for all variables that need to be interpolated). BTW: this is why it's important to have a solid, fixed logic step interval (which is fixed at 30fps in this case) - you want stuff like the player's linearspeed to remain well defined for each logic step, so they can never do silly things like go faster than maxspeed units per second.
However meanwhile (especially if v-sync is off), your render thread might be blasting away at much larger, lower or volatile framerates, e.g. 218fps this second and (if your optimizations don't hold up) 21fps the next second*, which in turn introduces a whole lot of movement jitter. This is where the interpolation pays off, which you use to “smooth out” the relevant variables. Just to be clear, at the start of each frame you calculate:
dtSinceLastLogicUpdate = something like (GetCurrentHighFrequencyTimestamp() - lastLogicStepTimestamp) / double(logicStepLengthInWhateverUnitsYoureUsing).
Note that with a predictive approach you're still theoretically running the risk of encountering similar visual glitches as with the networked code. Let's say the player is a bullet and their linearspeed is something silly (let's arbitrarily say it's 2000, which we'll call a “silly fast speed”). If the player's computer is running your game at ~300fps (300 render updates per second), then given the tick rate of 30 logic updates per second you'll have ~10 frames that are rendered during each tick, which means that VISUALLY the bullet gets to move 200 (2000/10) units before the next logic update has a chance of correcting its position.
That is to say, if the collision test in the next logic update finds that there's a wall 10 units from the bullet's current position, then you'll have visually (already) shown that the bullet goes through the wall by as much as 190 units. Of course, this is only a visual glitch and you can remedy it by either increasing the frequency of your logic updates appropriately or switching from a predictive interpolator in the render thread to a conservative one (which might use the last two already known updates as the from and to positions and interpolates between those every frame instead of looking at the predictive values for the next step). Again, your choice depends on what game you're making and what's important for gameplay (for instance, an FPS with a high logic update frequency and predictive rendering interpolation yields smaller input lag with a low chance of visual error, which is very likely preferable to waiting a full tick (actually two, since you're likely processing player input at tick intervals) before the drawn frames reflect the player's actions).
Hopefully this gives you an inkling what the problem is how you might go about solving it.
* I can't stress this enough - your framerate should NOT fluctuate this much under any circumstances ?