a better way to interpolate between positions?
hi, im working on an action based 2D persistant MORPG. anyway, im trying to tweak the game to deal with latency better. part of this is me tweaking the movement system. now, how movement works is this. the movement is done with the mouse. when the user clicks on the screen, his character then walks in a strait line to where he clicked. this proccess goes something like this: - client says to the server "may i please move? i clicked on X,Y" - server verifies this click is inside his screen. he then starts moving the client on his simulation. he then sends back to that client "ok, you can move. your position is X,Y, and the time is T". - client recives this message. he sets his position. he then uses the timestamp to "jump" to make up for lost time, so that his position is the same as the servers (remember the server started moving ~ping/2 MS ago, so he has to "catch up" to his own position.) the problem is that this "jump" is very ugly. not only does the jump have to make up for lost time, but it also has to make up for the fact that when the server first got they "hey, i want to move" packet, he immediately switched velociy on his end, and then sent the packet to the player. now during the time it took for the player to get "ok, you can start moving", the player was moving in his old direction. i could solve this second problem by having the client stop moving when he sends the movement request and have him send a timestamp with the request, and then have the server "back track" based on this timestamp, but, this would leave movement open to exploits (the client could send fake timestamps to make himself hop around..) anyway, im trying to come up with a good way to prevent this "jump", but i cant get it to look right. basically i do something like this. - client gets the "ok you can move message". he then "jumps" to make up for lost time, but only his physics position jumps. his rendering positions stays where it is. - each frame, the clients rendering positions increments a little faster (tweaking that value, maybe 1.2x faster, but probably best to base it on how lagged behind the player is) then the physics position, untill the rendering position "catches up". anyway, basically how it is now is the client should quickly run to make up for lost time instead of just jumping to make up for lost time. however, i cant get it to look right and im not sure what im doing wrong. he kind of jerks backwards each time he moves.. i think it might just be a bug in my code though, but i also believe theres a better way to do this.. thanks a lot for any help. EDIT: btw, i forget to mention. the game is heavily action based, which means there are bullets flying around all the time. so sync must be as good as possible.
FTA, my 2D futuristic action MMORPG
Its Ok for a client to take action as long the server maintains authority. Of course, you should do some client side checking to see if the action is possible, ie- if theres a barrier in the way, or you've been the victim of a freeze attack.
When you get the authorization back with you're absolute XY, you want to blend into it over a couple frames to avoid jerkeyness.
Most professional games use a form of this technique.
Google up "Dead Reckoning" for more information.
When you get the authorization back with you're absolute XY, you want to blend into it over a couple frames to avoid jerkeyness.
Most professional games use a form of this technique.
Google up "Dead Reckoning" for more information.
throw table_exception("(? ???)? ? ???");
one article I found interesting on the subkect (of dead reckoning):
Dead Reckoning: Latency Hiding for Networked Games
Gizz
Dead Reckoning: Latency Hiding for Networked Games
Gizz
I would start the client moving at half speed towards the real goal as soon as you click. Then when the server packet comes back, you snap the client to where the server says it is, with the velocity the server says. If the round-trip-time is evenly distributed, the player will then be exactly where he should be anyway, so the snap will be small.
In addition, you can hide snaps, just like you're saying. It sounds like you're having a bug somewhere. The algorithm looks something like this (although you probably separate physics and rendering into separate interfaces):
In addition, you can hide snaps, just like you're saying. It sounds like you're having a bug somewhere. The algorithm looks something like this (although you probably separate physics and rendering into separate interfaces):
const float DELTA = 1.0f; // pixels const float OMEGA = 0.15f; // adjustment factor per step Point physPos; Point renderPos; Point velocityPerStep; void step() { calculate_phys_pos(); renderPos = renderPos + velocityPerStep; if( (physPos-renderPos).length() < DELTA ) { // snap when close enough renderPos = physPos; } else { // else make up for X percent per step renderPos += (physPos-renderPos) * OMEGA; } render_sprite_at( renderPos ); }
enum Bool { True, False, FileNotFound };
Something many people forget is that, as opposed to a multiplayer game such as Quake, Doom, etc. a MMORPG has usually one server which is accessed by players from all over the world. Therfore, trying to make it very fast paced can result in very nasty unsync between teh clients and the server, which leads to quick jumps between positions to compensate the time it takes for the client -> server ->client communication, jump backs, when the server tells you that hey, you can't move there, and the client has to move back, etc.
In a multiplayer game, most of the players are from the same continent, because no sane person would log in to a server from a different continent. So those games are usually meant for a ping of max 100 ms, after that a higher pig can be a serious dissadvantage.
That's why you really should go with a lag tollerant algorithm, and slow down the pace of the game.
In a multiplayer game, most of the players are from the same continent, because no sane person would log in to a server from a different continent. So those games are usually meant for a ping of max 100 ms, after that a higher pig can be a serious dissadvantage.
That's why you really should go with a lag tollerant algorithm, and slow down the pace of the game.
@hplus
i was actually just thinking about something like that [grin]. i was thinking that i could use the players average ping/2, and then immediately start interpolating towards that point, and hopefully by the time i stopped moving the movement ack would put me in about the same place (and then i could interpolate from there if i had to, maybe stop a little before just to be safe). RakNet has some nice functions with ping like GetLowest/Last/Average ping.
i havent tested it yet though, so ill probably just go with the method you mentioned since you actually know what your talking about [lol]... ill test it anyway though.
@Radu
thats why my game is not a MMORPG [smile]. i dont plan on supporting people from all over the world but i think the game will still be playable even with a high ping. also, my game is not targeted towards traditional MMORPG players in the first place (for one thing, PvP is not only encouraged but pretty much mandatory). it is more like a persistant action rpg. dont get me wrong though, there are still heavy persistant RPG elements to it and when i said "heavily" action based i probably should have followed that with "for an RPG" [grin]. my goal is to handle 30 players which i think is very reasonable from the tests ive done so far with my game. i have some good plans to help hide latency on top of this. i actually think its fun to mix 2 different methods of network programming, and so far it seems to be coming along pretty good.
i was actually just thinking about something like that [grin]. i was thinking that i could use the players average ping/2, and then immediately start interpolating towards that point, and hopefully by the time i stopped moving the movement ack would put me in about the same place (and then i could interpolate from there if i had to, maybe stop a little before just to be safe). RakNet has some nice functions with ping like GetLowest/Last/Average ping.
i havent tested it yet though, so ill probably just go with the method you mentioned since you actually know what your talking about [lol]... ill test it anyway though.
@Radu
thats why my game is not a MMORPG [smile]. i dont plan on supporting people from all over the world but i think the game will still be playable even with a high ping. also, my game is not targeted towards traditional MMORPG players in the first place (for one thing, PvP is not only encouraged but pretty much mandatory). it is more like a persistant action rpg. dont get me wrong though, there are still heavy persistant RPG elements to it and when i said "heavily" action based i probably should have followed that with "for an RPG" [grin]. my goal is to handle 30 players which i think is very reasonable from the tests ive done so far with my game. i have some good plans to help hide latency on top of this. i actually think its fun to mix 2 different methods of network programming, and so far it seems to be coming along pretty good.
FTA, my 2D futuristic action MMORPG
Perhaps you should have a fixed timstep, for the server end.
On logon, the user syncronises with the server, along with the current time (from the server. it starts at 0 when it starts, and will probably end in 2^64 steps, or
18446744073709551616 * (1 / 16) which is
18446744073709551616 / 16 seconds
or 2^64 / 2^4 which is 2^60 or
1,152,921,504,606,846,976 Seconds. Which is a very long time... (Aproximatly 38,121,172,896 Years (Thirty Eight Billion, One Hundred Twenty-One Million, One Hundred Seventy-two Thousand, Eight hundred Ninty-Six years)
Now, when your client sends the message, it goes and picks a time T, in which the action will go ahead, based on your average ping time. Now your client starts moving, as it sends the packet.
Now when it recieves a confermation, it just keeps going in the direction it was in. When it hears a rejection, it skips back to where it started from and tries again. After a few tries, it gives up.
So, using a similar system, all the comps would know what was going to happen (that is close enough to them), a few steps before it happened. And at all times, the server is authoritive. The client says that it needs a full update, and the server sends the relitive positions of movable objects relitive to them.
And the server and real time when it was sent.
Now, this would work well for some types of games, it might not be the best for mmorpg's, but i would say that it is workable.
From,
Nice coder
On logon, the user syncronises with the server, along with the current time (from the server. it starts at 0 when it starts, and will probably end in 2^64 steps, or
18446744073709551616 * (1 / 16) which is
18446744073709551616 / 16 seconds
or 2^64 / 2^4 which is 2^60 or
1,152,921,504,606,846,976 Seconds. Which is a very long time... (Aproximatly 38,121,172,896 Years (Thirty Eight Billion, One Hundred Twenty-One Million, One Hundred Seventy-two Thousand, Eight hundred Ninty-Six years)
Now, when your client sends the message, it goes and picks a time T, in which the action will go ahead, based on your average ping time. Now your client starts moving, as it sends the packet.
Now when it recieves a confermation, it just keeps going in the direction it was in. When it hears a rejection, it skips back to where it started from and tries again. After a few tries, it gives up.
So, using a similar system, all the comps would know what was going to happen (that is close enough to them), a few steps before it happened. And at all times, the server is authoritive. The client says that it needs a full update, and the server sends the relitive positions of movable objects relitive to them.
And the server and real time when it was sent.
Now, this would work well for some types of games, it might not be the best for mmorpg's, but i would say that it is workable.
From,
Nice coder
Click here to patch the mozilla IDN exploit, or click Here then type in Network.enableidn and set its value to false. Restart the browser for the patches to work.
Quote:
Original post by graveyard filla
@Radu
thats why my game is not a MMORPG [smile]. i dont plan on supporting people from all over the world but i think the game will still be playable even with a high ping. also, my game is not targeted towards traditional MMORPG players in the first place (for one thing, PvP is not only encouraged but pretty much mandatory). it is more like a persistant action rpg. dont get me wrong though, there are still heavy persistant RPG elements to it and when i said "heavily" action based i probably should have followed that with "for an RPG" [grin]. my goal is to handle 30 players which i think is very reasonable from the tests ive done so far with my game. i have some good plans to help hide latency on top of this. i actually think its fun to mix 2 different methods of network programming, and so far it seems to be coming along pretty good.
Oh, I was under the impression, from the previous thread, that it is an MMORPG. Well, if it's just a multiplayer game I can't really help you, but I suggest you looking through the Quake 1/2 network code. You can't beat JC's 1337 skils anyway :)
hi everyone,
i have been working on this, and im not really liking the results i see. i might just be screwing up somewhere in my code, but movement appears to be "jerky". ive been working on it alot, tweaking everything i could think of, but its just not getting any better.
anyway, its really late, and i was just doing some brainstorming and thought i would share my ideas with you guys, and maybe you could comment on it or something. its too late to try implementing this now, but i just had this idea..
basically, it would work like this.
- client sends "i want to move. i clicked at X,Y." the client does _not_ start moving at all, not even at half his speed.
- server gets the message and grabs his average ping/2 (we will call this p2 from here on out). the server then waits p2 MS before executing this movement on his simulation. he then sends to the client "ok, your good to go. here is your position, your p2, also, the time is T". the client gets this and sets his position to what the server has. there should not be much of a difference here. the client then finds how long it took to receive this packet. if the DT is > p2, then he jumps to make up for lost time, where lost time is dt - p2. if p2 is > then the DT, then he waits p2-DT MS and then executes the movement.
also, at the same time the server sends this ack back to the client, he sends to all clients in the area "a player is moving. his position is X,Y. here is his p2 and the time is T". these clients do basically exactly as the other client did. they see if the time it took to get the packet is bigger then the p2. if it is, then they jump to catch up. if its not, then they wait to execute the movement.
the result is that clients will see a ping delay in initial movement. however, there should be barely any "jumps". also, if you have 150 ping and another player has 150 ping, then other players should have no jump to their movement. if your ping is higher then another players, then there will be a jump where the jump is the difference in your pings (or the difference in your p2's i should say). if you have a lower ping, then there is no jump at all.
essentially, this boils down to instead of "everyone catch up to this guy", it turns into "lets all execute the command at time T, or if T has passed, lets catch up". anyway, this is all just in theory.. i might have screwed up somewhere in there, but its really late, so forgive me [grin]. hopefully that will give you an idea of what im trying to accomplish. the end result is a more delayed reaction to movement, but movement in general should appear much smoother, even with large pings.
theres one big worry i have with this system though. in several cases (3), the peer must wait X MS, and then execute the movement. for example, when a server gets a movement message, he waits ping/2 MS and then executes the movement. when a client gets his movement ack, he could possible have to wait ping/2-DT MS to execute his own movement. for other clients, you would have to do the same. this worries me. since we have to wait, how could we be sure that we actually only wait that exact amount of time? at best, we could only hope for N MS resolution, where N is FPS/1000, correct? do you know what i mean? think: if the wait begins at the top of our loop, and we have to wait 3 milliseconds, but the rest of our loop takes 5 miillseconds, then when we get back to the top, we should have executed the action 2 MS ago.. would i need threads to get things working? or, maybe i should put CheckActionQueue() all over my code? (e.g. at the top of the loop, the middle, the bottom, possibly inside a tight loop, etc..)
thanks a lot for any help.
[Edited by - graveyard filla on January 26, 2005 3:56:45 AM]
i have been working on this, and im not really liking the results i see. i might just be screwing up somewhere in my code, but movement appears to be "jerky". ive been working on it alot, tweaking everything i could think of, but its just not getting any better.
anyway, its really late, and i was just doing some brainstorming and thought i would share my ideas with you guys, and maybe you could comment on it or something. its too late to try implementing this now, but i just had this idea..
basically, it would work like this.
- client sends "i want to move. i clicked at X,Y." the client does _not_ start moving at all, not even at half his speed.
- server gets the message and grabs his average ping/2 (we will call this p2 from here on out). the server then waits p2 MS before executing this movement on his simulation. he then sends to the client "ok, your good to go. here is your position, your p2, also, the time is T". the client gets this and sets his position to what the server has. there should not be much of a difference here. the client then finds how long it took to receive this packet. if the DT is > p2, then he jumps to make up for lost time, where lost time is dt - p2. if p2 is > then the DT, then he waits p2-DT MS and then executes the movement.
also, at the same time the server sends this ack back to the client, he sends to all clients in the area "a player is moving. his position is X,Y. here is his p2 and the time is T". these clients do basically exactly as the other client did. they see if the time it took to get the packet is bigger then the p2. if it is, then they jump to catch up. if its not, then they wait to execute the movement.
the result is that clients will see a ping delay in initial movement. however, there should be barely any "jumps". also, if you have 150 ping and another player has 150 ping, then other players should have no jump to their movement. if your ping is higher then another players, then there will be a jump where the jump is the difference in your pings (or the difference in your p2's i should say). if you have a lower ping, then there is no jump at all.
essentially, this boils down to instead of "everyone catch up to this guy", it turns into "lets all execute the command at time T, or if T has passed, lets catch up". anyway, this is all just in theory.. i might have screwed up somewhere in there, but its really late, so forgive me [grin]. hopefully that will give you an idea of what im trying to accomplish. the end result is a more delayed reaction to movement, but movement in general should appear much smoother, even with large pings.
theres one big worry i have with this system though. in several cases (3), the peer must wait X MS, and then execute the movement. for example, when a server gets a movement message, he waits ping/2 MS and then executes the movement. when a client gets his movement ack, he could possible have to wait ping/2-DT MS to execute his own movement. for other clients, you would have to do the same. this worries me. since we have to wait, how could we be sure that we actually only wait that exact amount of time? at best, we could only hope for N MS resolution, where N is FPS/1000, correct? do you know what i mean? think: if the wait begins at the top of our loop, and we have to wait 3 milliseconds, but the rest of our loop takes 5 miillseconds, then when we get back to the top, we should have executed the action 2 MS ago.. would i need threads to get things working? or, maybe i should put CheckActionQueue() all over my code? (e.g. at the top of the loop, the middle, the bottom, possibly inside a tight loop, etc..)
thanks a lot for any help.
[Edited by - graveyard filla on January 26, 2005 3:56:45 AM]
FTA, my 2D futuristic action MMORPG
Here would be a simple idea.
Your server is syncronised.
It does 16 updates a second. No matter what.
Now 1/16 second resolution is ok, usually.
Now, when you logon to the server, the server says "I started counting at time ms/s/min/hour/day/month/year"
From that, and the clients own clock (which is syncronised to an atomic clock (Remember those web adds?)), can work out what the current server time is.
Now the client says something to the effect of "What can i see"
Then the server streams back a list of objects, their textures (ie. #19, not the whole actual texture), and where they are.
Now, whenever something moves, it goes and tells the server before it moves.
Ie. "I will change my velocity by 1.0,2.3 at time T1" Where T1 is a few timeslices in the future.
Then the server records that, and gets ready to change its model at time T1, to the new coordinents.
But before it does that, it sends it to all the other clients, so that now, as long as T1 is far enough in the future, there is no percievable lag.
There is also no jumping because of mispredicted coordinents.
When something goes wrong, your client simply gets a list of updates, and evenually it'll get through. So, it'll jump then, but not most of the time.
Now, theres another way.
You could get it to do, microupdates. So it keeps going as though its doing 16 updates per second, only it runs faster (with fewer clients). It still drops players if it can't make the 16 per second, but now updates occur more often.
Also, the server should be split into two halves (which should probably run on two processors, in two different threads).
One is the network code, which just gets the messages off the network, shoves them on a stack, and tells all the other clients about it. It does this continuously and is not synced to anything.
The second, is the physics and ai code, which runs the rest of the game from the data it gets from the first thread.
From,
Nice coder
Your server is syncronised.
It does 16 updates a second. No matter what.
Now 1/16 second resolution is ok, usually.
Now, when you logon to the server, the server says "I started counting at time ms/s/min/hour/day/month/year"
From that, and the clients own clock (which is syncronised to an atomic clock (Remember those web adds?)), can work out what the current server time is.
Now the client says something to the effect of "What can i see"
Then the server streams back a list of objects, their textures (ie. #19, not the whole actual texture), and where they are.
Now, whenever something moves, it goes and tells the server before it moves.
Ie. "I will change my velocity by 1.0,2.3 at time T1" Where T1 is a few timeslices in the future.
Then the server records that, and gets ready to change its model at time T1, to the new coordinents.
But before it does that, it sends it to all the other clients, so that now, as long as T1 is far enough in the future, there is no percievable lag.
There is also no jumping because of mispredicted coordinents.
When something goes wrong, your client simply gets a list of updates, and evenually it'll get through. So, it'll jump then, but not most of the time.
Now, theres another way.
You could get it to do, microupdates. So it keeps going as though its doing 16 updates per second, only it runs faster (with fewer clients). It still drops players if it can't make the 16 per second, but now updates occur more often.
Also, the server should be split into two halves (which should probably run on two processors, in two different threads).
One is the network code, which just gets the messages off the network, shoves them on a stack, and tells all the other clients about it. It does this continuously and is not synced to anything.
The second, is the physics and ai code, which runs the rest of the game from the data it gets from the first thread.
From,
Nice coder
Click here to patch the mozilla IDN exploit, or click Here then type in Network.enableidn and set its value to false. Restart the browser for the patches to work.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement