We would love you to play this but your browser doesn't support HTML5 canvas.
Just use a different browser and you can happily play this game.

Complex Skill Trees in GameMaker

Above is an interactive demo where you can try out the skill tree and reset it.

What Can This Skill Tree Do?

I wanted to have a skill tree where you could move back and forth in any direction and loop around back on yourself. I also wanted to have branches with one to many relationships and many to one relationships.

This basically allows you to have any shape skill tree you like.

I also thought it would be best to manage the whole thing from an array. The reason for this is I didn’t want to be moving large numbers of skill objects around a room (In my example there are only 40 skills but some people might want hundreds).

Complex Skill tree in GameMaker Complex Skill tree in GameMaker Complex Skill tree in GameMaker
How it works:

The whole project is made up of two objects obj_skillspawner and obj_skill.

obj_skillspawner:

This objects contains all the data we need about the skills in arrays; their draw location, what skills they link to. This object will then loop around this array to create all of the skills.

obj_skill:

This object is the skill, it is responsible for drawing itself and the line between it and any skills it is linked to. It will also run the code to purchase when it is clicked on.

First lets understand the arrays:
skillname[0] = "Skill0" // the name of the skill (isnt used)
skillimage[0] = 0 	// this is the image that should be used
skillneeds[0,0] = -1	// What skills the player needs to unlock before they can get this one (-1 is always available)
skillx[0] = 230		// x position of this skill on the screen
skilly[0] = 230		// y position of this skill on the screen

skillname[1] = "Skill1"
skillimage[1] = 0
skillneeds[1,0] = -1	// -1 always available
skillx[1] = 370
skilly[1] = 230

skillname[2] = "Skill2"
skillimage[2] = 0
skillneeds[2,0] = 0	// Link to both skill 0 and skill 1
skillneeds[2,1] = 1 
skillx[2] = 300
skilly[2] = 160
	

Those three arrays build this skill tree:

Simple Skill tree in GameMaker

Notice how skill 0 and 1 don’t say they are connect to skill 2, They only point towards the skill start object. This is because skill 2 says it is connected to both 0 and 1. When connecting skills you only need to connect them in one direction, you DON’T need both skill 1 to point skill 2 AND skill 2 to point back to skill 1.

Simple Skill tree in GameMaker
The Code:

obj_skillspawner – create:

This is the code that turns your array into individual skill objects, also pre caches where to draw the lines into an array.

for (i=0; i<array_length_1d(skillname); i++) // loop around for each skill
{

	var newskill = instance_create_layer(skillx[i], skilly[i],"Instances",obj_skill); // Create an object that will be this skill 
	newskill.image_index = skillimage[i]
	newskill.skillname = skillname[i]
	newskill.skillid = i

	show_debug_message("We have made skill " +string(skillname[i]))
	
	// ASSERT – at this point the object skill has been made 
	
	with(newskill) { // we now want to pre record all the lines this skill is connected to so we dont have to work it out every time
	
		for (j=0; j<array_length_2d(other.skillneeds,other.i); j+=1) // loop around all the skills I connect to 
		{
			skillneeds[j] = other.skillneeds[other.i,j]
			show_debug_message("Skill "+ string(newskill.skillname) + " needs " + string(skillneeds[j]))
			
			if (skillneeds[j] == -1) { // This skill is always available so draw a line to the central object 
				
				status = 1
				linetox[0] = obj_skillspawner.x
				linetoy[0] = obj_skillspawner.y
				needcount = 1
				
			} else { // on the new skill record where its lines should be drawn so we don’t need to look it up every frame
				
				linetox[j] = other.skillx[skillneeds[j]]
				linetoy[j] = other.skilly[skillneeds[j]]
				  
				needcount++
			};
		}
	}

};

	

obj_skill – create:

Initialise everything obj_skill will use but we will overwrite all of this.

image_speed = 0 //Just to stop the skill trying to animate 

// Initialise some things we will overwrite in obj_skillspawner 
skillname = 0	// We don’t use this but this could be drawn next to or on mouse over to show the player the name of the skill
skillid = 0	// this is the unique id of this skill 
skillneeds = -1 // this will be an array holding the unique id of any skill requiered before getting this one
needcount = 0	// this will basically hold array_length_1d(skillneeds) so we dont have to do it every frame

linetox[0] = 0	// this will be an array of where to draw every line coming out of this skill 
linetoy[0] = 0

status = 0	// 0 = unavailable, 1 = available, purchased = 2 
	

obj_skill – Draw:

Draw the lines

