Not enough ratings
How to create a selectable player (Parenting on a real world example)
By Scorcher24
In this guide you gonna learn how you can enable your player to have a class or a different character to select, including different weapons and graphics. We are gonna use parenting for this, so see this as an extended guide on parenting with a real world example.
Rate  
Favorite
Favorited
Unfavorite
The Problem
So you want to make that super cool RPG, but you don't know how to have different classes in your game. It also adds the challenge of having different weapons for each class etc.

If you struggle with this, this guide is for you.
Disclaimer
You will notice that I am ending most codelines with a semicolon. This is by no means required, but it is valid code. I am doing that because I am a C++ Programmer where this is required.
So please, no debating about it ;-).

All Code in this tutorial was written by me from the ground up. I hereby put this code under Public Domain, granting everyone the right to use it for whatever purpose.
Setting up
What you need:

  • Different pictures for your different characters.
  • Different particles or images for your weapons.
  • 2 rooms - one for selecting and an example level.

You don't need any extra graphics for the selectable classes.
We just reuse the same graphics and use the object system to create the selectable objects.

This guide uses images from Kenny, who provided it via OpenGameArt.com, which you can download here:
http://opengameart.org/content/platformer-art-deluxe
The package is provided under Public Domain, you can use it freely in your game.


What you also need is basic knowledge of GameMaker itself and GML. I will not provide much hints how to create objects, sprites etc. If you struggle with this, go back to basic tutorials or read the manual. If anything besides this is unclear, please let me know in the comments.
Parenting done right
The first thing we gonna use is the parent system that is available in GameMaker.
For that we gonna create a new object and call it "objPlayerParent".

Parents are used to add the same events, attributes and even sprites to various object and/or to combine those. I am gonna show you how to do this.

For objPlayerParent, do not add any sprite as image. Just leave it blank.

Run Forest, Run


Now, we gonna add movement to this object, so the player can move it around.
For the sake of this tutorial, we gonna keep it simple. Add the following events and create a script in the event, adding the code provided:

Key Press "Left"

speed = 10;
direction = 180;

Key Press "Right"

speed = -10;
direction = 0;

Key Release "Left" and "Right" (1 Event for each)

speed = 0;

Intersect Boundary

speed = 0;

Now what this code does, is to simply allow the player to move left and right and stops him when he goes outside the room area. Please note, if you use views, you might wanna use a different approach. But this basic setup is enough for our example.

Preparing Violence


Now, add a "Create Event" and add a new variable called "weapon", via the drop action.
Leave it at 0.

Add a second variable, called "canShoot".
Change it to 1.

We need those variables for 2 things.
"weapon" is gonna tell our parent class which weapon the player is using. So this way we can have different behaviour and images for the weapons particles.

The "canShoot" variable is gonna be used to limit the players ability to shoot. Otherwise the player might just unleash thousands of shots each step.
To reset it, create a new event for Alarm 0 and change "canShoot" in this Event back to 1.
Do not restart or start the timer anywhere for now, we gonna code this section next.

Somebody shoot him


Create a new event for a key press of "space". Add a script.
We are gonna add the following code:

var new_shot;

if ( canShoot == 1 )
{
// Disable shooting
canShoot = 0;

// The timer reenables the ability to shoot
alarm[0] = floor(room_speed / 4);

// Create new shot and send it into the direction of the mouse
new_shot = instance_create( x, y, weapon);
new_shot.speed = 20;
new_shot.direction = direction;
}
( As you notice, there is a 0 missing in the code above inside the brackets of alarm. This is not due to my bad coding, but Steam messing it up when displaying the code.)

You should be able to understand this code. What it does is simply to look if shooting is enabled. If yes, it is blocking shooting and resetting the alarm to ~7 steps. This means, our player can shoot each 7 steps one bullet. It then creates and speeds up the projectile and sends it into the current direction of the player.

