As a GameMaker project grows, repeating the same code becomes difficult to manage. You may have five enemy objects that all need health, contact damage, death effects, and collision behaviour.
Copying those systems into every enemy might work at first, but one small change would then need to be repeated across several objects. Parent objects offer a cleaner solution.
A parent can hold shared events, variables, and general behaviour, while child objects inherit those features and keep their own sprites, values, and specialised mechanics.
Learning how to use parent objects effectively can make a GameMaker project easier to expand and debug. They are especially useful for grouping enemies, hazards, collectibles, interactable objects, and other assets that share a common purpose.
However, inheritance can also become confusing when hierarchies are too deep or child events accidentally replace important parent code. This guide explains how GameMaker parent objects work, when to use them, how to override events safely, and which common mistakes to avoid.
What Is a Parent Object in GameMaker?
A parent object is a regular GameMaker object assigned as the parent of one or more child objects. A child can inherit the parent’s events, code, actions, and Object Variables while still maintaining its own identity and appearance.
Imagine a project containing these objects:
obj_enemy_parent
obj_enemy_slime
obj_enemy_archer
obj_enemy_bat
The slime, archer, and bat can all use obj_enemy_parent as their parent. The parent might manage health, damage reactions, and death, while each child provides its own sprite and movement style.
A parent does not need to be placed in a room. It can exist only as a shared category or behaviour template. GameMaker also allows code and collision checks aimed at a parent to include instances of its child objects automatically.
This makes parenting useful for two related purposes: sharing behaviour and grouping different objects under one common type.
Put Shared Behaviour in the Parent
A parent should contain behaviour that genuinely applies to every child. For an enemy family, that may include health, damage handling, hit effects, and defeat logic.
In the Create Event of obj_enemy_parent, you could write:
max_hp = 20;
hp = max_hp;
contact_damage = 5;
take_damage = function(_amount)
{
hp = max(0, hp - _amount);
if (hp <= 0)
{
instance_destroy();
}
};
When child objects do not define their own Create Event, they automatically use the parent’s Create Event. The slime, archer, and bat therefore receive the same variables and take_damage() method without duplicating the code.
Keep shared behaviour reasonably general. Movement often belongs in individual children when enemies travel in very different ways.
A flying bat, ground-based slime, and stationary turret may share health logic but should not be forced into one complicated movement system.
A useful rule is to place code in the parent when changing that code should logically affect every child.
Use Object Variables for Child-Specific Values
Children often need the same variables but different default values. A boss may have 500 HP, while a small enemy has only 10.
GameMaker’s Object Variables are inherited by child objects. A child can override the value while keeping the same variable name and configuration defined by the parent.
For example, define these Object Variables on obj_enemy_parent:
max_hp = 20
contact_damage = 5
move_speed = 2
Then override them in individual children:
obj_enemy_slime
max_hp = 15
contact_damage = 4
move_speed = 1.5
obj_enemy_boss
max_hp = 500
contact_damage = 35
move_speed = 3
This approach is cleaner than creating unrelated names such as slime_health, bat_health, and boss_health. The shared enemy code can always read max_hp, regardless of which child instance is running it.
Object Variables are initialised before the Create Event, so the inherited parent code can safely use each child’s overridden values when setting up the instance.
Simplify Collision Checks with Parents
One of the most practical uses of parent objects is reducing duplicate Collision Events.
Suppose the player can be hurt by ten different enemy objects. Without a shared parent, the player might need ten separate Collision Events.
When all enemies inherit from obj_enemy_parent, the player needs only one event targeting that parent. GameMaker will include its child objects in the check.
Inside the player’s Collision Event with obj_enemy_parent, you could write:
take_damage(other.contact_damage);
The same principle works with collision functions:
var _enemy = instance_place(x + attack_x, y + attack_y, obj_enemy_parent);
if (_enemy != noone)
{
_enemy.take_damage(attack_damage);
}
Passing a parent object to functions such as instance_place(), place_meeting(), and other supported object-based operations includes instances of that parent and its descendants.
This technique is excellent for enemy families, solid obstacles, damageable targets, pickups, doors, and interactable objects. It lets new child types work with existing systems without adding another specialised check.
Override Child Events Carefully
A child does not always need to behave exactly like its parent. You may want every enemy to share health logic but give each one a different Step Event.
When a child defines an event that also exists in its parent, the child’s event overrides the inherited version. The parent event will no longer run automatically.
For example, suppose the parent Create Event initialises health:
hp = max_hp;
is_dead = false;
The archer needs additional variables, so its Create Event might use:
event_inherited();
shoot_cooldown = 60;
attack_range = 240;
The event_inherited() function runs the parent’s version of the current event before continuing with the remaining child code. It can only be used inside an object event.
Without that call, hp and is_dead would not be created by the parent event. This is one of the most common inheritance bugs in GameMaker.
Place event_inherited() near the beginning when the child depends on parent setup. You can place it later when the order genuinely matters, but that decision should be deliberate and clearly documented.
Override Methods for Specialised Behaviour
Sometimes child objects need to replace one small behaviour without overriding an entire event. Method variables are useful for this pattern.
The parent could define:
perform_attack = function()
{
// Default close-range attack
show_debug_message("Basic enemy attack");
};
The archer can inherit the Create Event and then replace only that method:
event_inherited();
perform_attack = function()
{
instance_create_layer(x, y, "Projectiles", obj_enemy_arrow);
};
Now shared parent code can call:
perform_attack();
The archer uses its projectile version, while other children keep the default attack.
When defining functions inside objects or structs, GameMaker recommends method-variable syntax such as perform_attack = function() rather than declaring them with global-style script-function syntax.
This matters because method variables can be overridden predictably by child objects.
This pattern is useful for attacks, movement strategies, death effects, sounds, and item interactions. It lets the parent control the overall flow while allowing each child to customise selected steps.
Keep the Inheritance Hierarchy Shallow
GameMaker can include descendants several levels below a parent in object-based operations. However, that does not mean every project needs a deep inheritance tree.
A structure like this is usually easy to understand:
obj_enemy_parent
obj_enemy_ground
obj_enemy_slime
obj_enemy_knight
obj_enemy_flying
obj_enemy_bat
But adding many more layers can make it difficult to discover where an event, method, or variable originates. A bug in obj_enemy_bat may actually come from code several parents above it.
Prefer broad, meaningful categories. If two objects share only one small utility, a reusable script function or component-style struct may be clearer than creating another inheritance level.
Also avoid using a parent simply because two objects look similar. Parenting should usually describe a shared gameplay relationship or shared behaviour.
Common Parent Object Mistakes
The first common mistake is forgetting that a child event overrides the parent event. Adding an empty Create or Step Event to a child can prevent inherited code from running unless event_inherited() is called.
Another mistake is placing too much behaviour in the parent. A giant enemy parent filled with conditions for every possible child can become harder to maintain than separate objects.
Developers also sometimes access a parent object as though it were one specific instance:
obj_enemy_parent.hp -= 10;
When multiple child instances exist, this may affect or read from an unintended instance. Use a specific instance ID returned by a collision function or stored in a variable instead.
GameMaker’s documentation advises using instance handles when a particular instance matters.
Finally, do not assume every variable exists merely because objects share a parent. Define required data consistently in the parent, through Object Variables, or inside inherited setup code.
Parent objects are most effective when they represent a meaningful family of GameMaker objects. They can centralise shared events, provide inherited variables, simplify collision checks, and allow children to specialise selected behaviours.
Use event_inherited() whenever a child event should extend rather than replace the parent event.
For smaller behavioural differences, override method variables instead of duplicating entire events. Keep hierarchies shallow, give every parent a clear responsibility, and use specific instance IDs when modifying individual objects.
Create a simple enemy parent with health and damage logic, then add two children with different sprites, statistics, and attacks. Testing that small structure will show how inheritance can reduce repetition without removing the unique behaviour of each enemy.
