Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have an input pipeline that stores InputObjects into a queue, which I then iterate through once every frame.

while(!inputQueue.isEmpty())
{
    InputObject inp = inputQueue.pop();

    boolean handled = false;
    for(Entity entity : inputRecievingEntities)
    {
          //entity.manage() returns true if it wants to consume the event, false otherwise
          handled = entity.manage(input);
          if(handled)
               break;
    }
}

This works fine to make sure the input is handled by only one entity. However, consider this situation:

There is a button overlaying the screen. The user can either click the button to jump or press anywhere (else) on the screen to shoot in that direction (which is handled by the player entity). If the player entity happens to be before the button entity in the inputReceivingEntities list, the player will shoot and not jump. If the button is before the player, the player will jump, and not shoot (which would be correct). Obviously I could assign some sort of priorities to the objects and sort the list but is there a better way to do this?

share|improve this question

2 Answers 2

up vote 2 down vote accepted

In your example, isn't the reason why the button press should take precedence simply because the button is on top?

So you don't really need to assign priorities, or sort your list, as you already have such an order in place somewhere else - the draw order. Just handle mouse events in the inverse order that you're drawing your entities.

For example, in my 2D engine I have entities placed on a display list, which is divided into layers and sorted in draw order. Then my input manager gets a list of all entities from my display list (but only the ones I mark as Interactive) and events are handled front to back, top layer to bottom layer.

At the bottom of everything, if nothing else handled the event, I also have a class called Stage which exists simply to handle events that were not consumed by entities (such as clicking outside of all entities).

Entities consume events by default, but if one them should be non-blocking, I simply return a different value from the event handler like you're doing (which is a design pattern called chain of responsibility by the way).


Can you further explain the display list? Or should I ask another question about it?

Sure. But bear in mind that this just my personal solution to a specific problem. Feel free to take from it anything that might be useful to you, but with a grain of salt; each project is different, and this solution just happened to fit well with my needs. It won't fit every project, and I don't claim it to be the best way or anything.

My display list is made up of two separate parts:

  1. The sprite hierarchy representing every type of sprite I can display.
  2. The display list (which I call the stage) which groups and manages my sprites.

Here's a basic overview of this system, in some C# inspired pseudocode mostly:

Part 1: The Sprite Hierarchy

class Sprite
{
    mixed Position, Rotation, Scale, Origin
    bool Visible, Interactive
    bool IsInside(x,y);
    void Update();
    void Draw();
}

class ImageSprite : Sprite {}
class TextSprite : Sprite {}
class PolygonSprite : Sprite {}
class CompositeSprite : Sprite { List<Sprite> Children; }
class AnimatedSprite : Sprite { List<CompositeSprite> Frames; }

Part 2: The Display List

class Stage
{
    List<Layer> Layers;
    Camera Camera;

    List<Sprite> GetSpritesAt(x,y);
    void HandleInput();
    void Update();
    void Draw();

    event StageMouseDown, StageMouseUp, SpriteMouseEnter, SpriteMouseLeave;
    event SpriteMouseDown, SpriteMouseUp, SpriteMouseClick, SpriteMouseMove;
}

class Camera {}

class Layer
{
    CompositeSprite Root;

    void Add(sprite);
    void Update();
    void Draw();
    List<Sprite> GetSpritesAt(x,y);
}

And the only part relevant to your initial question lies on the Stage.HandleInput method. It goes roughly like:

void HandleInput()
{
   // Note: GetSpritesAt already returns sprites ordered by the drawing order
   List<Sprite> sprites = GetSpritesAt(mousePosition);

   // Handle input starting from the topmost sprite on the topmost layer
   // Trigger events along the way
}

Example:

Here's an example of how I use it:

Stage stage = new Stage(2 /* Number of Layers */);
stage.SpriteMouseClick += sprite => Diagnostics.Debug.WriteLine(sprite.Id + " clicked!");

stage.Layers[0].Add(new ImageSprite(texture1){Position=new Vector2(300, 300)});
stage.Layers[0].Add(new ImageSprite(texture2){Position=new Vector2(200, 200)});
stage.Layers[1].Add(new TextSprite("Message text"){Position=new Vector2(100, 100)});

stage.HandleInput();
stage.Update();
stage.Draw();

That's pretty much all I need to create my scene and add interaction and events on my sprites.

share|improve this answer
    
As he described the problems I think he wants the button to always handle the input and the top NPC/Player. Reversing the order would still causes one to be blocked. –  ClassicThunder Dec 20 '11 at 22:49
    
Quoting the OP: If the button is before the player, the player will jump, and not shoot (which would be correct) So he clearly wants to block after the button press. He's asking how to manage the order. –  David Gouveia Dec 20 '11 at 22:54
    
Can you further explain the display list? Or should I ask another question about it? –  you786 Dec 20 '11 at 23:45
    
@yaj786 Sure, I'll just edit a new section into my post. –  David Gouveia Dec 20 '11 at 23:50

I would define input types and make your entities handle different input types differently.

So you would derive PlayerInput and ButtonInput from InputObject. Derive PlayerEntity and ButtonEntity from Entity (if you haven't already).

Then your manage function can be different for each entity type, and handle input from each input type in the correct manner.

This might be slightly over engineered, but it allows you to have entities that handle more than one type, as well as allowing different entities to handle different input types in diverse ways.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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