Notice how we use the variable "weapon" here. So far this script would crash, because weapon is nil right now. There is no object behind it. But we are gonna change this in our next steps.
Creating diversity
The Sprites

Create sprites and add the 3 different player skins from the sprite package, or your own and also add 3 different weapon images. I have also added a platform, where the player can walk on, but that is up to you.





The objects

From these images, create the objects as shown and name them accordingly. Those are our different classes and other things we need. In the end it should look like in the image. Again, using a tile as platform is totally up to you and not mandatory for the sake of this example.

As you can see in the image, we have now 3 objects that are named objSelectableClassName. Those are gonna be dummies that we use for the actual selection. We do not use the player objects for it, because the player would be able to actually play in that room where we don't want him to play or we would need to wrap all code with some if clauses, creating a big mess in the code. An object is only a few kilobytes big and I really think this way is cleaner and also better maintainable, especially in big projects. We also have our weapon names ready. Now we are gonna do the screen where the player is able to select the class he wants to play.
Editor's Choice
The rooms



Now create a room and call it "rmSelect" or any other name you are comfortable with. Arrange all your objects that are meant for selection like in the image shown above or however you are fine with. I gave it for the sake of this tutorial a size of 800x600 but this is totally optional and up to you.
I also gave it a nice background, but this is optional and you can leave it with a color.

Now, open the creation code of this room in the settings tab of the room panel.
Enter this code:

globalvar playerDude;
globalvar playerObject;

What this does is, that it creates global variables named "playerDude" and "playerObject" when the room starts. This ensures that as soon as we enter this room for the first time, those variables are created and we can access them in all scripts that we use. Have a look at the documentation[wiki.yoyogames.com] for more information.

After this, create a second room and call it rmGame. Give it a background or not, a size you are fine with and leave it for now.

Coding the selection

Now, open your first selectable object. We are gonna start out with the Mage.
Create an event for "mouse left pressed" and create a script.
Enter this code:

global.playerDude = objMage;
room_goto(rmGame);

Now do this for all other objects and replace the assignmet for global.playerDude with the respective objects, meaning objWarrior in the warriors code, objPriest in the Priests code.

This code is simply assigning the selected object to our global variable playerDude. We need to store this, so we know what the player selected in the next room, where we actually gonna spawn him. After doing that, the game moves us to the gaming room.

Finishing touches (Optional!)

This is an optional part, but I feel the need to point it out. If you make a selection of any kind, it is always good to give the player some feedback. There are 2 ways of creating feedback here.

My favorite is to use tooltips. It is a simple way of giving the player information what a button or a selection does. If you don't know how to make tooltips, look at my other guide for more information:
http://steamcommunity.com/sharedfiles/filedetails/?id=113152074

Another way would be to render some text below the dudes that simply displays something when you hover the mouse over the sprite. Game Maker's Sprite Editor also has the ability to add some glow around images. So you could copy the sprites we use, add some glow around them and when the player hovers over them, you replace the rendered sprite with the glowing one.
Simple, but effective and intuitive feedback for the player to see what he is actually doing.

You can also combine those methods. Be creative!
Arming the child and giving it a parent
Remember back when we added this code for shooting and I said this will make our game crash right now? We gonna take care of this right now and it is really, really easy.
If you have set up your objects like I did, you should have three objects:
  • objFireball
  • objBrick
  • objStar

So the idea is, that the Mage shoots Fireballs, the Warrior throws bricks in ya face and the Priest is gonna burn you with stars.

We gonna start with the Mage once more. Open objMage and add a "Create Event".
Wait a second. We are already using this event in our objPlayerParent, does this not cause problems?? The answer is: Yes, it will, if we don't do something about it.

If you have the same event in your parent and your child object, then the child overrides the parent's event. This is actually quite useful, but also a source for errors.
In our case, we created 2 variables in the parent's "Create Event". But we need those, otherwise our scripts won't work.

On the right side, open the tab where it says "Control". Click the button where it says "Call Event".
What this actually does, is that it calls the parents event of the same type. (If you want to do this in code, you will have to use event_inherited()[docs.yoyogames.com]).


