🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Everything working...and now?

Started by
22 comments, last by Almar Joling 23 years, 4 months ago
25 bytes per packet for each ship on screen? or for all of them together? If it''s 25/update at 10 ups thats about 250 bytes/sec + 32*10 bytes UDP overhead, or about 570 bytes/sec. Thats pretty good for an action game. However, if thats per ship then say 5 ships on screen 250*5 + 320 = 1570 bytes/sec still pretty good. Say a 56k modem, at a sustained byte rate of 3.5 k/sec can support 12 ships on screen, thats excluding other updates such as state changes and bullets events. Still quite acceptable for a space game.

I currently use a 15 update per second update rate. Unfortuantely it was an early design decesion and can''t be changed now, as too much logic is fixed to the 15 ups. If i had the time i would revamp it to 10 ups and get about a 20% decrease in bandwidth usage, plus from my calcuations no noticable difference in gameplay.

Dont worry about packet loss, as at 10 ups, there is always a new packet comming in. If you were to say implement a varaible update scheme where an entity can update between 1 - 10 ups, it might be worthwile to implement some form of relaible udp transmission.

10 ups is i think the standard for action games, from my reading.

Well Good Luck

-ddn
Advertisement
Well, the server will do a "relevance check" and only send data to players who are relavant to each other.

But, 12 ships on screen, or in one group can easy be reached, especially if the game is based on team work (8 ships close to each other, ready to attack the other side for example)

Netrek uses 5 updates/sec, and works pretty well. Now I was wondering if it''s more efficient to let a "stable" work on 5-1 update a second, and when the ship moves too much out of sync, that a new packet will be sent by this player. (Calculating it''s own death reckoning path)

I''m working on the Cubic Spline of fPrefect, the only problem is that I''m stuck with the variable "time", it''s between 0-1, and I''m not sure how to calculate the increasing steps, it''s just something I can''t solve correct. I thought about "1 / UpdaterateInMilliseconds". so 100ms, becomes 0.01. And where it should start when a new packet arrives. 0.75?

On what for type of game are you working on Ddn? Just curious.

Thanks in advance,
Almar Joling
In your spline, t=0.0 is the time when you get this packet, and t=1.0 is when you expect to get the next packet. To convert those values into milliseconds, simply multiply by the period between your packets. If your next packet is due in 100ms, then halfway is your position at t=0.5, or 50ms.
Matt Slot / Bitwise Operator / Ambrosia Software, Inc.
Okay, I''ve become so *desparate*(working on this project for a year) that I''ll post some code, that I''ve made. It''s Visual basic, but you all should understand it. (I suppose every C++ programmer knows a bit of VB?) I''m using an update interval of 100ms...

".vecCubicSpline(0)" is just one simple "D3DVector2" nothing special. It is also the position of the ship on screen!
(A D3DVector2 is "x,y")

''=======Following sub: when a new packet arrives, it will be send through this sub to create a new spline''=======Public Sub NewPacket(ShipID As Integer, NewPos As D3DVECTOR2) Dim CurrentPosition As D3DVECTOR2 Dim Current100Ms As D3DVECTOR2 Dim OldVelocity As D3DVECTOR2  Dim NewPosition As D3DVECTOR2 Dim New100Ms As D3DVECTOR2 Dim NewVelocity As D3DVECTOR2    If Players.Count < 2 Then Exit Sub        Players.Choose 2        With Players            CurrentPosition = .vecCubicSpline(0)            OldVelocity = .vecOldVelocity            Current100Ms.X = CurrentPosition.X + (OldVelocity.X * 100)            Current100Ms.Y = CurrentPosition.Y + (OldVelocity.Y * 100)                NewPosition = NewPos            NewVelocity = .vecVelocity            New100Ms.X = NewPosition.X + (NewVelocity.X * 100)            New100Ms.Y = NewPosition.Y + (NewVelocity.Y * 100)                    P(0) = CurrentPosition            P(1) = Current100Ms            P(2) = NewPosition            P(3) = New100Ms        End WithEnd Sub 


The ships are "following" the cubic spline path (the x,y position returned by "CubicSplineReturn", using the time variable), created by the algorithm on Gamedev.net (I thought I mentioned the URL earlier in this thread). Now this is where the problem is... I just can''t get the "time" right...

