Jump to content
  • Advertisement
Sign in to follow this  
caymanbruce

How to write robust, efficient and well structured client interpolation code?

Recommended Posts

I have implemented client interpolation and it works well. But I don't like my current structure. It looks really ugly and created too many temporary objects, besides that it is really hard to maintain the code.

I am not going to show too many logic here as it is very tightly coupled with other parts of my game. Note that my code is written in javascript but if you show me some direction in generic language or C++ that's OK too because I think the logic should not be too different.

In my game I have hundreds of players and other NPCs, and every network update I get a timestamp. I just bundle them up in a very big state object. Let's call it "currentRenderState", similarly I have "previousRenderState" and "futureRenderState", which means the state I receive in last update and the state I receive in current update. I am going to interpolate from "previousRenderState" to "futureRenderState". The interpolation result will be stored in "currentRenderState". If next update state hasn't arrived and the player state hasn't reached "futureRenderState" I will interpolate from "currentRenderState" to "futureRenderState".

 

So my state object contains a lot of information.

state = {
  timestamp,
  allPlayerStates,
  allNPCStates
}

 

Here "allPlayerStates" is a very big object too. It contains all the states of all players and each player contains dozens or even hundreds of properties.

Every time I interpolate I need to clear the object in currentRenderState, also I need to reference allPlayerStates and allNPCStates in "previousRenderState" and "futureRenderState" to get one of the individual state and interpolate it. At the end of the interpolation I create a very big temporary state object and put the interpolation value into this state object and assign to "currentRenderState". Then in the interpolation code I loop through the "allPlayerStates" of "currentRenderState", and assign the value to each player on client side. Also I loop through "allNPCStates" to assign the value to each NPC on client side. This logic works, but I feel tiresome each time I read through my code. Is there a better way to organise my interpolation code, and probably make it more efficient too?

Edited by caymanbruce

Share this post


Link to post
Share on other sites
Advertisement

Looks like you're storing your state in the inverse way to how I'd store it.

I'd have each object responsible for its own state, and its past states. I can then ask each object "what is your state at time T" and it can produce an interpolated or extrapolated state accordingly.

However, you don't always need to store the current, interpolated state for an object. If I'm just using this system to decide where to render something on screen, I can just ask for that value to be produced when necessary.

It's also usually not necessary to explicitly label states as current/previous/future. States have timestamps, and you have the current time (or at least, the notional time that you intend rendering), and you can interpolate between whichever 2 states are either side of the current time to decide what to render.

Finally, treating NPC states and player states separately is making extra work for yourself, so why bother?

Share this post


Link to post
Share on other sites
4 minutes ago, Kylotan said:

Looks like you're storing your state in the inverse way to how I'd store it.

I'd have each object responsible for its own state, and its past states. I can then ask each object "what is your state at time T" and it can produce an interpolated or extrapolated state accordingly.

However, you don't always need to store the current, interpolated state for an object. If I'm just using this system to decide where to render something on screen, I can just ask for that value to be produced when necessary.

It's also usually not necessary to explicitly label states as current/previous/future. States have timestamps, and you have the current time (or at least, the notional time that you intend rendering), and you can interpolate between whichever 2 states are either side of the current time to decide what to render.

Finally, treating NPC states and player states separately is making extra work for yourself, so why bother?

Thank you for your input. I have thought about putting the interpolation logic inside the loop of the player list. But maybe I am just being lazy not to test out if that works better or not because changing my interpolation code is really a headache. It can take up a day or even more. And it usually breaks my game and takes me even more time to debug.

The main reason of separating NPC and player states is that they are different thing. They behave totally diffenrently and NPC has only a few properties versus player which has a lot more properties.

Quote

However, you don't always need to store the current, interpolated state for an object. If I'm just using this system to decide where to render something on screen, I can just ask for that value to be produced when necessary.

In my game, it works like this: (Pseudo code, not in interpolation, but in the code when client receives an update)

previousRenderState = futureRenderState;

if (currentRenderState exists AND currentRenderState.timestamp > previousRenderState.timestamp) {

    previousRenderState = currentRenderState;

}

futureRenderState = (incoming update state values...);

So sometimes I need to assign the current state to the "previousRenderState" for better interpolation.

Share this post


Link to post
Share on other sites

Ok, your method of interpolation is the simplest one and does require storing the current interpolated state. That's fine. I'd still store it on a per-object basis.

If you want a more concrete example of how to make your code look less "tiresome" then we're going to have to see the code.

Share this post


Link to post
Share on other sites
7 minutes ago, Kylotan said:

Ok, your method of interpolation is the simplest one and does require storing the current interpolated state. That's fine. I'd still store it on a per-object basis.

If you want a more concrete example of how to make your code look less "tiresome" then we're going to have to see the code.

I agree with you too storing it on a per-object basis breaks it down into smaller unit so it's easier to debug. Unlike what I am doing now every time I debug or change some data structure it is a nightmare. But I still need to fix my code to adapt to the new structure.

Share this post


Link to post
Share on other sites

