| Game Maker: The Power of Inheritance |
|
|
|
| Friday, 13 July 2007 | |
|
We tend to get a lot of questions of the “How do I do …?” variety, so this month we’re going to take a look at one of the often overlooked features of Game Maker that can be used in many different ways to solve a lot of common problems: Parenting
Inheritance and Parents
As we’ve said before, Game Maker is an object oriented system. One of the greatest benefits of object orientation in programming languages was the notion of inheritance. To put it simply: It is possible for objects to inherit actions and behaviours from other objects, the objects that are inherited from are called Parent objects and objects that do the inheriting are called Child objects.
You have just witnessed inheritance. In GM an object will perform the events and actions that its parent object has code for. But that’s not all that we can do with parenting, it’s an extremely useful method once you come to grips with it.
Object Hierarchies
As you’ve seen, an object will perform events that are specified on its Parent, but this only happens when the Child object does not have code in that event itself. For instance, when an object sets its speed in a creation event and its Parent sets the speed at creation in another direction, the Child object will only perform the code in its local create event and not move the same way as its Parent. Try it with our example above and see what happens… To get around this there’s a Perform Inherited Event action which will force the Child object to perform the actions that are specified by the same event on its Parent object.
This can lead to some interesting and efficient systems if you apply it in your games. For instance, if you want to have 5 or 6 enemies that all behave the same way and only look slightly different, it’s possible to create a base Enemy object with all the behaviours that you want enemies to have and then simply make a lot of “empty” objects with different sprites and set your Enemy object as their parent.
It is also possible to have different but similar behaviours inherited in this way. Imagine that you want to have a lot of different types of cars available for your player to drive, all with different accelerations, top speeds and handling characteristics. Instead of laboriously coding each car, it is possible to build a basic Car object which handles all the calculations that change the car’s current speed, turning angle and position, using the attributes you’d like to customise as variables. The trick is to set those variables in each Child car’s Creation event to give them different characteristics and rely on the Parent car’s Step event code to move the car properly.
Inheritance is a useful part of Parenting that can save you a lot of time and effort in your games, but there’s another, arguably more important side to using Parent objects that can have even more impact:
Polymorphism
This interesting-sounding word refers to how it’s possible in object oriented languages to refer to a child as though it was the same as a parent object. Confusing as that may initially sound, there’s a lot that this unlocks for us. Consider the case where you have many different types of enemies that can be hit by many different types of bullets. Without Parenting, you’d have to have collision events with each type of bullet on every enemy. Using inheritance it’s possible to have a base Enemy which does all the collisions with each type of bullet and the other enemies all inherit that behaviour, unfortunately you’d still have to code the collisions with every type of bullet…
However, let’s create a base object that all the bullets inherit from, called it Projectile for the sake of argument. Now it’s possible for our Enemy object to have only one collision event for collisions with Projectile and, because of polymorphism, every single child of Projectile will trigger that collision! We’ve just gone from many events on many objects, to many events on one object, to finally one event on one object. Talk about time-saving.
![]()
Of course it’s possible to use good object oriented programming techniques here to make each child of Projectile have a variable on it with the amount of damage it deals, then subtract that damage during the single collision event with Projectile. You can do a huge amount of different things with general code that uses variables with different values per child object.
This effect isn’t just available with collision events though, it can be used in every event, action or function call that asks for an object type. That means it’s possible to: find the nearest child of a parent object; use a with clause on an entire object hierarchy; test to see if a specific object is part of a hierarchy; keep track of total numbers of related objects for score or gameplay reasons; and many other useful things too, all with as little actual code as possible.
Things to look out for
While it is possible to create strings of Parent-Child relationships so that Projectile is the parent of Missile which is the parent of Homing Missile, Game Maker will not let you create loops in this way, so Homing Missile can’t be the parent of Projectile. It is also possible that sometimes inherited events may need to be triggered using the Perform Inherited Event action instead of relying on the normal inheritance system if the chain of parents gets too long. Polymorphism works no matter how long the chain of inheritance is though, so feel free to create as many “stub” parent objects as you need to make your life simpler.
In closing, Parenting gives you access to the powerful tools of inheritance and polymorphism, tools which can make your games much easier to build. It does take a certain type of thinking to solve game problems in an object oriented way, but with practise this becomes easier and easier. It’s also a great head start in the principles of OO programming.
Destroying an object from outside:
It is often necessary in a game for one object to destroy another, particularly when they collide or interact in other ways. In a collision event this is easy: Simply use the Destroy the instance action and make it apply to the special object other, which in a collision event points to the object was collided with.
In non-collision events this gets a little trickier as we don’t have the other object set to the right instance so we can’t change what the Destroy the instance action applies to… There is hope though: All you need to do is create an Execute a piece of code action and plug in this code:
with (deadObject) instance_destroy(); Assuming that deadObject is a variable that points to the object you want to destroy (which can be obtained from an instance_position() or similar function call), it will work perfectly.
|




