Featured Post

Dodgeball Game Maker Tutorial

This will be a series of posts that will teach you step by step how to make a simple arcade game using Game Maker Studio 2. The final game w...

Thursday, September 17, 2020

Dodgeball Tutorial: Enemy parent and child enemies

Inheritance: creating a parent object and a child object

Now that we have a basic enemy, we will create the other ones, but we will introduce the concept of inheritance, which means that we will have a parent enemy object with the functionality common in all enemies, and then, each enemy will have his own object, having the same parent object. This way we don't have to write the code multiple times and if in the future we want to change something, we can just change it in one place and all child objects will be affected by that change.

The first thing we need to do is to create a new object in the enemy folder called "oEnemyMedium" and assign the "sEnemyMedium" sprite to it. Now we can go to the "oEnemy" and remove it the sprite assignet to it, as the parent won't be instanced in the game, only the children, so there's no need to have a sprite in oEnemy anymore.

Now we will open our oEnemyMedium object and assign the oEnemy as a parent. To do this, we have to go to the parent section of the object and choose oEnemy as the parent of oEnemyMedium.

Now if we go into the room, we won't see our enemy anymore because we've removed the sprite. In the room editor will appear an "?" because our enemy has no image. What we have to do here is to delete the oEnemy and put the oEnemyMedium which is a child of oEnemy and has all it's functionality plus the sprite. So just delete the oEnemy selecting it and pressing the "supr" key, and then drag and drop from the assets tab the oEnemyMedium to the room (make sure that the instances layer is selected). If we run the game now, it will behave exactly as before but we have the parent functionality working and this will speed up the process when creating the other enemies.

Creating the other enemies as childs of our enemy parent object

Now we are going to create the rest of the enemies, so under the enemy folder, we are going to create oEnemySmall, oEnemyBig and oEnemySpecial. We need to create the sprites for those objects aswell inside sprites/enemies. Remember to put the origin of the sprite at middle center just as we did for our player and enemy medium sprites.

Note that the oEnemySpecial has more than one image, this is because it's an animated sprite. When importing the image for this one, we have to select all the images that compose the animation and import all of them into the sprite. So we will have a sprite resource composed of various frames that make an animation.

Now that we have all the necessary sprites for our enemies, we have to assign those to the objects. Also we have to set the parent of those objects to oEnemy, so we tell the engine that this objects will use the functionallity of the parent object. After assigning the parent, the create and step events from the oEnemy should appear in the child.

Now we can add the other enemies to the room and run the game to see that they behaive the same way as they have the same parent.

Changing the behaivour of different childs

It's great to have multiple enemies behaving the same way having the code only in the parent object, but let's add some variety to the behaivour of this children. We will make the small enemy to move faster, the big enemy to move slower and the special enemy to move always towards the player, so let's get started.

If we open our oEnemySmall and right click on the create event we can select the option of "inherit event" which will allow us to run the code in the parent plus some additional code that we want to add to it.

When doing this the code editor will open with a line of code that says "event_inherited()". This functions runs the code in the parent. So we will just add one line of code below, to make this enemy to move faster:


event_inherited();
_speed = _speed * 2;

First we run the code of the create event in the parent, which assigns a initial speed and direction for the object. And then we multiply this speed by two, making it faster.

Now we can do the same for our big enemy but instead of multiply the speed by 2, we will divide it by two, to make it slower. The good thing of this system is that then we can change our value in the parent object and the child objects will adapt it's speed to be twice and half fast of that initial speed that we have set on the parent.

The line of code inside the create event of the oEnemyBig should look like this:

_speed = _speed / 2;

Remember that this line has to go under the event_inherited(); to have it working properly, otherwise we will get an error because the variable _speed won't exist if first we don't call the parent function.

As for our special enemy, we will do the same but on this case, we will inherit the create event and the step event, because this enemy will be slightly different. On the create event we will divide the speed by 4, this will be the slowest of the enemies as it will be following the player constantly.

So add this line in the create event under event_inherited();:

_speed = _speed / 4;

Then do the same with the step event, but on this case, we will put the code above the event_inherited(); because we want to first run some code, and then call the parent code. As on this case the enemy will move towards the player, before calling the moving code of the parent, we will set the direction each frame to point to the player. The code should look like this.


if not instance_exists(oPlayer) {
	exit;	
}
_direction = point_direction(x, y, oPlayer.x, oPlayer.y);
event_inherited();

This code says works this way:

  • If the player don't exist (it has been destroyed) then we exit the event and do nothing, because there is no player to move towards.
  • If the player exists, then we update our direction to move towards the player.
  • Then we run the code of our parent object which moves the enemy.

And with this we are done, we've created multiple enemies that behave slightly different but all of them are using the same code, so if in the future we want to change how all enemies behave, we can just change it in the parent object. This is also usefull because on the Player object we configured the collision with the oEnemy which is the parent, this will allow us to detect collision with any of it's children. Otherwise, we should add a collision event for each enemy that we have in the game and this is not a good solution when we have a game with a lot of enemies.

Now if we run the game, we will se the enemies moving at different speeds and also the enemy special will be moving towards the player always.

On the next chapter we will create an object that spawns enemies in the room every few seconds.

No comments:

Post a Comment