@Kylotan But I am very curious though. How not to store the current interpolated state? You see, one of the biggest headaches I have when changing my code is that I have to assign my "currentRenderState" to the "previousRenderState" (outside of interpolation). This results in copying a very complicated object into another object, value by value, and I can't copy its reference otherwise weird things would happen and those states will become unstable because changing one state can affect another. 

Share this post


Link to post
Share on other sites

If you simply store states as they come in, you can interpolate between them as necessary based on the current time. The current state is just a weighted average of a past state and a future state which is usually trivial to calculate once per frame for display purposes and then throw away. I explained this to you in a similar thread back in March. You have chosen a different route where, once you receive a new state update, you start interpolating towards that immediately, which requires that you assume your currently interpolated state is the starting point. (You still don't strictly need to be storing that interpolated state - you only need to 'commit' it to the 'previous' state when you get a new one to replace the 'future' state.) Both routes are valid, having different pros and cons, and I've implemented each.

You might also consider that if state copying is too expensive for you, it might mean you are copying too much state. Many games only ever need to store position and orientation for these purposes. Others might add velocity to that, or maybe the current animation(s) and frame number(s). It's still only a very small amount per entity.

Share this post


Link to post
Share on other sites
Quote

If you simply store states as they come in, you can interpolate between them as necessary based on the current time. The current state is just a weighted average of a past state and a future state which is usually trivial to calculate once per frame for display purposes and then throw away. I explained this to you in a similar thread back in March. You have chosen a different route where, once you receive a new state update, you start interpolating towards that immediately, which requires that you assume your currently interpolated state is the starting point. (You still don't strictly need to be storing that interpolated state - you only need to 'commit' it to the 'previous' state when you get a new one to replace the 'future' state.) Both routes are valid, having different pros and cons, and I've implemented each.

Sorry I went the other route because I felt that was enough for my game and easier to implement. But what does 'commit' mean?

Quote

You might also consider that if state copying is too expensive for you, it might mean you are copying too much state. Many games only ever need to store position and orientation for these purposes. Others might add velocity to that, or maybe the current animation and frame number. It's still only a very small amount per entity.

Apart from those values I have "alive" to check if player is alive, and "username" because I need to show it on screen, and the player's "score". The player's position is not just x and y. It has many parts moving after it so I need to pass those position values too.

Share this post


Link to post
Share on other sites

By 'commit' in this situation, I just meant 'store into previous state'. Because the interpolated value can just be a transient, calculated value, used merely for display. It's only when you receive a new state and need to treat the current state as the beginning of the interpolated range that you would actually need to store it.

It sounds to me like your state is not really all that large, and you're including things that shouldn't be in there anyway. Username is usually completely static, so it doesn't need to be in there. You can't interpolate it anyway. Dead or alive is certainly state, but you can't interpolate that, so again, it doesn't need to be in this specific data structure. I can't comment on position because for most MMOs this is literally one vector or matrix - if you have something more complex, it might well require a lot more state, or, it might just require a more sensible way of storing and deducing it.

Share this post


Link to post
Share on other sites

@Kylotan I might have been too lazy to split those properties such as "alive" and "username". But I have this concern: because I am putting every state into a big object, when I query a state from a list of players or NPCs I can quickly get the property and display its status. Otherwise I will have to maintain and query another state list to get these properties. And if this other state list doesn't have the same player IDs with the current state  I am in big trouble.

Back to 'commiting' the current state. I think you mean recalculate it when I need to store it to the "previousRenderState"? Would that be doing extra calculation when that situation comes up?

Edited by caymanbruce

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By tromtrom
      I've been doing some research on delta compression (used and described in the Quake3 doc http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/Quake3Networking,), and I'm looking for some clarifications on that topic please if possible.
      I understand that the delta compressed state is the difference between any given world states, meaning that if we store the state of every entity in a world state at every tick, the difference would be only the states of entities that changed between these two world states.
      Now when sending back the delta state to the client, do we go as far as only mentioning the properties that changed? Let's say a character moved only on X axis but didn't move on the Y axis between two states, are we sending to the client the whole state (x, and y) or only the new x position?
      If that's the case and let's assume there are a few more properties that describes a character, how can the client identify which properties have actually changed when rebuilding the information from binary data.
       
    • By tromtrom
      I've been doing a lot of research on how to implement a game server to support a web based game in the vibe of surviv.io, or zombsroyaleio. There are so many ressources out there, but apparently surviv.io is built with NodeJS using Websockets. That implies also that they are built on TCP protocol.
      They might not look like big titles but they surely look very steady (from my point of view) and I feel like they do deal with classic Fast Paced multiplayer concepts such as Client-side prediction, interpolation, and potentially lag compensation. 
      During my research, there seems to be that constant debate on UDP over TCP. To sum it all up, it seems that TCP is not appropriate for fast twitching games, however I do believe they fall into that category.
      How can they get away with TCP? Is this debate actually now outdated now we have better internet connections?
    • By msmile042
      Hi, I have a huge text file, its about 900 megs full of data thats comma delimated (.csv). It's basically just the dump of a huge table from a database. Anyway, the schema they were using was horrible, so I whipped up a little C++ program that parses the file and adds that data to a new (normalized) database. I left it running for a few hours and when I came back, my PC was bogged down and it said "The system is low on virtual memory... ". Anyway, has anyone ever parsed a huge file like this before? Any advise on a better way to do it? Should I do the whole thing at once? I was thinking of splitting the file into chunks... but how could I do such a thing? Is there any easy way to split this big bastard? I guess I could read say 50 lines into a buffer, spit it into a new file, clear the buffer, read 50 more lines, etc... then after doing this 10,000 times I start dumping to a new file. Thanks for any advise.
    • By Adrian Bigaj
      Hello!

      The game: https://www.combo-clicks.com/
      DEV blog (so everyone can read the journey and some history):
      http://www.combo-clicks-dev.com/
      TL;DR
      Feedback for Combo Clicks and also IDEAS for future games will be super appreciated (Hyper Casuals done in 3-4 weeks, each game with React Native).
      I will try to post on my blog atleast on weekly basis (both for gamers and developers) 
      Thank you!




    • By rouman
      Hi I tried to make some game in canvas JS.
      But dont know how to make sound effects like laser beam, I just add autoplay to some laser.wav and it is terrible.
      I need not fixed time. Each voise should have random time like 2s, 3s, or 10s?
      How to replace sound with another sound but not just replace but to make it slowly like animated.
      Is there such ablity or any library?
      Maybe some knew tutorial or book about sound game effects.
      myHobby.bmp
    • By Josheir
      I am getting very interested in the very popular JavaScript.  I would like to create games with it.   One thing that concerns me is the availability of the webpages' code to others.  I would really like to watch some movies on JavaScript but I don't know how to feel about people being able to copy my code (or for that matter if it is possible.)  Am I being unrealistic?  Are there means to make the code unreadable by the occasional viewer?  Perhaps it is just html5 and css3 that can be viewed with google chrome's view source and I am confused.
      Thanks in Advance,
      Josheir
    • By Josheir
      I took a hiatus of sorts and am thinking about switching from C++ to JavaScript.  It seemed like there was always a great response when I was into C++ here.  Where is the hottest area/areas for JavaScript questions.  I never had a question not responded to before!
       
      Thanks,
      Josheir    
    • By Josheir
      I am considering writing a JavaScript browser game that uses three windows.  What I am wondering is after the initial load of the game will the web pages be ready and therefore quick enough for any user.  One problem would be that the third window would open and close so does this mean that there is a necessary reload of that seperate third window page code and images by the browser that would slow it down?
       
      Thank you; it would be a fun project,
      Josheir
    • By BigBadMick
      Hey everybody,
      I'm currently working on a simple HTML5 game and my javascript collision detection function isn't working. The game features a little man that runs from side to side at the bottom of the screen, while a meteor falls from the sky. The function is supposed to detect a collision between meteor and man.
      In the routine, the top left corner of the man is at (player.x, player.y) and the top left corner of the meteor is at (meteor.x, meteor.y). The man is 25 pixels wide by 35 pixels tall. The meteor is 50 pixels wide by 50 pixels tall.
      Any idea where I've screwed in up this function?
      // ============================================================================= // Check for a collision between the 50 x 50 meteor and the 25 wide x 35 tall // main character // // Main character is drawn at 540 and is 35 tall, so the top of the character // is at y = 540 and the bottom is at y = 575. // // Function returns 1 if there has been a collision between the main // character and the meteor, otherwise it returns 0. // ============================================================================= function check_for_meteor_player_collision () { // edge positions for player and meteor var player_top = player.y; var player_bottom = player.y + 34; var player_left = player.x; var player_right = player.x + 24; var meteor_top = meteor.y; var meteor_bottom = meteor.y + 49; var meteor_left = meteor.x; var meteor_right = meteor.x + 49; var vertical_overlap = 0; var horizontal_overlap = 0; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Check for vertical overlap // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Check if meteor bottom overlaps player if ((meteor_bottom >= player_top) && (meteor_bottom <= player_bottom)) { vertical_overlap = 1; } // Check if meteor top overlaps player if ((meteor_top >= player_top) && (meteor_top <= player_bottom)) { vertical_overlap = 1; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Check for horizontal overlap // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Check if meteor left side overlaps player if ((meteor_left >= player_left) && (meteor_left <= player_right)) { horizontal_overlap = 1; } // Check if meteor right side overlaps player if ((meteor_right >= player_left) && (meteor_right <= player_right)) { horizontal_overlap = 1; } // console.log("vertical_overlap = " + vertical_overlap); // console.log("horizontal_overlap = " + horizontal_overlap) // If we've got both a vertical overlap and a horizontal overlap, // we've got a collision if ((vertical_overlap == 1) && (horizontal_overlap == 1)) { return 1; } // if we've fallen through, we haven't detected a collision return 0; } // =============================================================================  
    • By Awoken
      Is anyone aware of a universal Javascript Webkit?  Ideally one that will run in all, and if not all then most browsers?  Does anyone have any experience using a webkit in conjunction with WebGL?
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631398
    • Total Posts
      2999840
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!