Here’s an internet PvP recording for the latest version, all previously non-public codes for performance enhancements has been merged into the open-sourced version.
Yet another earlier one for basic ops demonstration.
The battles played over internet were all between Dongguan city, Guangdong Province and Nanjing city, Jiangsu Province
Looks pretty awesome, quick question about the delayed input. If I correctly understand input are only collected every forth frame, then applied to the next 4 frames after? If so, does this cause a delayed start/slow down when stopping?
First of all if you’re concerned about a sensible delayed start/slow down when stopping, it’s mostly due to _processInertiaWalking instead of the batched input. You can tune InertiaFramesToRecover of each character to try if some other values fit your need most – but mind that a smaller InertiaFramesToRecover makes “turn-around & abrupt start/stop” more prone to teleportation during internet play.
Secondly, you can also control the granularity of batched input by tuning INPUT_SCALE_FRAMES, basically the batch size is just (1 << INPUT_SCALE_FRAMES) so changing it to INPUT_SCALE_FRAMES = 1 gives you “1 input per 2 frames” – but as a reasonable good fighting game player I tried INPUT_SCALE_FRAMES = [0,1,2,3] myself, only INPUT_SCALE_FRAMES = 3 is sensible for me, which complies with popular theory that only some professional athletes are capable of telling signal delays at 10ms resolution.
That said, the best values are always defined case by case, so I made them tunable.
Is the idea of the batched input and delayed client-side execution to help keep the client more in line with what is executing on the server? For example, my FixedUpdate runs every 16ms, so I would collect the input on frame 1 and send it to the server, then on frame 4 get the next input/send to server and start executing the input collected in frame 1 for frame 4-7. This would cause a delayed execution of 64ms which I guess you would disguise with some animation or something. Movement is easy enough to slice over 4 frames but how would this work for other actions that are instant (an attack of sorts or healing)? Would you only execute the action client side on frame 4 and nothing for 5,6,7?
The intent for batched input is mainly for saving bandwidth. The ease of syncing game dynamic progression (as well as rollback) is a by-product which you can achieve by many other ways.
In terms of delay, again you’d have to try it yourself, I met so many claims that sth should be executed “immediately”, while they actually are not aware of what time resolution sensing an average human has. Somebody might be able to sense 10ms delay, there’s no point to argue over that, if you’re really just worried about that, it’s always possible to tune the constants to a “no delay” config – but make sure that you have someone else to test whether a tuning is really improving their gaming experience.
I personally like the present tuning to exploit the difference between human time resolution sensing and what modern computer/phone can do, to provide a polished/disguised game experience.
Ahhh so batched inputs are sending 4 sets of inputs (1 per frame) at once? Then these are just replayed delayed on client (in your case). Or are you sending a single input and apply it over 4 frames?
I’m just seeing how this compares to mine which seem pretty smooth but I’m sending packets each FixedUpdate (16ms)
No for the first guess, by INPUT_SCALE_FRAME=2, the client side actually only recognizes 1 input per 4 frames (64ms), while “sending” is another story, for now I checked whether or not the current input is different from the previous, if yes then it’ll send “immediately”, otherwise would cache and send when holding threshold is hit.
For the question, if you’re just using fixed intervals, my approach only generalizes what you’re doing, there’s no comparison – I can always fall back to fixed intervals which I’ve tested to be very prone to large internet fluctuations and it’s just more difficult to get a smooth graphic output. Again don’t just think of it, have a try by running it. There’s no word more convincing than evidence, my prediction of your question is: you couldn’t feel any difference when playing them.
Thanks for the explanation, I think I’ll look over your code some more and see if this is something I can implement in my game. Movement is so tough to get right, I’m happy with what I have now but can see some advantages with your approach once i get into rolling back events and such.
Np, it’s quite nice to me that you really got the essentials of what’s important.
Here’s my 2 cents: you might find some of my animations not smooth enough compared to some others’ demos, that’s totally expected because for many moves (including attacks) I set a relatively safe “inertiaFrames/startupFrames” – which means visual delay – they were not there if you watched the early videos.
For playing over the internet, it’s almost trivial to be smooth if you have good network to send 1 packet per 16ms uniformly, and all players receive at that rate uniformly – in that case you can tune the graphics to be 10 times smoother than what I showed here.
However that kind of smoothness is very fragile if you test it under controlled LAN with occasional large delays or packet loss (and would be even worse if you use TCP only). What I’m battling against in this project is actually the bad network cases – of course I admit that my animating skill is like sh*t hence the outcome is looking worse than what the algorithm is offering