2
\$\begingroup\$

I'm having trouble wrapping my head around a method to compartmentalize my game control scheme within the game loop in an efficient way. Currently this is basically how my control works in bad pseudocode / JavaScript. I think this type of scheme is pretty standard for simple games..

Init() {

    function onKeyDown( event ) {
        switch( event.code ) {
            case 'KeyA':
                moveLeft = true;
            case 'KeyD':
                moveRight = true;
            etc...
    }

    document.addEventListener( 'keydown', onKeyDown, false );

}

GameLoop() {

    CheckControls();
    MoveWorldObjects();
    Render(); 

}

CheckControls() {

    if ( moveLeft ) velocity.x -= 10;
    if ( moveRight ) velocity.x += 10;
    etc...

}

This method has worked fine for me so far, especially since the eventListening is abstracted, and relatively quick for what I need it to do. However, as my game gets bigger the controls are starting to look very disorganized and I'm starting to wonder if this is a good program flow for a larger game.

Another problem is the fact that there are multiple control schemes in the game, so different characters will use different keys to activate different skills. It made sense to me to try loading different schemes at run time from JSON files, but I can't wrap my head around how I would do event handling from JSON, because I can only store values/gameStates, which I am already doing. Adding a JSON layer to the controls doesn't seem like it would help me at this point.

Is there an approach to organizing game control that I should read about? Or is it a good idea to keep all of the control responses very close to the game loop and simply try to work around that limitation. Or perhaps there is a way to separate basic controls (like movement) from more advanced/less high-speed responses like pulling up a UI?

Thanks in advance for any help! -G

\$\endgroup\$
2
\$\begingroup\$

This is the keyboard input method that I have been using in javascript.

First define the keyboard function, which I have shamelessly copied from somewhere (I'm honestly not who the original author was but it appears on StackOverflow a few times).

function keyboard(keyCode) {
    var key = {};
    key.code = keyCode;
    key.isDown = false;
    key.isUp = true;
    key.press = undefined;
    key.release = undefined;
    //The `downHandler`
    key.downHandler = function(event) {
        if (event.keyCode === key.code) {
            if (key.isUp && key.press) key.press();
            key.isDown = true;
            key.isUp = false;
        }
        event.preventDefault();
    };

    //The `upHandler`
    key.upHandler = function(event) {
        if (event.keyCode === key.code) {
            if (key.isDown && key.release) key.release();
            key.isDown = false;
            key.isUp = true;
        }
        event.preventDefault();
    };

    //Attach event listeners
    window.addEventListener(
                            "keydown", key.downHandler.bind(key), false
                            );
    window.addEventListener(
                            "keyup", key.upHandler.bind(key), false
                            );
    return key;
}

This bit of copy-and-past code gets hidden away, but now it allows us to do definitions like this, which used the keycode to define variables of keys.

 var left = keyboard(37),
     up = keyboard(38),
     right = keyboard(39),
     down = keyboard(40);

Now we add event functions to each key for press and release.

left.press = function() {
    movingLeft = true;
};

left.release = function() {
    movingLeft = false;
};

I would not advise to execute game code in the callbacks, but leave it in the main event loop. You can shift all of your input logic to these functions, though. For example, I am setting a flag above and then I will check that flag in the main loop. I am not trying to add velocity or do any game logic in the event.

This stays in the game loop

if ( movingLeft ) velocity.x -= 10;
if ( movingRight ) velocity.x += 10;
etc...
\$\endgroup\$
  • \$\begingroup\$ This is great, and I like the ability to abstract arbitrary controls to specific functions, that's exactly what I need to do. However, one question. You've essentially replaced a single callback with a multitude of callbacks/eventHandlers that all seem to respond to the same event. Is this true? Will every downHandler be called for each keypress? I'm worried that the abstraction adds fat to the event handling, which already feels clunky due to the large switch function. \$\endgroup\$ – Gavin Jan 22 '18 at 2:57
  • \$\begingroup\$ @Gavin Yes, every instance will listen to all window keydown and keyup events \$\endgroup\$ – Jay Jan 22 '18 at 3:09
  • \$\begingroup\$ I think I can work with that. Thanks for the help. \$\endgroup\$ – Gavin Jan 22 '18 at 3:21

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.