Jump to content


Photo

Multi-Parenting in GM


  • Please log in to reply
10 replies to this topic

#1 gmx0

gmx0

    The Messenger

  • GMC Member
  • 1182 posts
  • Version:GM6

Posted 25 May 2012 - 07:04 PM

By default, Game Maker has a hiearchy(in contrast to a network or relational) structure for parenting, meaning that each object can only have one parent, and the "genealogy" or "family tree" of an object cannot loop.

The parenting system is powerful in and of itself. Each child can inherit the events of the parent, or overwrite it. When using instance distance or finding options for finding a parent object, each child is considered their own parent, instead of individuals.

But when you have masses of interacting objects, like in RTSes or sandbox games, multiple parenting would be nice for easier programming. Unfortunately, one must jump through hoops with GML to do so.

I've created somewhat of three basic structures/theories for multiple parenting:
3 Multi-Parenting Examples Source

(The file is in .gm6 :GM6: , but is compatible and can be converted in the newer versions of Game Maker :GM7: :GM8_new: )

So the three theories in summary:
1. Father/Mother
Each child object's primary, default parent is called the "father". A child can also have a secondary parent called the "mother". When a child executes events, it does so it executes the father's events first, then the mother's.

Pros: event handling is seamless
Cons: mother parent does not affect instance finding functions

2. Dual Object/Overlay
Each child has a primary parent, and also a secondary parent. It creates the secondary parent as an invisible overlay instance. This helps so that the instance finding functions can still find both somewhat seamlessly.

Pros: instance finding functions(howbeit modified)
Cons: event handling complicated between two objects, double the memory needed

3. Combined
Simply, combining both theories.

Pros: instance finding functions, event inheritance
Cons: event handling may conflict between the two objects, double memory needed

How would you do multiple parenting in GM? Or are there alternatives? Would you ever need to have multiple parenting?
  • 0

#2 GStick

GStick

    All Secrets Exposed

  • GMC Member
  • 1576 posts
  • Version:GM:Studio

Posted 25 May 2012 - 07:22 PM

I suppose it all depends on the final goal. What are you wanting to use multiple parents for?

  • It can't be methods - GM doesn't have those, and it's already possible to assign a script to any object.
  • If it's for events, then it sounds like none of the solutions described above solve the problem. One only allows for proper event inheritance from a single parent, and from your description the others just muck everything up.
  • If it's for variables - Well, they all seem to cover this base equally well, if they were a feature included directly in GM.

Here's a problem with the last one: GM doesn't have anything to distinguish private vs. public variables. So why are we able to directly interface with what we would normally want to be private variables once we inherit them? Shouldn't the parent be handling these?

Though if GM were to include private/public access and methods in the future, then I think I would rather have interfaces:
http://en.wikipedia....sed_programming
http://www.dotnetperls.com/interface

edit: There's also the issue that we want our child objects to be represented in code as the objects they inherit. If I can't locate an object that inherits from a mother, then there's minimal point in the inheritance.

Edited by GStick, 25 May 2012 - 07:25 PM.

  • 0

#3 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 342 posts
  • Version:GM:Studio

Posted 25 May 2012 - 07:40 PM

IMO the parent/grandparent hierarchy works well. If your program is so complex that multiple parents are needed, I think that it's cleaner and easier to just use scripts.
  • 0

#4 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16820 posts
  • Version:GM:Studio

Posted 25 May 2012 - 08:09 PM

In almost all my games I have multiple parents for my objects, and it normally follows a "tree" system...

So, at the top of the tree I have my deactivation parent. This has two children which are static and dynamic. Static has two more children which are solid and non-solid. On the other side I have the dynamic which has four children (sometimes more) : Player, Enemy, NPC, and Decoration. Each of those can also have multiple children. So, for example, an enemy instance can have three parent objects, with each one dealing with a particular thing (collisions, specific AI and general AI, deactivating, interaction etc etc...).

I find this approach to work VERY well and it has got to the point that at the start of every new game I prepare I automatically create the top two tiers!
  • 1

#5 Boreal

Boreal

    C++ Wackjob

  • GMC Member
  • 417 posts
  • Version:None

Posted 27 May 2012 - 08:25 PM

I think GM would benefit from a complete switch from inheritance to composition. Multiple inheritance is a terrible way to solve the problem of multiple code bases unless the user knows how to avoid the "diamond problem".
Posted Image

With composition, "objects" would become "components" and there would be a new resource type, "entities". Components could benefit from single inheritance but then you're only abstracting the problem. In my current game project (C#) I use a component-based system and it is fantastic (especially because I can take advantage of .Net's reflection :P). I can write components and then load entity configurations from files, then use arbitrary property/function names to access data or perform actions in a decoupled manner.
  • 0

#6 paul23

paul23

    GMC Member

  • Global Moderators
  • 3366 posts
  • Version:GM8

Posted 27 May 2012 - 11:30 PM

Multiple inheritance paradigm is a very hard to understand thing, and the gains are minimal over an interface & single inheritance tree approach. To the point that most languages don't allow this; The only language which I actually know this paradigm is allowed is C++, and even there I hardly ever used this (Well I did use the iostreams library but there parenting is hidden from the user).

The generic solution used in languages which don't allow multiple parenting this is to write "interfaces"; where the implementation of the method is only made "below" the multiple inheritance (potential diamond) in the graph.


