Instead of charging out headlong into what I expect my final project to be, I’ve decided to get every component of a good RTS working on its own in its own isolated project. The goal with these isolated projects is to keep all of the elements as self-contained as possible to minimize coupling. After I have all of the components independently developed, I’ll be able to import them and begin design of the game itself.
The biggest asset to a good RTS game is an intuitive, responsive, and flexible selection system. Once you get in your flow while playing, you want to be able to issue commands to the right units as quickly as possible. If you can’t easily get the selection you want, it interrupts the flow and creates a frustrating experience.
Using the above information, I created the following goals for my selection system:
Additionally, we need to be able to save our selections to be recalled. To that end we will use:
I decided that to store which units are selected, I will create an object called Selection with a ds_list called Selected. The units will also need to remember whether or not they’re selected so our Selection object will have to make sure those two sets of information are synced. By creating a new ds_list when the left mouse button is released, we can compare the newly selected units with our currently selected units and modify our selection according to which modifier keys are depressed at the time.
Implementing the control groups was much easier than the mouse controls. Selection has an array called ControlGroup that holds 10 ds_lists. When saving a selection, we copy our Selected ds_list over to the ControlGroup[i] ds_list. When recalling a selection we do the opposite.
for( var i = 0; i < 10; ++i){
if( keyboard_check_pressed( ord( string(i)))){
// Add to group
if( keyboard_check( vk_shift)){
for( var j = 0; j < ds_list_size( Selected); ++j){
var a = Selected[| j];
if( !a.ControlGroup[i]){
ds_list_add( ControlGroup[i], a);
a.ControlGroup[i] = true;
}
}
// Set group
}else if( keyboard_check( vk_control)){
var cg = ControlGroup[i];
for( var j = 0; j < ds_list_size( cg); ++j){
(cg[| j]).ControlGroup[i] = false;
}
ds_list_clear(cg);
for( var j = 0; j < ds_list_size( Selected); ++j){
var a = Selected[| j];
a.ControlGroup[i] = true;
ds_list_add( ControlGroup[i], a);
}
// Recall group
}else{
selection_clear();
var cg = ControlGroup[i];
for( var j = 0; j < ds_list_size(cg); ++j){
ds_list_add( Selection, cg[| j]);
(cg[| j]).Selected = true;
}
}
}
}
Each game object has a boolean corresponding to the ds_lists Selection.Selected and Selection.ControlGroup[0-9].
For the test environment I created a simple hierarchy which is a simplified version of what I plan to use in the final product: Two objects oGuy and oBuilding have a parent oActor. This set up allows Selection to verify that a selection is selectable while still allowing the two types to be handled differently.
Each actor will have a script called RightClick that stores what should be their default behavior when the right mouse button is clicked. In this case, buildings do nothing and oGuys will move towards the click. When an actor knows it is selected, it will draw a green circle beneath itself.

I was able to create this component using 1 object (4 Events) and 2 scripts totalling less than 200 lines of code.
]]>