GameDev Blog Post 2: Highlighting Selected Object

Disclaimer: I am neither a professional game developer nor am I a professional programmer. I doubt I am following best practices. This is just what worked for me at the time. Hopefully it works for you if you’re playing along while reading!

Version of Unity used: 2019.4.13f1 Personal

In my first game dev blog post, I showed how to select an object when you clicked on it. In this post, I’ll make it so when you click on an object, that object is “highlighted” to show the player what objects they have selected.

This project can be found on GitHub. A zip file specific to this post can be downloaded from here.

How to Create a “Highlight”

When I first set out to do this, I wanted to figure out a way to indicate to the user what object they had selected when they clicked. In the Unity Tutorial – RTS Controls – Select Objects YouTube tutorial, they simply change the color of a box from red to green. That is pretty simple to do in Unity, and works well when you are working with simple, solid colored objects.

For my project, though, I have a sprite with multiple colors. You can just change the color of the Sprite Renderer in the same manner, but it doesn’t look very good. Instead, I wanted to make my object “glow” or look like it was “highlighted” when it was clicked. I searched for how to do this in Unity, to see if there was some obvious way to do it, and various forum posts seemed to suggest doing something like using multiple materials, using a separate mesh renderers or shaders. It was all a bunch of stuff I didn’t quite understand right away so I tried to figure out a quick and simple way to do what I wanted.

What I ended up doing was creating a new sprite that was a two-pixel wide yellow outline of my infantry sprite. It looks like this:


I made this in MS Paint using the same technique I described in part one. I first resized my image to 34×34 pixels so it would be 4 pixels larger in both directions compared to the infantry sprite. I then copy/pasted in the infantry sprite, drew the outline around the infantry, then deleted the infantry sprite. I resized the outline to 340×340 pixels, and then used Gimp to make the white space transparent. When I imported it into Unity, this is what it looks like when I have the outline at the same position as an infantry sprite versus an infantry sprite without the outline:

It looked like a pretty obvious indicator that one object was “highlighted” versus the other. I was happy with it! I added the outline to my “prefabs.”

Adding a Script to the Infantry Sprite

To create the highlight effect on the unit, I created a UnitScript script file.

This script will be used for various things for the “units” in the game later on. I next wanted to attach the script to the infantry sprite object. To make sure that the script will be attached to all infantry objects, you need to make sure to attach it to the infantry prefab. Otherwise, you will only attach it to the individual object in your scene, and any new infantry objects you create will not have the script.

So, first, select the infantry object in the scene. Then, in the inspector window, click on “Open” next to “Prefab”

Then, click on “Add Component,” search for the UnitScript, then add it.

Then, double click on the UnitScript to open it in Visual Studio.

Add the Outline to the Script

In Visual Studio, add the outline as a variable in the script.

[SerializeField]
public GameObject outline;

Save the script, and then back in the Unity Inspector, select the open the prefab for the infantry object.

I am also going to add a public bool variable to my UnitScript called “currentlySelected” which I will use to track which objects the user has selected.

public bool currentlySelected = false;

Activating the Highlight Outline

I will create a function in UnitScript that will activate and deactivate the highlight outline object. The function is called “ClickedOn” and is fairly simple and is shown below:

public void ClickedOn()
{
	if (currentlySelected)
	{
		outline.SetActive(true);
		Debug.Log("Currently selected set to true. Activating outline.");
		outline.transform.position = transform.position;
		
	}
	else if (!currentlySelected)
	{
		if (outline.activeInHierarchy)
		{
			Debug.Log("Currently selected set to false. Deactivating outline");
			outline.SetActive(false);
		}
	}
}

Here is what ClickedOn Does:

If currentlySelected is true:
1. Set the outline object to “active” in the hierarchy. This means that the object will be visible in the scene.
2. Set the “transform.position” of the outline to the “transform.position” of the gameobject UnitScript is attached to
– – “Transform.position” is the position in the world of the object. Basically, the object’s x,y, and z coordinates in space. The gameobject UnitScript is attached to is the infantry object. So, this is making sure that the outline object is in the same place in space as the infantry object, ensuring that the outline will line up correctly around the infantry

If currentlySelected is false:
1. Check if the outline is “active in the hierarchy” – basically, do a sanity check that the outline object actually exists before you take any actions against it
2. Set the outline to no longer be active in the hierarchy. This makes the outline invisible in the scene

So, the ClickedOn function will be used to make the outline appear when the infantry is selected, and then disappear when the infantry is no longer selected.

Initializing the Outline

In UnitScript’s “Start()” function, the outline object will be initialized so it exists in Unity to be interacted with. “Start()” will execute when the infantry object is created in the scene. There is a similar function called “Awake()” that will also execute when the infantry object is created, and Awake() actually runs before Start(), but for right now you can just do this is the prepopulated Start() function. The code is as follows:

void Start()
{
	outline = Instantiate(outline, transform.position, Quaternion.identity);
	outline.transform.SetParent(gameObject.transform);
	ClickedOn();
}

This does:
1. uses “Instantiate” to create a new gameobject using the outline prefab that was attached to the script. The infantry object’s transform.position is used for where to spawn the new object. Quaternion.identity is the “rotation” of the gameobject or something similar that I don’t actually understand
2. “transform.SetParent” is used to make the outline a child of the infantry object in the hierarchy. This makes the hierarchy a little more organized, and also makes it easier to keep track of and access the outline attached to specific infantry objects
3. “ClickedOn()” is then called. UnitScript starts with currentlySelected set to false, so by calling ClickedOn() in Start(), this should ensure that the outline is hidden when the game starts.

Triggering ClickedOn()

Right now, MouseclickManager.cs is the script where mouse clicks on the infantry object are detected. So, that is where ClickedOn() will be called from to highlight the object.

When a user clicks on an infantry object, the variable rayHitUnit will contain the collider of the infantry object. That collider will be used to access the UnitScript component of the infantry object using the following code:

UnitScript unitScript = rayHitUnit.collider.GetComponent<UnitScript>();

Once the variable unitScript has access to the infantry object’s UnitScript.cs component, you can then access public variables and functions from its UnitScript. The following code will set currentlySelected to true, and call the ClickedOn() function:

if (rayHitUnit.collider != null)
{
	UnitScript unitScript = rayHitUnit.collider.GetComponent<UnitScript>();
	if (!unitScript.currentlySelected)
	{
		Debug.Log("Selecting a new unit.");
		unitScript.currentlySelected = !unitScript.currentlySelected;
		unitScript.ClickedOn();
	}
}

Now, when the game is run and the user clicks on the infantry objects, the highlight outline is activated.

“De-selecting” the Infantry Object

To de-select the infantry object, or to remove the outline, you can simply do the reverse when the object is clicked on again. If the player clicks on a unit that was already selected, set currentlySelected to false and call ClickedOn() again.

else 
{
	Debug.Log("Deselecting the unit unit.");
	unitScript.currentlySelected = !unitScript.currentlySelected;
	unitScript.ClickedOn();
}

Here is what it looks like when you select both units, then deselect the unit on the left by clicking it again

De-Selecting All Units

It would be nice for the user to be able to de-select all currently selected units by doing something like right-clicking. To do this, you first need to keep track of the selected units in a list. To make this easy, I’m just going to keep that list in MouseClickManager, but you could do that in a different object if you wanted.

First create the “unitsSelected” list. It will be a list of gameobjects.

public List<GameObject> unitsSelected;

The list will need to be initialized as an empty list in the Start() function of MouseClickManager.

unitsSelected = new List<GameObject>();

When you click on a unit to select it, it will need to be added to the unitsSelected list:

unitsSelected.Add(rayHitUnit.collider.gameObject);

And also removed from the list when you de-select the object:

unitsSelected.Remove(rayHitUnit.collider.gameObject);

To de-select all units, a new function will be created in MouseClickManager called “ClearUnitSelection()”

void ClearUnitSelection()
{
	if (unitsSelected.Count > 0)
	{
		foreach (GameObject unit in unitsSelected)
		{
			UnitScript unitScript = unit.GetComponent<UnitScript>();
			unitScript.currentlySelected = !unitScript.currentlySelected;
			unitScript.ClickedOn();
		}
		unitsSelected.Clear();
	}
}

Next, back in the Update() function, you will need to add a detection for a right click. When the user right clicks, call ClearUnitSelection()

if (Input.GetMouseButtonDown(1))
{
	Debug.Log("Right clicked.");
	ClearUnitSelection();
}

Now, when the user right clicks, they should deselect all units. Lets see that riveting video!

Next Steps

Next, I will hopefully add a new unit (tank), and maybe add some land tiles for the units to move around on.