Alright, so now that has been taken care of. Now add another "VAR Drop Action", name it weapon and set it's value to objFireball.

As last step, set the parent of this object to objPlayerParent.
Repeat those steps with objPriest and objWarrior, using their respective weapons and you are done.
Creating the game room


Remember rmGame we created in the previous part of the tutorial? I have changed it to look like this. A nice background, some tiles and this little star. This is our controller for spawning the player.
We gonna create this now, since it gonna helps us to do a little task. You don't necessarily need this, since you could use the room creation event for it, but it is actually better to use a different event.

Create a new object, call it objSpawnController and place it in our room.
You have two choices. One is to give a little bogus graphics so you can see on the first look what it is. In that case you need to untick "visible" in it's properties. Or you can leave it empty. If you render some GUI with this controller, you will need to leave it visible, because otherwise nothing is drawn.

Now create a "Room Start" event in objSpawnController.
You find this under "Other" in the event menu.
Create a script and add this code:

global.playerObject = instance_create( 416, 270, global.playerDude );

Please note that the actual parameters for the position depend on your room and you will have to adjust them as needed. Or you can create physics and have your player fall down to the actual floor. I hope you get my drift.

What is important is that this code spawns the object we have selected previously. We store the instance of the player in a global variable for various reasons. First of all, we can access it directly in any script. Second of all, we can transport him over rooms and it keeps it's values like weapons used, health etc etc. You should actually create your player instance only 1x in your entire game (depending on your game though), but in this case it is the best way to do it.

Create a second event, for pressing "Escape" on the keyboard.
Create a script and add this code:

with ( global.playerObject ){
instance_destroy();
}
room_goto(rmSelect);

This destroys the player object and sends us back to the selection. We don't need this actually, but for the context of this tutorial, it is useful. Note how I have to use the "with" keyword to destroy the instance. instance_destroy()[wiki.yoyogames.com] takes no parameters and is always executed on the current object. So without it, it would destroy our controller. With it, I can redirect this command to the players instance.
Rounding it up
Now you know how to put a selection together to enable your player to use skins, different classes, different spaceships and other stuff. You also probably learned how to do tooltips in GML.

All this is actually fairly simple, but it adds so much to every game.
If you have any questions, please ask them in the comments, I will answer them.

I also got a few downloads for you guys:

GMZ to import into GameMaker
Executable to run the example (if you don't have Studio)

Workshop:
Workshop


Have fun and please report errors and mistakes!
Credits
10 coconut chocolate cookies and 3 cups of coffee have been harmed during the creation of this guide.
4 Comments
< >
Jessie Aug 17 @ 2:46pm 
Brilliant, much more helpful than the tutorials on the GM forums.
PackSciences May 12 @ 1:21pm 
Thanks dude :)
99 Beers Jan 5 @ 8:42pm 
Thanks very much OP. This helped me a lot.

Would like to add if you want to make a top-down rpg/shooter where the mouse aims and shoots this is what I modified from OP. I'm a noob so most of this is Drag'N'Drop not scripts.

Create Object: ObjWeaponParent (this is to make cursor aiming)
Create Event: Move Towards Point
x: mouse_x
y: mouse_y
speed: 20 (or whatever you prefer)
*Like OP mentioned - no sprite for Parents.

Next find your weapons: fireball, brick and star.
Make sure you assign the ObjWeaponParent to each of them.

Finally, open objPlayerParent
We got aim above, now to fire with mouse. Now create event - I pick Global Left Mouse - this for whatever reason allows me to hold and fire instead of clicking for each bullet.
1) Event > Global Left Mouse
2) Execute Code : Same Code as OP gave for using space bar to fire.
3) Delete The last two lines of Code:
new_shot.speed = 20;
new_shot.direction = direction;
vgreeson Dec 21, 2013 @ 6:35pm 
Very helpful! Thanks.