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:
- The sprite hierarchy representing every type of sprite I can display.
- 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.