Public sub FollowShip()    If Players.Count < 2 Then Exit Sub        .Choose 2        CurrentTime = CurrentTime + 0.1 ''100ms???        If CurrentTime > 1 Then CurrentTime = 0        retCubic = mdlInterpolation.CubicSplineReturn(CurrentTime)        .vecCubicSpline(0) = retCubic ''on screen position!        Me.Caption = CurrentTime ''disregard...End Sub 



Please help & any help apreciated,
Almar Joling

(PS: I can upload a compiled version if needed)
Almar Joling

Well, I don't speak VB, but I can do pseudo code:

TimeBetweenPackets = 100 // constant in milliseconds
TimeOfLastPacket = 0 // updated with each packet

FollowShip()
CurrentTime = GetMilliseconds()
DeltaTime = TimeOfLastPacket - CurrentTime
if DeltaTime < TimeBetweenPackets
// Still following the path, 0.0 < t < 1.0
CurrentLocation = CubicSplineReturn(DeltaTime / TimeBetweenPackets)
else
// Waiting for new packet, fall back on dead reckoning
CurrentLocation.X = NewPosition.X + (NewVelocity.X * DeltaTime)
CurrentLocation.Y = NewPosition.Y + (NewVelocity.Y * DeltaTime)
end if
end FollowShip()

Where NewPosition and NewVelocity are the same variables used in your NewPacket() routine above. The only major addition is a millisecond clock to tell how old your data is. With this, you know how far along the spline you should be (t<1.0), or how far past your prediction you have gone (t>1.0).When a new packet arrives, the equation starts again.

Edited by - fprefect on February 15, 2001 10:15:09 AM
Matt Slot / Bitwise Operator / Ambrosia Software, Inc.
I dont know enough about VB to understand completely what you''ve written. You''ll have to reprhase it in pseudo-code for us non VB literate folks 8^).

There are 2 things you need to consider while using splines. From reading the article splines are used to interplate from known positions to what is essentially desired positions. If your using splines to interperalte from known positions to known positions, that is your passing along to the client data points sampled from the players position, then the client must always run behind the server if it wishes to smoothly interpolate between the data points. Ohterwise if it wishes to use the most current data point as positional data, it cannot interperlate correctly as the next data point has yet to arrive, and so on and so on.

To use splines you have to think of the next data point, not as a sampled positional data point but as a desired positional data point. That is a projection of where the player will be, not just on the client but also the server side too. This is really the only way to use splines without the latency hit of interperlation. Lets look at an example.

t0 on server:
-client facing east, moving 1 velocity unit in direction of facing. Client wants to turn north presses the ''north'' key, and this is recived and processed by the server on tick t0.

-server extraplates based upon contraints of the player (turning radius, speed, etc..) where his final position will be, and generates a desired positional data point, which it will smoothly inteprelate the current positon of the player to the final position in say 10 ticks(this is proably based upon the player constraints), using cubic-spline interperlation. (notice this is still t0)

-server sends to the client the desired positional data point. You could send extra data such as timming information, current positional data, etcc. Really depends on how synchronized your client - server is and how much loss is on the line.


t0-1 on client :
-client waits for data, until then it interplerates from the current position to a deisred positonal data point (which is btw old, but the client doesnt know this yet).

t0 on client :
-client recives desired positonal info packet from the server. This data contains the new desired positional data point for the player.

-it should be noted that the client recives the packet on its t0. This may not be the case in your scheme, as there are several different timming syncrhoniation methodology you could use. This was discussed in another thread. I use the 1/2 latency method of timmer sync for the client, becuase it doesn''t force the client to extrapalte too far forward into the future when it recived positional data. Another method is to syncrhonize with the servers timmer (which in this case the client currently would be at t0+latency_ms/tick_ms) which would force the client to extrapalte further to stay in sync with the server. For modem players this would result in jerky and jarring movements, even with spline interpelation.

-so the client has a new desired positonal data point. It uses this to interperlate forward to for t10 ticks(this either has to be sent with the packet or can be derived from some existing data the client has accessed too).

This just repeats in a continous cycle. Now there are 2 possible problems which you have to deal with, lost packets and culuminative synchronizaiton error. Lost packets can be dealt with by sending periodoic positional update (both desired and sampled) or implmeneting some sort of reliable udp scheme. Culuminative synchornizaiton error is more tricky. Notice in our disccusion about lag and its chaoatic nature (both in average latency and its standard deviation). Due to the nature of lag, packets will not arrive at a fixed interval. Even with your best syncrhonization scheme, packets will arrive with slight timming discrepancies to the clients predicted time. In our example the packet arrives at t0, but in reality it will proably arrive at t0+error. Where error is related to the standard deviation and how long a tick is. For good lag players error will be small enough to ignore for a few ticks, but eventually it will add up, and for badly lag players it can''t be ignored at all for even one tick.

To combat this cumulinative error you''ll need to peroidicly send absoulte postional data on the client, to resynchornize the client with the server, if your scheme is smart it can customize this update to the player as nessecary (say once every sec for lagged players, and once every 10 secs for good lag players)

Well hope this helps.

Good Luck

-ddn





















-ddn
For thin clients, you should always send absolute position data in your status updates -- otherwise losing a packet makes the whole sequence invalid and you have to resynchronize on an absolute packet anyway. Relative positions and virtual input methods tend to fall apart miserably under any real latency or packet loss, unless the client is equipped to follow high-level instructions (turn 90degrees N with radius 2 over the next 4 ticks).

Anyway, as I understand it, Almar''s code relies on a thin client that simply moves the ship from one location to another using absolute position data. Based on that...

Each absolute packet should hold the current location, orientation, and velocity (perhaps acceleration too) of the ship. This is enough data to correct any error and extrapolate the object''s new path (using dead reckoning) over the next few graphic frames, until the next packet comes in and corrects your prediction.

The benefit of the splines is not the course correction -- you could do that by simply slamming the new position data, making the ship appear to teleport in lag. The real benefit is to *smoothly* transition from the ship''s current location and vector (possibly incorrect) to a vector that matches the latest packet -- and does so before the next packet arrives.

If the delay between updates is lengthy (>100ms), you have several graphic frames to integrate your course correction; if the delay is short, then there isn''t likely to be much error to recover from anyway -- and if the latency is erratic (t is frequently >1.0), then the algorithm falls back on generic dead-reckoning based on the most recent data.
Matt Slot / Bitwise Operator / Ambrosia Software, Inc.
Hmm, your reply is very interesting but I'm worrying about one
factor. If you let the server calculate the new position, the
postion will likely to be wrong.
The server does not know when the "rotate" will stop.
Unless you do some sort of time synchronisation.
Currently, I've made my game so that it doesn't allow keypresses within 50ms.
With time synchronisation it's possible to use (TimePassed / 50 * AngleIncrement)
Although you're still not sure when the rotation will stop.
But with a steady packet stream this could work.

If I understand Ddn correctly you're explaining like "Here you
are, there you go" if I'm right?

quote:
"if your scheme is smart it can customize this update to the
player as nessecary (say once every sec for lagged players, and
once every 10 secs for good lag players)"

Hmm, what about:
If (ReceivedPosition-PositionOnScreen) > 20 Pixels Then
MoveAbsolute 'a "hard" update
Else
MoveRelative 'a "soft" update,using spline
End If

All those splines got me confused... is the article on gamedev.net Cubic Spline interpolation or not?

I've got fPrefects code *almost* working, but there's still some minor problem, somewhere. I'll work it out in P-Code.
btw, I first want to mention that I really appreciate your support (fPrefect, and ddn) I've been stuck at network synchronization (smooth movement part) for a long time, and finally I'm getting somewhere.

-----P-Code-----
//A new packet arrives, containing: Position, Velocity, Angle,Index,Playerid//The latter two are not really important here.//When a new packet is received it will be sent to "NewPacket"Sub NewPacket(Data as Packet) //This sub will create a new spline. Called everytime for a new //packet. // Position1-Position4 are the positions that are required to form the spline Position1(x,y) = PositionOfShip(x,y) //position of ship, it's the position of the local dead reckoned/"splined" ship (the one that the user sees!)  Position2.x = Position1.x + OldVelocity.x * TimeValue Position2.y = Position1.y + OldVelocity.y * TimeValue //Old velocity is the velocity BEFORE the new packet was received. Position3(x,y) = NewPacketPosition(x,y) //Use the new received packet position for the 3rd point Position4.x = Position3.x * NewVelocity.x * TimeValue Position4.y = Position3.y * NewVelocity.y * TimeValue //Newvelocity is the velocity that has been received in the new packet.  //Now we have 4 points for our cubic spline. "TimeValue" is anumber which is //just guesswork for me right now... it can be 100ms...250ms.// It doesn't really matter. I have the feeling that the error is here somewhere...//The ships seem to warp-and back constantlyEnd sub  


