First-Person-Player Input-Handling

Hi everyone :grinning:

My friend and I are currently working on a Low-Poly 3D-Survival Game. So far we are able to randomly generate a island with a 3D-Person Player being able to walk around with items in his hands (like in Minecraft :smile:).

Now we are facing two design decisions:
First of all, should player-controls (e.g. FirstPersonControl which extends BetterCahracterControl) handle input by themselves or should they just provide an interface for a suited input controller. This pseudo-code should clarify that:

FirstPersonControl fpc = player.getControl(FirstPersonControl.class);
FirstPersonInputController fpic = new FirstPersonInputController(fpc);
inputManager.addListener(fpic, KEYS_TO_LISTEN_FOR);

/* In FirstPersonController.class */
public void onAction(String name, boolean isPressed, float tpf) {
    if(name.equals(Input.ACTION_PLAYER_MOVING_LEFT)){
        firstPersonControl.setMovingLeft(isPressed);
    }
    //...other input 
}

/* In FirstPersonControl.class */
   public void setMovingLeft(boolean pressed) {
            movingLeft = pressed;
   } 
  //... other methods concerning movement

Or should the control itself be responsible for input handling, e.g. the FirstPersonControl implements ActionListener and therefore handles input directly.

As this post got quite long I´ll post the other question I have in a seperate thread.

Thanks in advance :grinning:

In my opinion, input should be handled by app states since input is global and app states are global.

But how would I go about updating the player controls then? Would the AppState call those interface methods of the player controls?

Yes, the app state would have to know which control you are controlling at that particular point.

I mean, in a “proper” design, input changes game objects and the controls are then used to reflect the state of the game objects in the scene graph. JME half encourages treating spatials as game objects but it usually causes problems later.

In this case, if you are going that route then the app state would need to know what to apply the current movement state/forces to.

And you could use something like observer pattern, event bus, notifications, whatever.

Thanks for the fast answers :grinning:
So basically I could every control that relies on input have implement ActionListener or/and AnalogListener and then in the AppState I could call those methods for every control added to that state.

/* In the AppState */
   public void onAction(String name, boolean isPressed, float tpf) {
        for(ActionListener a : actionListeners) {
             a.onAction(name, isPressed, tpf);
       }
    }

 public void addActionListener(ActionListener actionListener) {
   actionListeners.add(actionListener);
 }

Or would be the method by calling the concret controls interface methods (e.g. moveLeft(), moveRight(), rotate(angle), …) be better? That way I wouldn´t need to process all inputListeners when an input occurs and the control wouldn´t have to know about the concrete input actions (like “PlayerMoveLeft”, “PlayerRotate”, …) and therefore only provide some methods for chaning its state.

Or am I totally wrong with my ideas? :sweat_smile:

Thanks in advance :grinning:

There is really no use having an additional layer unless it is providing an abstraction. Frankly, there is almost no reason to have a custom control at all once the app state is handling input. It can just manipulate the forces of the control directly. Which makes sense since the Spatial and its controls are like a text field on a GUI (just a visual element). You don’t have the text field have its own database connection, for example.

Either way, simply passing through the events is the wrong idea in general.

Ahh thanks a lot, the example with the textfield made things clear now :sweat_smile:
So nothing wrong with having the concrete classes like FirstPersonControl in the PlayerInputState if I got things right?