Warning: Constant WP_CRON_LOCK_TIMEOUT already defined in /home2/jemston4/public_html/wp-config.php on line 91

Warning: Constant AUTOSAVE_INTERVAL already defined in /home2/jemston4/public_html/wp-config.php on line 92

Warning: Constant WP_POST_REVISIONS already defined in /home2/jemston4/public_html/wp-config.php on line 93

Warning: Constant EMPTY_TRASH_DAYS already defined in /home2/jemston4/public_html/wp-config.php on line 94
Initial Commit – JEMstone Games

Initial Commit

I’ve wanted to make my own RTS game since I first played Starcraft back in ~2001. It is a huge undertaking though, so I’ve always thought it’s too ambitious. Sometimes I’d sit down to start, make part of a system, get overwhelmed, and save it never to be looked at again. This time, though, I’m attacking it with a plan!

Components

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.

Step 1: Selection

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.

Planning

Using the above information, I created the following goals for my selection system:

  • Selection will prioritize groups of units or a single building
  • A single click with the left mouse button will select a single unit
  • A drag-click will follow the selection priority
  • Pressing CTRL while clicking will select all of the same type of unit on the screen
  • Pressing SHIFT while clicking will modify your current selection. If any of the units selected here are not already selected, all newly selected units will be added to your current selection. If all of the units selected are already selected, these units will be removed from your current selection
  • Double-click will have the same effect as CTRL+click
  • Pressing CTRL+SHIFT will combine these effects

Additionally, we need to be able to save our selections to be recalled. To that end we will use:

  • Control Groups will be stored in keyboard row 1-9+0
  • CTRL+# will create and/or replace that control group with your current selection
  • SHIFT+# will add your current selection to that control group
  • Simply pressing the number will recall the stored control group

Implementation

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].

Test Environment

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.

Testing functionality of new Selection system

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

Leave a comment

Your email address will not be published. Required fields are marked *