Architectural design for clean code/solid communication between GameObject components.

Started by
2 comments, last by werekarg 4 years, 3 months ago

Hey folks!
I'm trying to make games in TypeScript, and although I could probably make alot of small simple games withoout worrying about this, I have a desire to achieve skills in the architectural part as well. I'm a software developer in my day job (still fairly new to the craft though), and I strive to follow the SOLID principles for object oriented design, as well as generally trying to achieve best practices.

I'm however a bit stuck. I'm trying to figure out how the communication between different part of the engine should work, without trowing unnecesary data objects all around my code, and making every single data object public.

I'm thinking some sort of event system, but I can't figure out a good way to do it.

My GameObjects have components, which I think should be the building block of beavior. But as an example in my code, I want the MoveComponent to tell the CollisionDetector each time it's owner moves, so that the CollisionDetector can do it's job, and in case of collisions tell the components which care for it (in my example the BounceComponent of the same GameObject), that it happened.

So to my ears that sounds like an observer pattern, but is that a good way of doing this? Is there some other obvious way of structuring your game that I'm not aware of?

Link in case you are curious:
https://github.com/TcMikjaer/TypeGame

Thanks for your time.

Advertisement

Hi there.

There's always different ways to do the same thing and pretty often you'll realize that none of them is the perfect solution. The important thing is to choose how you want your components to communicate and stick to that decision throughout the whole project.

Long ago I wrote my own entity system and had the same doubts. I started doing it the “right” way where all communications between components were made through messages. It made the whole system to be slow, hard to debug and unmanageable. Then I decided that I'd use an hybrid approach where I'd use the best real-life solution for each scenario.

You need to understand that components can be of different kinds. Some are designed to work on their own, some are designed to work together and can't never be separated, some are designed to work as a service for other components, some are specifically made to execute a specific task and others are made to act as an interface to the rest of the components in the same entity. Well the list goes on, so it doesn't really make sense to make them all work the same way.

So, in the example you provided, your entity will have these components:

  • TransformComponent
  • MoveComponent
  • CollisionDetectorComponent
  • BounceComponent

The TransformComponent does nothing, it just exists so the entity has a place to be.

The MoveComponent will probably be aware of the input and just need to tell the transform component to update accordingly.

The CollisionDectector actually needs to know if the entity has moved, so it can detect it on his own asking the TransformComponent for the current position and comparing it with the latest one. Making the MoveComponent to notify directly the CollisionDetectorComponent that it moved is a bad idea, since an entity could also be moved by an external force, and you'll also be introducing an unnecessary dependency to the MoveComponent, but this depends entirely on the type of game you're creating so, if you still want a component to notify something do it with a message or maybe use a blackboard.

Finally, the BounceComponent works pretty much the same as the collision detector. It'd be either waiting for a collision notification or actively polling the blackboard looking for a collision.

Hope this helps.

cocos creator, which has a similar node-component system, uses events to communicate between components of the same node. for all intents and purposes, it works well.

i'm using signals (https://www.npmjs.com/package/@robotlegsjs/signals) and ioc/di (https://www.npmjs.com/package/inversify) to implement something akin to robotlegs structure (model - service - mediator - command). i'm thus using signals to communicate between components of the same node (but, sometimes, i do rely on events for this), components of different nodes and to propagate notifications between models and components (something changes in a model, and one or multiple components need to observe the change - score changes in a model and a component that observes the score needs to update a label, for instance).

This topic is closed to new replies.

Advertisement