if (status == 0) { // set the colour of the line (black means they can unlock it, gray is still locked)
	draw_set_colour(c_gray)
} else {
	draw_set_colour(c_black) // I want all my lines black 
}

for (d=0; d<needcount; d++) // loop around all of the lines we have already cached and draw them
{
    draw_line_width(x,y,linetox[d],linetoy[d],2)
};
	

obj_skill – Draw End:

Draw the skills

switch (status)
{
    case 0: // Unavailable
		draw_sprite(spr_skills,10,x,y) // image_index 10 is a gray image of the skill so draw this if they cant buy the skill
	break;
    case 1: // Available 
		draw_sprite(spr_skills,image_index,x,y) // they can buy the skill so draw it normally
	break;
	case 2:
		draw_sprite(spr_skills,image_index,x,y) // they have bought the skill so draw it normally but ontop draw a box that shows they own it
		draw_sprite(spr_available,0,x,y)
	break;
}
	

obj_skill – Left Click Released:

The player wants to buy this skill so check to see if they can buy this one and then check all the skills that link to this one to see if they should now be available.


if (status == 1) { // You can only buy this skill if it is available  

	// add any code here for buying the skill, i.e. you might have to deduct money or skill points 

	status = 2 // set this skill as being bought 
	
	with(obj_skill) { // go through all skills and see if they should now be set to available
	
		// Set skills I link to as available 
		for (i=0; i<needcount; i++) {
		    if (skillneeds[i] == other.skillid) {
				if (status == 0) { // dont overwrite if they have already bought upgrade
					status = 1 // This skill is next to me on the tree and is unavailable so make it available. 
				}
			}
		};
		
		// Set skills that link to me as available  
		for (i=0; i<other.needcount; i++) { // go backwards down the tree
			if (other.skillneeds[i] == skillid) {
				if (status == 0) { // dont overwrite if they have already bought upgrade
					status = 1 // This skill is next to me on the tree and is unavailable so make it available. 
				}
			}
		}

	}
	
	// add any code here to save the changes 
	
}

	

Now that looks like a lot of code but it’s mostly comments, at the bottom of this page there is a link to download a GameMaker 2 project file so you can try it out for yourself.

Customisation:

When it comes to moving this over to your own game I have really only focused on the data structure and making the tree. I have only used 9 skill images and repeated them however I would suspect you would have a unique image for each skill, in fact I would suggest you had a unique image for mouse over, purchased, available to buy, unavailable. You may even want to have tooltips and other popups. All of this should just be added to the big array and passed over when the skill is made.

I haven’t included any concept of skill points which would probably be quite important for you. It would be trivial to add a count and an if statement to the on click event, however I didn’t do this because every persons game will handle skill points in a different way. I didn’t see this as part of the scope of this guide, if you are capable of putting this skill tree into your game I will also assume you are capable of counting skill points.

A harder aspect is how to know if someone has bought a skill, let’s say one of the skills somewhere on the tree was the ability to double jump, how can you check this every time someone jumped? It wouldn’t be efficient to check the tree every time. Well again I haven’t really included that because every persons game will be different, some people will have their skills on a different room that you do before you start the level, some people may do their skills inline by pressing a button when they are ingame. Ideally you would save when someone changes the skills (I left a comment in that show when to do this), you would then use this same save file to load the skill tree in the future and also load in which abilities the player has when they start a level.

The last thing you might want to add is the ability to remove skills, this would be pretty tricky because you would have to thoroughly reprocess every skill to see if its status needs to be changed because of the removed skill. Most games handle this by just clearing the whole tree and giving all the points back. It is possible to remove one at a time but it would basically triple the length of the code.

Path of Exile:
Path of Exile Skill tree in GameMaker

This is just a small amount of the very complex skill tree you get in Path of Exile. What I really liked about this was how you didn’t have a set path and could move around freely. The more powerful skills tend to be around the outside of the tree so if you wanted to try and rush to the outer skills you could, or if you wanted a more balanced character you could move around the web picking up skills that combed well together. They also made it so that Intelligence based skills were at the top, strength on the left and dexterity on the right, this allows you to move around the tree if you wanted a duel type character.

This is just an example of the type of thing you could do with this system.

This could be used for more than just skill trees, I would love to see it used to do overworld maps, dialogue trees, character progression, level selection, area specific damage etc.

Download Project File:

GM2 Project file: Download

GM1.4 Project file: Download (made by Dev Smithy)

Easy Difficulty
GameMaker
By David Strachan
Get an E-mail when I post something new: Signup