wheybags / freeablo

[ARCHIVED] Modern reimplementation of the Diablo 1 game engine
GNU General Public License v3.0
2.16k stars 195 forks source link

Base class for all game objects #478

Open grantramsay opened 4 years ago

grantramsay commented 4 years ago

Add a common abstract base class for all game objects: actors/items/doors/missiles/portals/stairs/chests/barrels etc, possibly even abstract things like traps/questTiles.

This base class should implement interfaces like:

Could even be extended to include things like:

This will help simplify interactions between game objects and maybe even tidy up the existing codebase a bit (e.g. consolidating existing actor/item/door/missile/stairs position maps).

Please comment with thoughts/ideas and anything I've missed or messed up.

Interesting wiki page with simple game objects discussing composition vs inheritance: https://en.wikipedia.org/wiki/Composition_over_inheritance

Original discussion: https://github.com/wheybags/freeablo/pull/475

Ultimately, it would be nice to have a common base class to both Actor and Missile, and a lot of the Actor logic could be moved into this base class (say, GameObject maybe). Then the constraint of no two Actors colliding becomes no two GameObjects colliding. Missile could be a subcless of GameObject, and there could also be a Portal subclass of GameObject (it doesn't really make sense for a portal to be a Missile).

Even with the town portal I felt it wasn't quite right. For example if you click a point directly on the other side of a portal you should get routed around it, currently you'll walk straight into it and get teleported. It should be using the "target" stuff already built in for items/actors/doors, but it's currently not that easy to do. Having a common base class (i.e. GameObject) with things like a "targetable" trait would make things much easier, and even help tidy up some of the existing codebase.

wheybags commented 4 years ago

This base class should implement interfaces like:

For now I would try to keep the inheritance tree as small as possible. GameObject can do nothing more than occupy a position (FAWorld::Position), and block it (or not, we can have a collision mask system eventually). It also gets an "update" virtual function that does nothing by default, and some sort of "draw" function, that also does nothing by default. Then Actor can keep doing all the stuff it does (including moving the position it inherits from GameObject), and Missile can do its own stuff too. Doors and Town portals could be some kind of "Activatable" object, and I think that would be enough? If we ever find we need to abstract out some particular bit of functionality, we could come back and do it then.

As for composition over inheritance, while I agree that it could be nice to introduce something like that (eg an entity component system), I think for this project its probably better to stick to what we already have. I've majorly refactored the codebase a few times now, if it's not 100% necessary I'd rather avoid doing that again and just finish the damn thing instead :p