Event Handlers and Decoupling

Started by
2 comments, last by ms291052 14 years, 10 months ago
I have a simple design question related to event handlers in my small bird's eye 2-D game. So far I have the following classes: Map - Manages the grid of tiles that represents a map. Object - Contains a position and string ID (e.g. "TreasureChest", "Goblin", or "Door"). Player - Derived from Object. Contains miscellaneous player-related data, such as inventory. World - Contains a map, a player, and a list of objects. I would like to allow the player to interact with objects by specifying an Object.Use() function. In the case of a treasure chest, the player would receive the treasure. In the case of the goblin, combat is initiated. In the case of a door, the world is changed to whatever is beyond the door. My question is where to define the Use() function. The obvious thing to do is to make Object and interface and implement it in classes for TreasureChest, Goblin, and Door, thus overloading the Use() function to do the appropriate action. The downside to this approach, however, is that a large number of small classes would be used, and this would force a lot of coupling. For example, the TreasureChest would have to know about the Player to modify his inventory and the Door class would have to know about the entire world to be able to change the map and Object list. An alternative solution is to store a function pointer in Object. As of now the function prototype is void EventHandler( Object Source, Object Sender, World World ). Then I can do this (pseudo-code):

static void PickUpHandlers::ItemPickUpHandler( Object Source, Object Sender, World World)
{
   Sender.Inventory.Add( Source );
   World.DeleteObject( Source );
}

void World::Load()
{
   // Load map data
   Object TreasureChest = new Object( X, Y, "TreasureChest", PickUpHandlers.ItemPickUpHandler );
}

void Input::UseButtonPressed()
{
   // Find target object based on player position:
   TargetObject.Use( TargetObject, Player, World );
}

Questions: - Is this approach reasonable? It certainly seems better than the first approach to me. - Where should the event handlers go? Static functions in an event-handler class seems clumsy. - Is there a better solution to this problem that I have overlooked? Thank you very much for your time and advice, ms
Advertisement
I think it's a little awkward and overengineered for this problem, but it's not totally unreasonable.

Where they go perhaps depends on how many of them there are per object type, if you're loading object configs from some external file, and so on. In the end, they're going to be a little clumsy.

You're worrying too much about coupling though. Are you ever going to use a Treasure Chest without your game's Object class? Without a Player? Just couple them if it makes the code easier/cleaner/more maintainable. I'm not saying make 1000 subclasses for each little thing because that's kinda dumb; you'll still likely end up with events to customize the behavior of various objects, but don't make your problems harder than they need to be.
I think this would be a great place to integrate a simple scripting language. Each object would have a script associated with it and the meat of the Use() function would live inside the scripts. The world and player would then expose themselves to the scripts so the object scripts could access them.
Actually, one of the goals of this project is to implement a scripting language into all of this. The question then is how do the player and world expose themselves to the script? Assuming they're not global, we run into many of the same problems.

I'm still quite interested into what the 'ideal' software engineering solution is. Similar problems come up from time to time, and I would like to have a solid foundation on which to continue.

This topic is closed to new replies.

Advertisement