Game Development Community

Can I use setScenePhysicsFPSActive for multiplayer physics?

by John Klimek · in Torque Game Builder · 09/28/2006 (5:51 pm) · 14 replies

Many of you have probably seen my name and have probably seen it associated with posts about multiplayer real-time networking (and my Scorched Earth game clone). Well, I'm still trying to figure out a way to get consistent physics across different machines (so when I launch a projectile on one machine, all of the other machines will have the exact same trajectory and exact same collision point).

Based on a reply from Melv, I've tried out the setScenePhysicsFPSActive command and am very suprised by the results. It seems to give me EXACTLY the same collision points on several different machines! However, if the solution was this easy I don't think I'd be having the problems I seem to have.

Anyways, will setScenePhysicsFPSActive ensure me the same physics on every machine? (eg. so I can simply tell each client "use t2d physics to launch a projectile at XX velocity" and then I will be assured each client will have their collisions *exactly* the same)

As always -- thanks for your help!

- John

#1
09/29/2006 (12:11 am)
John, we've been over this before bud--there is no way possible in any engine to have on the fly physics calculations to be exactly the same on all machines without a fully custom physics implementation designed to do exactly that (and I'm talking a full bore one--for cross mac/linux/windows machines for example, you're even going to have to write/use a software floating point math library, since the hardware across different cpu types isn't even consistent and deterministic).

This is why, for those games that require this type of scenario, developers have traditionally used pre-calculated tables of physics responses combined with interpolation of objects between physics states.

What you need to do in my opinion is to research the concepts of interpolation (external to GG's forums, although there are some good posts regarding the general concept), and transmit unique and deterministic game world positions and trends (velocity, rotational velocity, etc), and then have deterministic interpolation methods that get you from here to there.

However, you still won't have two machines stand side by side and see the exact same thing at the exact same time--and that's due to the fundamental technology of network information delivery.
#2
09/29/2006 (5:54 am)
Sorry, I got excited when I seen that two machines had the exact same collision points... (and thought that maybe everything else would stay in-sync)

I also understand about multiple machines seeing things at the same time; I know that latency (eg. lag) will cause *every* machine to see things at a different rate, but as you said all I need is for everything to be deterministic so everything happens exactly the same (not at the same time, but same trajectory, pathing, etc, etc...)

I think that implementing an entire deterministic physics engine is a bit above my skill level so I'm still trying to figure out a way to make my game multiplayer. Here's what I've tried so far:

1) Calculating the trajectory using vector math on the server and then sending the path to each client. The problem is that moving between calculated points is interpolated and can produce different points (and different collisions) on each machine.

2) Implementing real-time networking following Tom Bampton's guide from TGE to TGB. I'm still trying to get this to work but I'm not having much luck so far.

If you can think of any other ideas for me to try please let me know. I wish I was more skilled and was able to write a deterministic physics engine with interpolation, but I just can't. :(

Thanks for your reply and as always thanks for your help! I really do appriciate it.
#3
09/29/2006 (9:40 am)
A basic skeleton:

--first, write script code that interpolates an object's position within your scene based on known parameters. In other words, give it a start point, an end point, some values (whatever you want, things like trajectory, speed, air resistance, whatever), and a total time for the move to take place. For the most part (tweak as you decide you need once you have the basics working), the clients should have physics turned off. Your interpolation algorithm here is basically your "physics", since you are trusting the server to handle physics checks.

--second, use the server side only to determine start and end points for a particular game action. This would be your base game logic--player fires a missle, the server determines where the missile should start, where the missile should end, and most importantly, only the server tracks for collisions. You will probably want the server to be checking forward (castCollision used in some way) so that you can update your clients as soon as possible for any upcoming collisions, but in general any time things are going to change on the server, send a new commandToClient(s) to make sure they are interpolating to a new position.

I'd start small on this framework to get the feel for how it would work. Create an extremely basic interpolation routine for your client side, such as moving in a straight line given a start point, an end point, and an amount of time to make the end point. Then you can add more to your interpolation routine, giving you a trajectory, etc. Finally, you can start sending intermediate end point/trajectory updates and make sure your clien side interpolation is recovering from the changes nicely, and finally you can handle creating new events like "collide", "explode" and the like.

All this can be done in script, and in fact you are basically doing a script version of real time networking, just at a bit slower rate and with slightly less information being sent.
#4
09/29/2006 (11:10 am)
First off, thanks for that very informative post. I think I have a general understanding of what you're saying and it sounds like it should work!

However, I am a bit confused. I understand that the server should be the only thing tracking collisions and then notifying each client, but wouldn't that require very, very low latency? (or would the server say, "in 2 seconds this object will have a collision at xx,yy?)

For the interpolation, would this be called every frame or how would it work and how would the server be able to give updates to the clients?

Michael Worister wrote a simple function that calculates N number of points based on a starting position, velocity, mass, wind, and gravity but I don't think you're talking about that. Are you talking about having the server send segments of the entire trajectory to the client every N seconds?

Ideally I'd like to implement "black holes" (eg. areas of the level that affect the trajectory of an object if an object gets too close). Would this be possible with the methods you described? (if not thats OK... at least I'd still have something that works!)

I think one of my main confusions is how the server can send intermediate updates while the projectile is in motion. I do understand the concept of interpolation but it seems like when the server sends a message to the client, the client would be receiving "late" information and the projectile would be much further than where the server told it to be.

Again, thank you so much for your help Stephen. I really, really appriciate it.

Hopefully this thread can also be useful to other people trying to create similar games!
#5
09/29/2006 (11:48 am)
@John: Now you are starting to understand just a few of the reasons why this is such a difficult challenge!


--the basic premise of simulations like this is that the client is always operating "in the past" with regards to the server. You have to add on extrapolation (how to have the clients move further than the server in cases of latency/lost information) to allow for those situations you mention, and again that will need to be at least relatively deterministic, plus have a mechanism for correction.

--You are correct, high latency can cause this model to break down, although that can be adjusted for by selecting and tweaked use of castCollision on the server to try to send updates for the future. Basically, if you have your server running in future time, and come up with an algorithm to determine when to send updates and why, you can help to overcome that.

--I am talking about the type of interpolation Michael discussed, although I highly, highly suggest you start with a much simpler interpolation model, and learn how it's working for you intimately so you can make wise decisions about how to implement your enhanced effects (black hole, etc.).

--ideally, your server would calculate the entire path of an object, reduce it down to parameters that can be interpolated, and send the parameters to the client for interpolation.

If the server then later detects a situation that has occured that must be corrected, it would send updated parameters to the clients, and the client must be able to accept those updated params and interpolate to them. Not necessarily trivial,so again start small and easy.

Ironically, by the time you get all of this done, you've gotten to the Torque real time networking model (not part of TGB), but hopefully along the way you've picked up a lot of understanding of how it actually works.
#6
09/29/2006 (12:04 pm)
I'm still a bit confused (not suprising) since it seems like you are talking about two different models:

1) Sending entire path information.
2) Send information to the clients while the projectile is in motion.

Your first paragraph above talks about extrapolation , and your second to last paragraph talks about if the server detects a situation that must be corrected. This leads me to believe you are talking about #2 from above.

However, you say in the third paragraph from the bottom that I should calculate the entire path of an object. This leads me to believe you are referring to #1 from above. However I don't see how I can calculate the entire trajectory of a projectile when other objects might influence it's movement (eg. black holes and other special effects).

With either method, it seems like I need to implement a function that is called every frame (that does the interpolation/extrapolation). Is this right? (also see my comment in the first paragraph about how I don't see why I'd need extrapolation if I somehow calculate the entire path of the projectile)

Regarding the use of castCollision for the future, are you suggesting I use castCollision and then tell the clients to "queue" this collision until the specified time?

Any chance you will be on IRC later tonight? Maybe we could talk about this a little more?

Thanks !!
#7
09/29/2006 (1:19 pm)
Bascially, I'm talking about the server pre-calculating (running in future time, or simply looking ahead using castCollision) the entire path of the object, reducing it to parameters that can be interpolated, and having the clients be sent that information in a NetEvent (via commandToClient) to replicate the information.

Remember that with interpolation, you must know the start and end states to interpolate.

Then, the server "hangs out" in client time, and determines if there are going to be any adjustments that need to be made to the pre-calculated paths (by checking future time). If it detects one, it sends an updated set of parameters to the clients and the clients then interpolate from current position to the new position.

It's a complete mindset change, which I think you may be balking at a bit....the server is literally ahead in future time doing it's thing, and telling the clients to "catch up" when appropriate. And it's complicated!
#8
09/29/2006 (2:19 pm)
I do understand that the future is operating in "future" time because anything it sends out will to the clients will have already happened (eg. it will be in the past in the eyes of the server, but the current in the eyes of the clients).

I'm not sure about the server having to make adjustments to the pre-calculated paths by checking "future time".

Here's how I invision the system working:

