0
\$\begingroup\$

at the moment I'm writing a game server, so I made an event "handler". I mean, if a player send to the server "I move" it fire a function, so I think I'm doing well at the moment.

But there's a problem and I don't know how to handle it. Lets take an example.

When a player want to attack he need to press a key one time, and it will attack automaticly every second, that means the server receive one packet with "I attack" and the server handle it, But I don't know how to make the player attacking every second correctly. It's kinda hard to explain I'm sorry ! So what I'm doing at the moment is, if the server receive from the player "I attack" I start a timer for the player which call a function every second. And I do that for every player but, I think that is not a nice idea. Should it be better to make one big timer ? If yes, which interval should I use ? 100ms or more ?

Well I hope you understood me, I know I didn't explain it well and sorry for that ! Thanks in advance for your help.

\$\endgroup\$
1
\$\begingroup\$

It sounds like you are using some kind of callback system to handle incoming messages. This is entirely reasonable but it does not obviate the need for a game loop. In fact, "one big timer" idea is basically exactly the same as a game loop. A typical client might have a loop like:

while(!exited()) {
    handleInput();
    sendReceiveNetworkMessages();
    updateGameObjects();
    render();
    window->flipBuffers();
}

In a client, you want to run as fast as possible. If V-sync is enabled, then flipBuffers() will block and prevent the loop from running too quickly. That is why we don't use timers typically for game loops, because we need it to start over immediately to write the next frame. On a server, this might look like:

while(!done()) {
    time start = now();
    sendReceiveNetworkMessages();
    updateGameObjects();
    waitUntilTime(start + 100ms);
}

There is much less work to do, because we don't need to render the game world. But we still need to run the game logic, create and destroy entities, damage players, handle logins, etc. The architecture you describe as using seems to be based on reaction to network messages. When a player requests to attack, they kick off a timer that repeatedly attacks. This is putting the state of a player (i.e. whether they are "continuously attacking") into the timer manager. While it might seem simple to code, this is likely not a good idea because it requires extra code to handle cancelling the timer, etc. It is cleanest to store this state as explicitly as possible, as opposed to implicitly in the presence or absence of a timer.

You probably have a Player object on the server for each connected player. They would have a boolean field isAttacking, and a time field lastAttack. Then during object update, if lastAttack + 1sec < stepStart + stepDuration, we say the player can attack that step. Then crucially we update lastAttack = laterOf(lastAttack + 1sec, stepStart). Why not just say lastAttack = stepStart? Because we want the player to attack once a second, and otherwise depending on how our steps actually line up with the 1 second interval, we might be off by 100ms, which wouldn't be fair to multiple players. On a client this usually is ignored because a frame is 16 or 30ms, so the error there is negligible.

Now the response to the network message is just to set or clear the isAttacking flag in the player. Thus the architecture is driven by the game loop, rather than in response to messages. The laterOf function ensures that we don't need to worry about the lastAttack time being in the far past if the player stops attacking, then later starts up again. If we didn't do this, they would attack every frame until we had added enough 1sec intervals to catch up!

Note that timers provided by the language or OS are probably expensive. A small constant number is fine, but one for every player will not scale to many users.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.