I am trying to figure out how to not break the SOLID principles with a collection of classes I am writing.

Currently, I have two stacks of classes that cater for editing and rendering Terrain and Paths.

Terrain -> TerrainChunk -> TerrainTile

Path -> PathChunk -> PathTile

The top level Terrain object exposes methods to add and remove Tiles which are then partitioned into Chunk objects forming part of a partitioned scene graph.

The Chunk objects themselves contain an array of Tiles and if something causes the tile or chunk to become dirty (terrain height is altered or a tile is added/removed) then the chunk “re-draws” itself which is as simple as looping through the tiles and calling Render().

The implementation of both the Terrain and Path stack of classes are largely the same (adding, removing, partitioning into chunks etc) with only the Render() method really doing anything different, i.e.: rendering a simple path or a single terrain tile.

I am quite happy with this setup so far which has proven to be extensible enough for my needs to date. This is working as expected and (surprisingly) I haven't butchered my code enough to worry about breaking any of the SOLID principles. Yet.

However, the need has arisen for the TerrainTile to know about the PathTile and also the PathTile needs to know about the TerrainTile.

The reason I believe this is true is that I would like to be able to “cut away” the terrain where the path is and also add “tunnels” to the path though the terrain. In order to do this, both terrain and path need to know about each other to determine where the terrain should be drawn or cut away and which paths should have "tunnels" added to them.

Ideally, I would like to implement something similar to this capture from Theme Parkitect although the principle is most likely the same in any other simulation game with terraforming.

Theme Parkitect

I’m not sure how to create the relationships between the two classes however without breaking at least 3 of the SOLID principles.

I could certainly go right at it and brute force this into my current implementation but that’s not very nice and would go against the lean and sane implementation I have strived for thus far.

Can anyone offer up any suggestions as to how I might inform one stack about the changes in another without introducing dependencies or hacking my code to pieces?

Perhaps I am barking up the wrong tree and the approach I have in mind isn't entirely suited for the job, in which case, are there any alternative options I could explore?

Note that I am not asking here about how to create either the terrain or the path tiles themselves but simply, how can I inform each of the appropriate parties of changes to each other without creating cyclical dependencies on each class.

If it matters, I am using Unity and C# but really this problem is both platform and language agnostic.

  • \$\begingroup\$ Based on the assumption you're using a modern language, I hope you implemented the methods using an abstract Tile and Chunk class \$\endgroup\$
    – Bálint
    Oct 26 '16 at 9:48
  • \$\begingroup\$ Yes. I did. The terrain and path classes are extended from Grid -> GridChunk -> GridTile which implements most of the base methods such as adding, removing and partitioning exposed as virtual methods to allow for extension. \$\endgroup\$
    – Zack Brown
    Oct 26 '16 at 9:57

When experiencing friction like this when trying to add a new use case to an existing design it's a sign that the abstraction is in the wrong place.

In this case I think that you need a new class that knows about both TerrainTile and PathTile, and can do the modifications needed. My reasoning is that only a class with higher access than at the lowest level can make the appropriate choices.

Yes, you can add the actual modification to methods in the lower classes but leave it to the new class to organize those calls.

Personally I would put this new class at the Terrain layer as a place to start. At this layer the new class will know about the tiles and paths and can orchestrate the changes.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .