I'm writing a game that has many components. Many of these are dependent upon one another. When creating them, I often get into catch-22 situations like "WorldState
's constructor requires a PathPlanner
, but PathPlanner
's constructor requires WorldState
."
Originally, this was less of a problem, because references to everything needed were kept around in GameEngine
, and GameEngine
was passed around to everything. But I didn't like the feel of that, because it felt like we were giving too much access to different components, making it harder to enforce boundaries.
Here is the problematic code:
/// <summary>
/// Constructor to create a new instance of our game.
/// </summary>
public GameEngine()
{
graphics = new GraphicsDeviceManager(this);
Components.Add(new GamerServicesComponent(this));
//Sets dimensions of the game window
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
IsMouseVisible = true;
screenManager = new ScreenManager(this);
//Adds ScreenManager as a component, making all of its calls done automatically
Components.Add(screenManager);
// Tell the program to load all files relative to the "Content" directory.
Assets = new CachedContentLoader(this, "Content");
inputReader = new UserInputReader(Constants.DEFAULT_KEY_MAPPING);
collisionRecorder = new CollisionRecorder();
WorldState = new WorldState(new ReadWriteXML(), Constants.CONFIG_URI, this, contactReporter);
worldQueryUtils = new WorldQueryUtils(worldQuery, WorldState.PhysicsWorld);
ContactReporter contactReporter = new ContactReporter(collisionRecorder, worldQuery, worldQueryUtils);
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
pathPlanner = new PathPlanner(this, worldQueryUtils, WorldQuery);
gameObjectManager.PathPlanner = pathPlanner;
combatEngine = new CombatEngine(worldQuery, new Random());
}
Here is an excerpt of the above that's problematic:
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
I hope that no one ever forgets that setting of gameObjectManager.WorldQueryEngine
, or else it will fail. Here is the problem: gameObjectManager
needs a WorldQuery
, and WorldQuery
needs a property of gameObjectManager
.
And, aside from that issue, it's a maintainability mess, because if the constructors aren't called in a specific order, the program will crash.
What can I do about this? Have I found an anti-pattern?