> simple, powerful, ubiquitous #Defold is a simple engine. It delivers what it promises: lightweight, portable, feature-full for 2D games. The most exciting and flagman feature of this engine is its messaging system. ## What’s the problem? One of the biggest problems in game development (and general software) is the number of connections between the systems. Writing a good system with even vague requirements is usually not so hard. The main complexity comes with inter-system interactions, especially in game development, due to the runtime nature of games. Some problems can appear for a glimpse of a second once in a while. In software development, we invented the term coupling to reflect how one system depends on other systems. The more direct connections, the more problems you can have and the harder it is to introduce changes. Overall complexity rises exponentially. ![[map.png]] The obvious way to handle this issue is to detach calls to the other systems from the callee. We need to introduce some other medium that handles communication but avoids hard referencing other modules. It can be implemented in many different [ways](https://www.gameprogrammingpatterns.com/decoupling-patterns.html). In Defold, the solution is its [Messaging System](https://defold.com/manuals/message-passing/). ![[messaging.gif]] The idea is simple: to avoid high coupling, we are forced to send messages between components, game objects, collections, and scripts. Addressing rules exist for different entities in code. Lua allows us to send a table as data with the message, thus simplifying the communication format. We don’t need to declare any additional structures and expose them for caller and callee. #Lua is 🔥 You need to implement a message-handling function on the receiver side, and voila. This system reminds me of Python, which forces you to use indentation instead of bracket pairs. The Messaging System forces you not to introduce more coupling than needed—no more keeping links to the object and verifying if it’s alive or not. In a nutshell, it looks like this: ```lua --send a message to the controller on the enemy game object msg.post("enemy#controller", "punch") ``` ```lua --function where the messages are handled function on_message(self, message_id, message, sender) if message_id == hash("punch") then self.health = self.health - 100 end end ``` ## Why is it good? The flexibility is amazing. You can send the message anywhere you want: to another script, another game object, another collection, etc. This works nicely. You don’t need to expose any methods, delegates, or events to another part of the project. Just establish a communication format and messages with data, and the deal is done. It achieves the goal of lowering coupling by default. This can be very useful for newbies in game development. At first, you always tie everything together. Chaotically and without any need. In my opinion, that’s a natural process: one needs to make mistakes to know why to avoid them. And the messaging system helps to prevent such mistakes at first. As I said, it’s similar to indentation in Python or Rust borrow-checker. With the messaging system, it’s easier to work in a team without the need to expose implementation details to another module. You can work on your part, and don’t be afraid the project will crash after you pull it. Of course, you can break everything anyway, but the system forces you to be less dependent on implementation details. Also, it’s worth mentioning that the refactoring process is more straightforward. You can inter-communicate with other systems only with messages, which are very localized in code. It allows you to refactor almost anything. The only requirement is not to break the contracts in messages and to adhere to the established message data format. ## Why is it bad? > In theory, the theory and practice are alike; in practice, they are different. Messaging looks very sweet, but I faced a few problems in practice. When you work with a few entities, the messaging feels slightly excessive, especially when the components are logically coupled. Of course, coupling is bad, but sometimes it’s not THAT bad. In addition, you can have better solutions that increase the quality of life, but the achieved coupling level doesn’t hurt the project. The following two problems are tied together. The first one is that it’s tough (at least for me) to understand how to get the correct destination address. You can send the message to the object without specifying the destination component. Every component and script receives the message. However, I almost always fail to get the address needed for a game object from the first attempt. The only help here is a URL property in the editor, but it doesn’t help with dynamic objects though. ![[properties.png]] The second problem is debugability. I can’t get all the objects’ addresses via a debug window during play. This information could help me (or others) understand how the URLs are built for all interactions. Also, I don’t have any information on who received my message. Maybe some additional debug information about message statistics would help: how many empty messages were sent, which component is the hottest one, etc. It’s all needed for debugging purposes. The last problem that causes me pain is sending the message to another collection created with collection [[GameObject vs. Collection vs. Factory vs. Proxy|proxies]]. The addressing logic that worked for one collection stopped working in this case. I think it’s tied to the fact that a collection proxy creates a new world. If I want to decompose the current collection into a logical one, I have to rewrite the working code. On the one hand, refactoring is easy code-wise, but refactoring data-wise is more complicated, especially for hard-coded addresses. ## Instead of conclusion I think forced messaging is a good general approach to reduce coupling in games using Defold. However, the nature of many systems and entities in game development dictates many more natural ways of inter-communication. In this case, we can implement such interactions with the message system anyway, but the overhead is more significant than the gain from less coupling. Also, the system itself requires more debugging to ease the adaptation of the approach. To provide ways to reduce hardcoding of the addresses. I hope some issues are resolved in the future, but overall, messaging has many more positives.