GML Should Objects Push or Pull Data?

samspade

Member
Here is the scenario. I have a bunch of objects - locks, keys, doors, buttons, combo locks, levers and so on. These objects need to interact with each other. Doors and locks interact, levers and doors or locks interact, combo locks interact with their individual buttons, and so on. They connections can be arbitrarily deep or complex.

Here is the question. Should objects only pull data from objects, only push data to objects, or a mix of both?

In other words. Let's say a Lever is attached to Lock A and Lock B. Lock A is attached to Door A, and Lock B is attached to Door B. If Lever is in position 0, Lock B is locked, but Lock A is unlocked and Door A can be opened. If Lever is in position 1, Lock A is locked, but Lock B is Unlocked, and Door B can be Opened.

So I interact with Lever. Should Lever A push its data to Lock A, which then pushes it data to Lock B. Or should Lever just send out a note that an update is needed, and then Lock A checks, Lever A, and Door A checks Lock A?

What are the pros and cons of each? Right now I have it as a mix of both mostly as an artifact of creation. Occasionally, this results in me forgetting which way data goes and messing things up.

To generalize the question, if you have a complicated system of data where a bunch of things all connected to each other and their states rely on the states of the things they are connected to such that changing one state could cause a cascading effect, how would you handle that cascade of changes?
 
I

immortalx

Guest
I don't know if there are "proved" good patterns about this, but I'd think that each object should mind its own business as much as possible.
So the sequence of actions in a real life lever-lock-door scenario, is that the lever is pushed and the lock is forced unlocked. When the lock is unlocked, the door is forced open.
The level has to know only if it's in position 0 or 1 (state). It has to unlock or lock a lock (action from change of state)
The lock has to only know if is locked or not (state). It has to open or close a door (action from change of state)
Thee door has to only know if its open or not( state)

I might be entirely wrong of course...
 

FrostyCat

Redemption Seeker
The proven pattern is the Observer pattern from standard OOP.
  • Subjects should keep a list of subscribed listeners and freely allow additions.
  • The subject should notify listeners when it has changed.
  • The listeners should pull pertinent data from the subject and act accordingly when notified.
This can be implemented as simply as a list on the subject side and a single user event on the listener side, but you're free to formalize this however you like once the basic groundwork is established.

The fact that you're talking about specific instances of Lever, Lock and Door, when the implementation happens at an object level, already suggests a problem with excessive/inappropriate coupling. It's a common issue with code written by designers, because their main concerns are specific, concrete implementations (e.g. design of a specific level or UI) instead of general-case, abstract implementations (e.g. reusable level/UI components). Out of the virtue of their work, they often end up blind to all but their most immediate visual needs. Unfortunately, given how virtually all educational material for GM these days is written by designers and not dedicated coders, excessive/inappropriate coupling and the general tendency to write unreusable code have become problems common to most of the GM user community at large.
 

GMWolf

aka fel666
In general I like my objects to act as services to other objects. With data being pulled up.

But pushing data down can also be useful. Like with an actor-action pattern (where the action pushes data into the actor)
 

samspade

Member
Currently, my method is a mix between these two. Which is part of the problem. For example, right now locks are 'passive' - they never push or pull. Information is pushed into them (e.g. through a key, or a lever, or something else) or pulled from them (e.g. a door). But this mix can be confusing. For example, when I have a lock which is composed of locks should it push or pull, which lock breaks the pattern and pushes? Everything pulling (when notified) seems to make the most sense.

As a side note, it's not actually objects or instances of objects. That was just for ease of explanation. 'objects' or 'instances of objects' are data in a map where each 'instance' is stored by name (string) and contain a set of variables and scripts which act as their data and logic. Everything is a map because I need persistence across multiple rooms, need to save everything, and just in general it makes debugging a little easier as my 'puzzle objects' are named, all in one place regardless of what other instances are in the room, and don't have dozens of extraneous variables to sift through. All communication between objects is essentially done by name. There's no difference between locks except the name or doors except for their name and the name of their lock, and any door can be attached to any lock (or no lock) by changing the name of the lock it would look up in the map, and so on.
 
Top