Next comes the code that is being used in the game's main render loop. It's similar to the code of fPrefect, but he made one mistake in it. I've pasted his code here. And changed the small error

TimeBetweenPackets = 100 // constant in millisecondsTimeOfLastPacket = 0 // updated with each packetFollowShip()CurrentTime = GetMilliseconds()//small mistake fPrefect, it shouldn't be "TimeOfLastPacket - CurrentTime" but:DeltaTime = CurrentTime - TimeOfLastPacketif DeltaTime < TimeBetweenPackets// Still following the path, 0.0 < t < 1.0CurrentLocation = CubicSplineReturn(DeltaTime / TimeBetweenPackets)else// Waiting for new packet, fall back on dead reckoningCurrentLocation.X = NewPosition.X + (NewVelocity.X * DeltaTime)CurrentLocation.Y = NewPosition.Y + (NewVelocity.Y * DeltaTime)end ifend FollowShip()  


And I've also put the cubic spline code, to make it complete...

//t is the time variable. It ranges from 0 at the initial point to 1 at the end point. //Formulating the rest of the variables. A = x3 – 3x2 +3x1 – x0B = 3x2 – 6x1 + 3x0C = 3x1 – 3x0D = x0E = y3 – 3y2 +3y1 – y0F = 3y2 – 6y1 + 3y0G = 3y1 – 3y0H = y0x = At3 + Bt2 + Ct + Dy = Et3 + Ft3 + Gt + H   



Well, that's the code that got me sleepless nights :o)
There's somewhere a small mistake, which I just can't find. The ships move very weird, I can't explain it so I've put a sample version online it runs at 150ms/packet. and will connect to 127.0.0.1 (localhost), so running two clients will do. Note that if you drop out the game, and want to try it again you have to restart the server... it's only been build to route data, and the game won't work straight when it thinks there are 3 players.
Before starting the game, run the server. When the server shows up, DP8 has been successfully initialized, and you can run the clients.

It's 40kb. http://www.quadrantwars.com/files/qwtest.zip

Again, Thanks,
Almar Joling


Edited by - Almar Joling on February 16, 2001 6:27:17 AM
I wouldn'' discount virtual input, it''s a valid and effiecent control mechanism. It''s even more tolerant of loss than the simpler absolute positional/velocity update method, ofcourse you''ll have to build in some redundancy just as you would with the absoulte positonal/velocity method, but not as much. In addition to its lower latency overhead.

If your using absolute sampled positional data points and interperlate between them to get a smooth path, you cannot suddenly interject a new data point wihtout first completing the current one your on. If you did the path would not be consistent with the one on the server. So i think Almar is getting confused on how to interject new data points with respect to the old data points. You don''t, you just complete the last one and then used the next one , and buffer any other comming down the pipe. Thus the drawback of using sampled positional data points and spline interperlation. To avoid this you would use the concept of desired positonal data point, which can change anytime, and has no inherent latency hit, as it''s the position which is projected by both the server and client as too where the player will be, not currently is at. At worse, this degrades into an absoulte positional update (if the projected position occures within the span of a tick), but normally withhin a constrained system (cant turn on a dime, has velocity etc..) it will smoothly interperalte between the points.

I use a system very similar, and i''ve noticed it''s more robust and uses less bandwidth than the absolute method.

Good Luck

-ddn

Hmm, English is not my native language (although I''m better in it than Dutch), and I''m not sure what you completely mean.

If I get it right, you say that I shouldn''t create a new spline everytime, but just shift the points "through"

Like?)
Position1 = Position2
Position2 = Position3
Position3 = Position4
Position4 = NewPosition

This will shift the vectors, and keep the spline in form.
Not sure if you mean this. I''m not familiar with the word "interject" but it means putting something between something else...

This topic is closed to new replies.

Advertisement