0
\$\begingroup\$

In Unity3D how do I manage input among many components, especially in relation to "blocking" input messages to certain components?

To make my question clear, an example:

Component 1: Input Manager

Manages a list of components that require input. They do this via a Register method, which adds the component to a List. Each registered component can poll input via this method:

public static bool GetKeyUpAndActive(KeyCode keyCode, MonoBehaviour entity) {
    return Input.GetKeyUp(keyCode) && List.Contains(entity);
}

This feels clunky, as each entity needs to pass itself to the manager, and the manager has to keep a list of registered input events.

Component 2: Script Manager

Manages scripts such as "Open Dialogue Box, say "Hello", play SFX, add Item x to inventory. Script manager responds to input, for example, if over component, and Input.Action is pressed, run this script.

Component 3: Dialogue Manager

Manages the dialogue box, pretty stock standard stuff. It also responds to input, pressing Input.Action will cycle through the dialogue boxes, until it reaches the end, then returns back to the game.

The main issue I am facing is that the script manager and the dialogue manager are responding to the Input.Action during their own updates. So Script 001 responds to Input.Action which triggers an open dialogue box, but because dialogue manager also responds, it has already cycled through to the next dialogue box.

I think the Input Manager is breaking encapsulation. I also feel like I'm missing an obvious component here, maybe I need a stronger subscriber pattern to follow, or should there be a separate state manager, and if so, should the input manager only send events/provide methods to components in the correct state, or should components check the state machine themselves?

\$\endgroup\$
6
  • \$\begingroup\$ minor terminology nit: "entity component system framework, such as Unity3D" Unity3D is certainly component-based but hardly fits any of the usual definitions for an entity-component system or an entity-system architecture (it lacks the "system" part in that its components are just a bag of things attached to a game object, each with Update methods and the like of their own). \$\endgroup\$ Nov 17, 2013 at 5:01
  • \$\begingroup\$ Agreeing with @SeanMiddleditch here, you may want to step back for a bit and research various Entity Component System designs since you're off track in how they fit together. Danger sign #1 is that you think that Unity is an ECS. \$\endgroup\$ Nov 17, 2013 at 5:46
  • \$\begingroup\$ I see what you're saying, but I wouldn't really say I'm off track, I understand the advantages it brings to the table especially when it comes to composition over inheritance. Unity3D might not realise every part of a ECS, but Unity is most aligned to that particular system, more so than MVC or similar. Wikipedia states itself that Unity3D and jMonkey are using the ECS pattern. \$\endgroup\$
    – Chris
    Nov 17, 2013 at 6:18
  • \$\begingroup\$ @Chris: again, a relatively minor nit, but the problem is that component-based design is its own thing and not all component-based architectures are ECS (ECS is a specific subset of all possible component-based designs). Yes, Unity is a component-based design but it's just flat out wrong to call it an ECS. You might want to change the title to clearly state this is about Unity and its branch of component than ECS since useful answers to your question will necessarily be very Unity-specific and you're more likely to get the right people to see and answer if you're clearer in your question. \$\endgroup\$ Nov 17, 2013 at 6:23
  • \$\begingroup\$ @Chris: in our field the terminology and accuracy in its usage comes in handy when Googling things or trying to attract the right people to a question. Just trying to help. :) \$\endgroup\$ Nov 17, 2013 at 6:26

1 Answer 1

3
\$\begingroup\$

Hey I will try to give you a starting point. Your problem of handling the input in more than one method could be solved by creating your own small messaging system:

  • Create a class InputMessage, this class contains the original Input action and a bool handled.

  • Your Input handler is the only class to access the original Unity Input, whenever a input occurs it generates a new InputMessage, encapsuling the original action.

  • Components can register to the input manager (just like you already handle it), maybe with the extend to provide a priority, indicating how 'early' it should be processed.

  • When a new InputMessage is created the input manager pass it to every component in the list, into a function InputMessage TakeInput(InputMessage im)

  • This function will handle input logic nd then return the original message, or an altered one, this new message is then passed to the next component, unless it got handled set to true

So in your problem you would just set handled to true in the script manager and return the message. Your InputManager would see this and break the loop. You could even use this system to change input messages in your components, if you ever need to do so.

Logic in InputManager could look somehow like this:

InputMessage im=new InputMessage(originalAction,false);
foreach(InputComponent ic in list){
  im=ic.TakeInput(im);
  if(im.Handled)
    break;
}

InputComponent would we an interface or abstract class adding the Takeinput function to your class signature.

Hope this gets you started, feel free to comment, if you got any questions

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .