Kal_Torak

Members
  • Content count

    77
  • Joined

  • Last visited

Community Reputation

346 Neutral

About Kal_Torak

  • Rank
    Member
  1. Releasing a game

    www.gameproducer.net Has a lot of info related to indie game development, marketing, and releasing indie games. Cheers
  2. Game Maker

    http://www.gamedev.net/community/forums/topic.asp?topic_id=500807
  3. As Mike said, rendering to a part of the window is pretty easy. I just took about 2 minutes and changed my renderer constructor to accept a Control instead of a WinForm, and then I just added a PictureBox (any Control derived class should work) to the form I was rendering to, passed the PictureBox control to the renderer, and voilà, my game was rendering to the PictureBox which was about 1/3 the size of the WinForm. I imagine you could switch between rendering to different Controls just as easily. I'm not sure what you'd have to do for reconstructing the device when you change Handles though, haven't done that myself. I'm using C#/SlimDX for my game projects, it's pretty smooth.
  4. Unity Building a level builder

    My first thought is that it looks more like a game builder than a level editor. It looks like most of your game logic will be written in the level editor, which, depending on how you divide up the functionality between editor and game could make it a bit confusing, and possibly too tightly coupled to the specific game to be very reusable. On the other hand, since it is a shmup, this style of editor seems like it could make it very easy to extend the game and easily add a lot of levels. Also, it seems a little odd not to define and use sounds in the editor, since everything else is defined and built there. Cheers
  5. GameMaker 7

    I believe one of the past winners of the GDNET 4E contest was made with Game Maker. Ninja Loves Pirate or some similar title IIRC. Game Maker is absolutely a good tool for the right job. You always have to keep in mind though, that the artist is what makes the painting, far more than what tools he uses. [Edited by - Kal_Torak on July 15, 2008 3:55:05 AM]
  6. Quote:Original post by hplus0603 When out of ideas, add logging! On the client, for each timestep, log the user input, the simulation state, the step number, and what you're sending to the server. For each received packet from the server, log the intended timestep and the server state. On the server, log each time step, the state for each player for that timestep, what state you're sending to each player, and what input (for which timestep) you receive from the client. Now, go through the logs, and compare the client and server states and inputs for each timestep. Processing your log into an Excel file might help with this, as will formatting the log to make it easy to machine parse. After doing this, you ought to figure out what the pre-/postconditions are for the bug firing, which in turn will let you insert conditional breakpoints, or asserts, to start debugging the problem. Belive me, I've done all that. Repeatedly. In depth. Ad infinitum. Everything matches up perfectly... Except that sometimes, even though everything syncs up, the numbers are wrong.
  7. Well. I restructured it to do one input, physics update and network update per tick. Still have the same bug. I did a couple other variations on the same theme, but apparently that's just not where the bug is. I'm all out of ideas.
  8. Quote:Original post by oliii something occurred to me (eureka!). I think it's a latency / rate problem. In the elapsed time you send an incorrect packet and receive the correction from the server, you will have sent potentially several more incorrect packets, and the server will have to send corrections for them. And if you keep doing that, the errors will never catch up until you send a valid position (i.e. you stop moving). Exactly. That is the problem that client side rewind & replay fixes. As soon as a server packet comes in that doesn't match the client position, it rewinds back to the timestamp on the correct packet and replays all the moves it was predicted ahead. Thus, the very next packet that comes in will match the new corrected state, and the dreaded correction loop is entirely avoided. The bug I have is sort of an edge case to this. It consistently replays all the predicted moves correctly. It's just the very next move, (that hasn't been sent yet) part of which was actually in the prediction/correction cycle, that is incorrect, and starts a new round of replaying. Quote: However, if I get this right, the number of corrections the server should send would basically fit into the latency window. After you receive the first correction, that should re-sync your character to the server (if you are not bumpipng into weird things again) after say, 200ms if you have 200 ms latency. A couple of things. Play with the tolerance (the thresholds used to detect an out-of-sync packet received from the client), and also, it should be possible to throttle sending corrections to the host (i.e. have a timer so you send corrections only every .1 seconds for example), that could stop the flooding of correction packets. See, the thing is, my server has no concept of the client being out of sync, or having a bad position. It merely takes a set of input, advances the client position, and sends back the results. So it doesn't send any additional corrections when the client messed up. If the client is out of sync, it's always the client's fault, and it's up to the client to fix it. Quote: Thirdly, when using UDP transmissions, inputs and predictions (that happen every 60th second for example) are bundled together on the client and sent at the network rate (say, 20th of a second). They are sent in batch if you will, to avoid multiplying packet. They are also sent duplicated to cover for packet loss. But using a reliable stream, I dont think that is necessary at all, and you can just write your data straight into the stream. My solution has pretty much the same effect. Instead of queuing up all the input that happens between network sends, I just poll the input at the same rate as the network so no input piles up on me. Quote: Another thing you can try for debugging, is to intentionally invalidate your prediction (say, if you press space, add 1 meter in the y position in your client-side calcualtions), and see what happens when the server corrects it. It should ping back in sync pretty quickly. Else, there is a pretty major bug in your code. Forcing a change of of the client's position would basically have the same effect as losing a packet. It wouldn't show up for #frames predicted ahead, and it would be effectually the same as having incorrectly predicted ahead, and it would be corrected as such. Quote: What we used to do is to apply one input per frame -> one physics update -> bundle inputs not sent yet -> send bundle at network rate. We had some problems with making the predictions work EXACTLY the same way on the client and server. Many things came into play and both machines would calculate a slightly different outcome for what we thought was a similar set of inputs. In the end, the inputs have to be exactly the same, and that means, identifying all your inputs that will affect your character physics. Right now, I'm not doing any prediction on the server. The server just deals with the input as it comes in. I may need to do some type of prediction down the road, to deal with giving all players a fair playing field regardless of latency. I'm not sure yet, haven't gotten that far. :D
  9. Ah, I wasn't thinking in terms of FPS games.
  10. Quote:Original post by hplus0603 and you actually let the user turn faster than the physics rate. I'm not understanding this part... The player can't get ahead of their own physics can they?
  11. I guess basically what I'm wondering is, if you're only updating physics 20 times per second, how do you keep it smooth? My game is in the twitch game catagory, requiring precision and low latency.
  12. Quote:Original post by shurcool Do you mean your client sends 60 commands per second? That seems pretty high. In my game, my command rate is 20, and the update rate is independent (but at the moment is also set to 20). By update rate, I mean how often the server sends out authoritative state updates to the clients. The server->client updates don't have to be in sequence, as it's ok to skip some and always send only the latest. As for the client commands, if you want to unlock the network sending from the physics tick rate, which I don't recommend doing, but it's possible by simply queueing up all the input commands since the last state that was authenticated by the server, and sending them all in one packet whatever times per second. By doing this, you're introducing extra artifical latency, so it's better just to send input commands to the server whenever you execute a physics update (i.e. as soon as one is avaliable). My client updates physics at about 60 times per second. I send network updates 30 times per second. The server replies to messages whenever they arrive. It doesn't send out updates at set intervals. I've basically got two different timesteps going at the same time. const float DELTA_TIME = 00.0166f; const float UPDATE_INTERVAL = .030F; while (AppStillIdle) { while (_updateAccumulator >= UPDATE_INTERVAL) { _updateAccumulator -= UPDATE_INTERVAL; ProcessInput(); SendNetworkMessage(); } while (_accumulator >= DELTA_TIME) { _accumulator -= DELTA_TIME; UpdatePhysics(); } Render() } The Input is locked with the Network rate while still letting the physics update faster. Quote:Original post by shurcool As for the client commands, if you want to unlock the network sending from the physics tick rate, which I don't recommend doing, but it's possible by simply queueing up all the input commands since the last state that was authenticated by the server I'm already decoupling the network sending from the physics update, but in a different way. I just slow the input down to match the network, instead of speeding it up by queueing until the next network send.
  13. Quote:Original post by oliii Could be many things. First you should try sending network ticks EVERY frame to simplify the problem and use a fixed timestep (which I think you do). One input update -> one character update -> one packet sent. But from where I stand, it looks like a timestep problem (or a mismatch of the number of updates performed for a given move sequence number). I'll probably restructure it that way for debug purposes, but as a final solution.. It's not a viable option to send messages 60 times per second. The server is going to have possibly hundreds of concurrent clients. Can someone give me a quick outline of how you could lock the local update rate (incl. input) to the required low network rate, and still the client update smoothly? I can't see a nice solution right off the top of my head.
  14. Quote:Original post by shurcool Ok, but can you explain what exactly you meant by #6 being wrong when the client is 5 moves ahead and replays all 5 of them correctly? I'll try to explain how I'm doing the updates here. (A side note first, I should have said in my first post. To reproduce the error, first hold down either left or right,(A or D) and press escape to force a message loss. It will lose one message only. To reset it, press spacebar. I usually have to keep losing messages for 15-20 seconds before it shows up. So hold down A/D and press escape then spacebar repeatedly.) The network update occurs at different intervals than the physics updating. This is because I don't want to send updates at as high a frequency as I'm updating local physics. I don't want to cap the local physics updating to the network update frequency either, because that would slow it down more than I'd like. As a result, I get a variable number of physics updates per network update. while (AppStillIdle) { double tempElapsed = HiResTimer.GetElapsedTime(); _accumulator += tempElapsed; _updateAccumulator += tempElapsed; while (_updateAccumulator >= UPDATE_INTERVAL) { _updateAccumulator -= UPDATE_INTERVAL; MoveState ms = = UpdateGame(); //The input is acquired in the UpdateGame method //The Replaying is also done in the UpdateGame() function ms.Timesteps = _timeSteps; ms.Velocity = _playerManager.LocalPlayer.Paddle.Body.LinearVelocity; ms.Position = _playerManager.LocalPlayer.Position; //Build the state and hand it to the network manager _networkManager.OutGoingState = ms; _moveHistory[CurrentHistoryIndex++] = ms; //store in circular history buffer } //This sends the update directly after it's been built, and before any more physics updates can occur. _networkManager.HeartBeat(); while (_accumulator >= DELTA_TIME) { _playerManager.LocalPlayer.LastPosition = _playerManager.LocalPlayer.Position; _playerManager.UpdatePhysics(DELTA_TIME); _accumulator -= DELTA_TIME; _timeSteps++; } Render() } This has the effect of introducing a constant lag equal to UPDATE_INTERVAL, because the input I just sent out has not taken effect. No physics updates have been calculated based on it yet. So we have to wait until the next round, at which time the number of updates we performed on it will be sent to the server, and then, a whole message later, the server can calculate the results of the last input and send it back. This has some implications in the Replay correction code, which I'll point out below. This is mostly pseudo-code for clarity. private void Correct(MoveState correctState) { Player.State = correctState; //Apply any input for this state. //Remember, this input here has not been calculated yet Player.ApplyInput(correctState.Input); //Set the timesteps back to the last correct state int timeSteps = correctState.Timesteps; //We have to replay all the way up to CurrentHistoryIndex while (i != CurrentHistoryIndex) { //Move to the next state i++; //Run the required number of physics updates for this state. //These updates are acting on the input from the LAST state. while (timeSteps < moveHistory[i].Timesteps) { _playerManager.UpdatePhysics(DELTA_TIME); timeSteps++; } //Apply any input for this state. Player.ApplyInput(correctState.Input); //Correct the position stored in the Move History moveHistory[i.Position = Player.Position; } //Run the remainder updates, this will bring us up to the current state. //Note that this is after all the moves in history have been corrected. //These are the updates that have happened on the last state, but have not been sent out yet. // while (timeSteps < _timeSteps) { _playerManager.UpdatePhysics(DELTA_TIME); timeSteps++; } /* This seems to be where the error is introduced. The moves in history are always corrected perfectly, but the the update that will be sent out next, using these remainder updates that we just calculated, that update will be wrong. */ } Here is some debug output that I've prettied up to make it more understandable. This is the error loop in action. Couple things to note, even though the error state is not always 1 digit ahead of the replay end state, it's still the next consecutive state. This is because there are sometimes 1, sometimes 2, physics updates per network update. Erroring on this state: 1130 *replaying* Replay end state: 1136 *normal network updating* Erroring on this state: 1137 *replaying* Replay end state: 1143 *normal network updating* Erroring on this state: 1145 *replaying* Replay end state: 1150 *normal network updating* Erroring on this state: 1152 *replaying* Replay end state: 1157 *normal network updating* Erroring on this state: 1159 *replaying* Replay end state: 1165 *normal network updating* Erroring on this state: 1166 *replaying* Replay end state: 1172 *normal network updating* Erroring on this state: 1174 *replaying* Replay end state: 1179 *normal network updating* So, taking the first two outputs from the above sequence, Erroring on this state: 1130 *replaying* Replay end state: 1136 //This is where the correction ended. It is the next one, (the one for which we ran the remainder updates) that is incorrect. *normal network updating* Erroring on this state: 1137 //This is the next one sent out after the replay, one with the corrected physics state. *replaying* Replay end state: 1143 *normal network updating* I hope this clarifies more than it muddifies. It's difficult to explain. Thanks for the replies. P.S. shurcool, I'm pretty sure it's nothing to do with threading; I haven't explicitly used multiple threads at all. Also, @fenghus, no, the latency doesn't change it. I've tested with more and less than 300ms, with the same results.