1) Client tells the server he wants to shoot a projectile at 30 degrees with 100 power (eg. velocity).
2) Server approves and calculates the entire path of the projectile. (how can this be done if I'm using black holes and other trajectory-affecting stuff?)
3) The clients follow the path given to them by the server and interpolate between points. (once again, I can understand how a simple ballistic trajectory being interpolated but not other special effects).
4) The server notifies the client of the collisions. (but if the clients don't receive this exactly at the end of their trajectory movement I would think it would look strange...)

Maybe if you can give me a detailed example of a projectile from the server to the clients it would help?

I think my main confusion lies in the fact that you're saying the server sends the entire calculated path to the clients but then corrects it(??)...
#9
09/29/2006 (2:50 pm)
Well, I never said the server sends the entire path.

What I said was the server sends the information required to interpolate the path, and the client uses it's interpolation method to recreate the path deterministically, and move the object. That's what interpolation is about--given a start point, and an end point, some paramaters, and an interpolation algorithm you never 'send the path' at all.

Second, let's say that halfway through the interpolation, another player fires a different projectile that would collide mid-air with the original projectile. In this case, the server would recognize the collision, and being aware of what it collided with, realize that it would have to correct the original interpolation parameters sent out previously.

It would send out a new set of interpolation parameters, and the clients would then say, "hrm, my projectile was here, but now I have to do something different. Let's use where I am right now (simple case) and interpolate to the new destination given the change.

I still recommend that you sit down and just do a very basic version, and add on step by step instead of worrying about understanding the complete complex end case from the very beginning. You'll get a feel for what interpolation is actually doing, how it's working, and how to add to it, and a lot of the confusion should go away for you (I'm hoping!).

BTW, in your example above, the server would send something like:

Projectile starts at point X1, Y1, follows trajectory type A with speed V (note that in actuality, the speed is redundant because you have an end time of where the path will be required to end, so you would be calculating the distance to move per interpolation frame. The speed V however may affect the trajectory itself based on ballistic math, so it could be useful in later, more complex interpolations), collides at point X2, Y2 at time T. The client's interpolation code would then be responsible for moving the client side projectile along the path.

Get that up and working, then do it for multiple projectiles, then do the case where it would collide. By that point, the interpolation stuff should make more sense.
#10
10/02/2006 (1:20 pm)
Ohhh... you said the server calculates the entire path but does NOT send the entire path. (right?)

...or are you saying that the server eventually calculates the entire path?

For example, let's say a projectile is launched from (10, 10) going at (1, 1) per second. What determines the end point I send? From what I'm understanding (or not understanding), I don't send the entire path but I'm only sending "small chunks" of the entire path. (right?) That way if the projectile changes mid-trajectory I can send updates out to the clients.

It seems like all this would work if I can keep consistant time across all clients. Is this possible? Otherwise I'm not sure how to tell each client that at 14:03 a collision will occur at (20, 20), etc...

Hope you're not getting frustrated with me. I really appriciate the help!

- John
#11
10/02/2006 (3:38 pm)
Hehe...you no worries, it's a hard concept.

You are still missing a vital concept however: no path information is sent at all, period. Drop the concept of a path being sent from your mind completely.

What this implementation assumes:

--an algorithm implementation that, given
----a known start point and time
----a known end point and time
----provided "adjustment" parameters that may affect the behavior during movement
--implementation of this algorithm on the server
--implementation of this algorithm on the client(s)
--a mechanism to network the start point/time, the end point/time, and the parameters (commandToClient)
--pre-calculation on the server of the entire path of the object, in the server's time frame.
#12
10/02/2006 (4:15 pm)
Ok. No path information (eg. coordinates) are ever sent. Gotcha.

See, I'm thinking that the parameters about the trajectory are sent over once and only once each time a projectile is fired. So the start point would be the turret/tank location and the end point will be the terrain (or object) it collides with. However I think you're saying to send over "small chunks" of trajectory information at a time. This is what is confusing me.

What's also confusing is the whole "time" parameter. Where does this come from? (don't I need to synchronize time on all clients to make this work?)


I'm not sure what's harder... trying to implement TGE's networking into TGB or trying to understand this concept. Perhaps I should go back to trying to follow TomB's code... =(
#13
10/02/2006 (4:32 pm)
When I was writing a physics-based networking game, I found that the best way to get a feel for how to do was to simply try. My first attempts were absolutely terrible, but it's (usually) easy to see where you need to send more information or what the client and server are getting angry over. If you start out small and iterate a lot, you'll probably end up with something nice, and if you don't, then you'll be able to at least do a rewrite based on what you've learned the first time. Trying to understand the need for interpolation and time adjustment before you see the problems of a system without them is going to be hard.
#14
10/03/2006 (2:29 am)
Let's try to explain this from a different direction, maybe a use case would help :)

--player (on client) inputs a command to fire a projectile
--fire event is sent to server
--server says "ok, have a fire event. player is here. his settings indicate (hypothetical) a velocity of 10 and a firing angle of 30.
----server creates projectile, sets physics, and runs the simulation forward in an accelerate dmanner until the projectile collides with something. It uses your interpolation algorithm to figure out where the object will go.
----server then restores the state of the simulation, but "remembers" the firing position, the time of the collision, and the end point of the collision.
----server sends an event to the client that basically says: "create a projectile at x,y. this projectile should use a velocity of 10, and a firing angle of 30. Use your interpolation algorithm to move this projectile so that it reaches point X1, Y1 in at time T (which was calculated during the "accelerated" phase)
--client recieves the event
----client creates the projectile, gives it velocity 10 and firing angle 30, and then moves the projectile according to the interpolation algorithm along a path that will end up at the collision end point at time T, changing the postion and velocity of the projectile in accordance with what the interpolation algorithm says.

It's important to note that only one event is ever sent to the client in this simplistic case. Since the interpolation algorithm is the same on both client and server, all that needs to be sent is the parameters of the projectile, including end point, start point, and time at which the projectile must reach the end point.

This is your first iteration, as Tom mentions above. Make it very very very simple--have your interpolation algorithm simply move the projectile in a straight line. Have the server decide the collision point (castCollision comes to mind, although you may need an alternate method--it's late and I'm not sure castCollision will give you all you need right now), then simply send off the data once and only once.

See if you can get the projectile to do what it should on the client, and as Tom again mentions, get the simple case working, then add in more and more :)