Your boy (me) is back again with another GameMaker tutorial. Today, the topic of discussion is object ownership. By assigning an owner to an object, which is usually another object, we can manage object interactions. In the example below, I will be using a player, bullets, and enemies to illustrate how you can use a single object that can be “owned” by any other object. Both the player and enemies will use the same bullet object, but they will not be able to shoot/damage themselves.
This entry assumes you know a little bit about object parenting. If you are unfamiliar, check out my previous entry on that exact topic, here.
Before we can start shooting bullets all over the place, we need to create a couple of objects and sprites. We need a player, a bullet, and an enemy. Go ahead and create the sprites and objects for all three, and let's start with the bullet stuff. Open your bullet object and add some code to the following events.
oBullet create event
owner = -1;
xSpeed = 0;
ySpeed = 0;
oBullet step event
x += xSpeed;
y += ySpeed;
with(parentEnemy){
if(place_meeting(x,y,other) && other.owner != id){
life --;
with(other){
instance_destroy();
}
}
}
In our create event we initialize the owner variable, which is set to a negative number by default. This variable will be storing the ID of an object, which is always a positive number. By initializing it as negative, we make sure that it can’t accidently be set to some other object. The xSpeed and ySpeed variables are how we will address the movement speed of the bullet. If you do not have a parentEnemy object, just replace parentEnemy with whatever your enemy/shootable object is named.
The step event may look a little strange if you’ve never seen or used the with operator. I’ll provide more info on with and other at the bottom of this blog, but here is a quick crash course. Using with allows you to run code as if you were doing so from another object. So, in this case, when we say with(parentEnemy) it's as though the following code is ran from every parentEnemy object that exist within the game. When using with you are also able to use other which is a shortcut to refer back to the object that is calling with in the first place. This makes it easy to check collision against our bullet!
First, we check place_meeting to see if the parentEnemy has touched the bullet, and then we check to see if the owner ID of the bullet is NOT the same as what it is colliding with. If the ID is not the same, then subtract one life from the enemy, and destroy the bullet. Before we can test this, we need to be able to shoot some bullets at some enemies, right?
Setting up the shooting, and the ownership of the bullets that are created, is really what this blog is about. When the bullet is created, a few variables need to be updated, such as the owner and the direction the bullet is moving. Open up your player object and add the create, and step events. We are going to slap together a quick and dirty player object.
oPlayer create event
left = false;
right = false;
up = false
down = false;
shoot = false;
facing = 1;
canShoot = true;
fireRate = 0;
fireRateMax = 20;
Up first we initialize some booleans that we will use for button presses. Addressing left is a lot easier than addressing keyboard_check_pressed(vk_left). Shoot will also be used to address a button press. Facing will help us determine the direction our character is facing, either left or right, and create bullets relative to the direction. The remaining variables are tied to shooting, and how often the player is allowed to shoot. We will cover that in a moment. First, let's set up our really basic movement.
oPlayer step event
left = keyboard_check(vk_left);
right = keyboard_check(vk_right);
up = keyboard_check(vk_up);
down = keyboard_check(vk_down);
shoot = mouse_check_button(mb_left);
//move
if(left){
x -= 2;
facing = -1;
}else if(right){
x += 2;
facing = 1;
}
if(up){
y -= 2;
}else if(down){
y += 2;
}
image_xscale = facing;
Alright, this is about as basic movement as we can get, but that is okay. Really the only reason we need movement is because I’m illustrating how to create bullets relative to the player. We assign all of our buttons to the variables we created, and then adjust the x/y position of our player object when we push the buttons. The most important thing here is that we change facing to -1 or 1 based on left and right button presses. On to the shooting! Add this code below everything you just added above.
oPlayer step event
if(shoot && canShoot){
bullet = instance_create(x + 16 * facing, y, oBullet);
bullet.owner = id;
bullet.xSpeed = 5 * facing;
canShoot = false;
}
if(!canShoot){
fireRate ++;
if(fireRate >= fireRateMax){
fireRate = 0;
canShoot = true;
}
//semi auto
if(!shoot){
fireRate = 0;
canShoot = true;
}
}
This is the good stuff right here! The first block of code checks to see if we are pushing the shoot button, and if canShoot is set to true. Then, if both of those checks pass, we create the bullet. When creating the bullet we store the ID of the bullet in a variable so that we can easily address it. Using this variable, we assign the owner of the bullet by passing in the ID of the player object. We then set the bullet speed based on the direction the player is facing, and finally, we set canShoot to false to limit how often the player can shoot.
This is all optional of course, but this is a good example of how fire rate works. After you have shot, you are not allowed to shoot again until certain conditions are met. We count up our fireRate until it reaches fireRateMax, and then canShoot is set back to true. This allows the player to shoot again! The lower the fireRateMax, the more often the player can shoot. Below, however, I added some code to allow for semi automatic (shoots as often as you click the mouse) firing. Once the player has let go of the shoot button, the fireRate is set to zero, and canShoot is set to true.
In the image above, you can see how the fire rate changes based on me holding down the shoot button, and rapidly clicking. Try not to be too jealous of my amazing art skills. Try tweaking your fireRateMax, and bullet speed when creating the bullet. You can easily turn this semi auto pistol style shooting into a crazy machine gun! Toss a bit of screen shake on there and you are on your way to a cool feeling gun.
This might be a little excessive...
That about wraps it up for object ownership. Keep an eye out for another blog post about how to make enemies shoot back at the player! Thank you for taking the time to read over this, and I’ll catch you next time. As always, you can reach me on Twitter or visit my website for more gamedev stuff.
Nathan Ranney is the founder of punk house game dev shop, RatCasket. He’s best known for the creation and development of Kerfuffle, an online indie fighting game.