Now taking this back to GM, is slightly different. As "parents" in GM are only a very simplified manner of inheritance. Just like "objects" in GM are very simplified version of classes in OOP. Events can be considered "methods". Now looking at the graph of above poster: what if an object "D" has no step event.. Yet both B & C have step events. Now what is executed?


Your solutions make things in first place "more complex" and probably also make the game semantically bad.


@ first suggestion
At first you should reconsider your graph & needs: If you really wish to execute both events in those cases there's also a perfect solution, like nocturne explained you should tree them up. IE: I have a airplane that IS_A vehicle which IS_A object. So in my inheritance graph I would create a airplane object which has as parent vehicle object. And this employee object has as parent a "object" object. Now in my airplane object I first call the vehicle's events before executing his own. Similare to the vehicle & object. (So execution isObject_Step -> Vehicle_Step -> Airplane_Step). Basically each object in the graph would "override" and "specify" the more generic layer above.


Now the only reason in which I ever can think of multiple "parenting" is when a certain class doesn't always derive from other classes. Taken above example: maybe you also wish airplane to derive from FlyingObjects. But not every FlyingObject IS_A vehicle. Nor IS_A vehicle a FlyingObject. So semantically the inheritance graph would be
Posted Image
Now what would happen if "airplane" create event was called, basically according to your explanation this would happen:
  • AirplaneEvent calls VehicleEvent
  • VehicleEvent calls ObjectEvent
  • ObjectEvent Executed
  • VehicleEvent Executed
  • AirplaneEvent calls FlyingObjectEvent
  • FlyingObjectEvent calls ObjectEvent
  • ObjectEvent Executed
  • FlyingObjectEvent Executed
  • AirplaneEvent Executed
Now looking at the list above shows a clash already: ObjectEvent is called twice, and one time after another event -that was supposed to overwrite it partly- was called.

Now there are once again solutions to this, like forcing the compiler to detect these, and then only let the main parent of a diamond be called once. Or by creating a "copy" from each parent - this would mean that Airplane::FlyingObject::Object::x is not the same as the variable Airplane::Vehicle::Object::x, but that would really change the way inheritance works in GM.



What I basically mean to show with this post is that multiple inheritance is not something trivial, it has numerous pitfalls. - And I doubt the gain is enough.
  • 1

#7 slayer 64

slayer 64

    GMC Member

  • GMC Member
  • 3278 posts
  • Version:GM8.1

Posted 28 May 2012 - 09:26 PM

i don't think everything needs to be a parent. sometimes it's better if it's a characteristic of an object. like solid and visible; isFlyingObject or isVehicle. then every combination can be set.
  • 0

#8 GStick

GStick

    All Secrets Exposed

  • GMC Member
  • 1576 posts
  • Version:GM:Studio

Posted 29 May 2012 - 06:27 AM

^The problem with that though is that even things that are only semi-related have that variable. A real life example: I had the variable _isSlope on block objects for the longest time. Eventually, things became related to blocks that had nothing to do with slopes. Needless to say I restructured it to make use of parenting better. So when the game wants a slope, it looks for a slope.

Your flying object thing could be a good call for interfaces? Lots of things fly but they all do it a bit differently...
  • 0

#9 gmx0

gmx0

    The Messenger

  • GMC Member
  • 1182 posts
  • Version:GM6

Posted 06 June 2012 - 01:42 AM

While characteristics of an object can be set using a variable, the limitation is that as follows:

Say you are making an RTS with player and enemy units.
Those units can be subdivided into ground and air units.

Now I can set a variable called "IsFlying".

But if I want to call all enemy units nearest to me that are flying for an anti-air attack, I can't use instance_nearest:
distance=range;
target=noone;
with obj_unit_enemy
{
if !IsFlying
continue;
var currentdist;
currentdist=point_distance(other.x,other.y,x,y);
 if currentdist>distance
 continue;
 else
 {
 distance=currentdist;
 target=id;
 }
}

Alternatively, I can make "obj_unit_enemy_flying". But another problem arises. What if I just want the nearest(either allied and enemy) flying unit to be found?

In any way, code gets more complex and slower. If there were multiple parents, I could use instance_nearest simply.
  • 0

#10 xshortguy

xshortguy

    GMC Member

  • Global Moderators
  • 4186 posts
  • Version:GM:Studio

Posted 06 June 2012 - 03:16 AM

Multiple inheritance is a rather fickle thing that should be avoided. Instead, I always found the idea of a mixin to be superior to a multiple inheritance structure. The Ruby language is an example of how this is done with the use of mixing in modules.
  • 0

#11 Boreal

Boreal

    C++ Wackjob

  • GMC Member
  • 417 posts
  • Version:None

Posted 09 June 2012 - 12:27 AM

Multiple inheritance is a rather fickle thing that should be avoided. Instead, I always found the idea of a mixin to be superior to a multiple inheritance structure. The Ruby language is an example of how this is done with the use of mixing in modules.

Except if you were to have interfaces, but that doesn't really help in a language like GML. I do prefer the mixin, or composition, solution. One of the major pros of composition is how easy it is to define entities at runtime. Of course, you also get into the problem with intercomponent communication, but I personally don't think it matters if the components can hold references to other components directly.

Edited by Boreal, 09 June 2012 - 12:28 AM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users