CardConquest GameDev Blog #12: Reseting Unit Movement

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

The previous posts in this series can be found under the CardConquest category on this blog. The github for the project can be found here. The zip archive for this specific post can be found here.

As the game stands now, the player can move units one tile away from the unit’s starting location in any given “turn.” Within the same turn, the player can keep moving units so long as they don’t stray more than one tile from that starting tile. This allows the player to manually “undo” and moves they make with their units. However, after a bunch of units have been moved, it can get confusing on which of the units was moved from where. So, to allow the player to easily and quickly “undo” unit movements they’ve had second thoughts on, I want to make a button that will reset all the movement for them.

Starting with Some UI

The key to this “movement reset” is that there will be a button for the user to press, which means some more UI stuff will need to be added!

Because the undo button will only be used to reset units that have moved, it should really only be available after a unit has been moved. Recall in the current UI, there is a text object that says “No Units Moved” that disappears when a unit has been moved. It makes perfect sense then, at least to me, to have the undo button appear in the same location as “No Units Moved” after the text disappears.

Making the Button

In the hierarchy, right click on the UnitMovementUI panel, go to UI, then select button.

Rename the button to ResetAllMovementButton. With ResetAllMovementButton selected in the hierarchy, go to the Inspector window to configure it.

First, select the anchor and set the button’s anchor to Top Left.

Then, set the position values for the button to: Pos X: 175, Pos Y: -25, Width: 300, Height: 50

Then, under the “Image” section, make sure that “Fill Center” is unchecked.

Back in the hierarchy, expand the ResetAllMovementButton object and select the child Text object.

Under the “Text” section, configure the following:

  • Set the Text to “Reset All Movement”
  • Font Size to 32
  • Alignment to Centered
  • Color to White

With all that configured, you’re scene will look like this:

Well, that’s unfortunate. To get a look at what the button will look like, select NoUnitsMoved in the hierarchy and uncheck it in the Inspector window to de-activate it.

Now you can see your shiny new button!

Great! For now, make it so that NoUnitsMoved is active again. The correct UI elements will be activated and de-activated as required in the GameplayManager.cs script.

Scripting it all out

To begin scripting out this movement reset functionality, GameplayManager.cs will need a way to access the ResetAllMovementButton so it can be activated and deactivated as necessary.

First, add a new global GameObject variable called resetAllMovementButton.

[SerializeField]
private GameObject UnitMovementUI, endUnitMovementButton, resetAllMovementButton;

Activating and Deactivating the Button

First, when the Unit Movement phase first starts, the ResetAllMovementButton should be deactivated since no units will have moved right when the phase starts. To make sure the button is not active, a check can be added to GameplayManager.cs’s ActivateUnitMovementUI function.

if (resetAllMovementButton.activeInHierarchy)
	resetAllMovementButton.SetActive(false);

So now when the Unit Movement phase starts, if the resetAllMovementButton is active, it will be deactivated.

The button should now be activated when a unit is moved. This can be done in the UnitsHaveMoved function as that is already modifying the UI after a unit has first moved. A check will be made to see if the button is not activate, and if it isn’t, the button will be set to active.

if (!resetAllMovementButton.activeInHierarchy)
	resetAllMovementButton.SetActive(true);

Save GameplayManager.cs and return to Unity. Select the GameplayManager object and add ResetAllMovementButton to its “Reset All Movement Button” variable.

Now, when you run the game and get to the Unit Movement phase, you should see the “Reset All Movement” button appear after a unit has been moved.

The reset button doesn’t do anything…yet. Let’s work on that!

Resetting Units

Now, a new function will need to be added to GameplayManager.cs that actually resets the units’ postions.

Fortunately, the original position of a unit is already saved in its previouslyOccupiedLand variable. So, in order to reset a units position, to undo any player movement, all you should have to do is “move” the unit back to the tile stored in previouslyOccupiedLand.

To do this, a new function called ResetAllUnitMovement will be created. The code is shown below:

public void ResetAllUnitMovement()
{
	if (!EscMenuManager.instance.IsMainMenuOpen)
	{
		if (resetAllMovementButton.activeInHierarchy)
			resetAllMovementButton.SetActive(false);
		if (!unitMovementNoUnitsMovedText.gameObject.activeInHierarchy)
			unitMovementNoUnitsMovedText.gameObject.SetActive(true);
		if (endUnitMovementButton.activeInHierarchy)
			endUnitMovementButton.GetComponent<Image>().color = Color.white;

		GameObject unitHolder = GameObject.FindGameObjectWithTag("PlayerUnitHolder");
		foreach (Transform unitChild in unitHolder.transform)
		{
			UnitScript unitScript = unitChild.transform.gameObject.GetComponent<UnitScript>();
			if (unitScript.previouslyOccupiedLand != null)
			{
				Debug.Log("Unit was moved. Resetting unit movement.");
				if (MouseClickManager.instance.unitsSelected.Count > 0)
					MouseClickManager.instance.ClearUnitSelection();
				   
				MouseClickManager.instance.unitsSelected.Add(unitChild.gameObject);
				MouseClickManager.instance.MoveAllUnits(unitScript.previouslyOccupiedLand);
				MouseClickManager.instance.unitsSelected.Clear();
			}
		}
		haveUnitsMoved = false;
	}
}

ResetAllUnitMovement does the following:

  • Checks if the EscMenu is open. Nothing will execute if the EscMenu is open to make sure the user doesn’t undo movement if the accidentally clicked the button while navigating the menu
  • Next it goes through and makes some modifications to the UI:
    • Checks if the reset button is active. If it is, deactivates the button
    • Checks if the NoUnitsMoved text is active. If it is not, sets it to active.
    • If the endUnitMovementButton is active, set its color to white
  • All units will be found by finding the PlayerUnitHolder object by its tag
  • A foreach loop is used to iterate through each unit
    • If the unit’s previouslyOccupiedLand object exists, do the following:
      • If MouseClickManager’s unitsSelected list count is greater than 0, call “ClearUnitSelection” from MouseClickManager – this clears all currently selected units and removes their highlights if the player clicked the button while they had units selected
      • Add the current unit from the foreach loop into unitsSelected
      • Call MouseClickManager’s “MoveAllUnits” and provide it the unit’s previouslyOccupiedLand variable
        • MoveAllUnits moves all select units to the provided land tile. So, clearing unitsSelected and then adding the unit means that only that one unit will be moved to its previouslyOccupiedLand tile
      • Clear unitsSelected
  • set haveUnitsMoved to false

One thing you may notice in the screenshot of the code is the squiggly red line below ClearUnitSelection and MoveAllUnits. This is because those functions are currently private and will need to be made a public functions. Go to MouseClickManager.cs and make ClearUnitSelection and MoveAllUnits public.

Save MouseClickManager.cs, and when you go back to GameplayManager.cs, the squiggly lines/error for MoveAllUnits will be gone.

With the ResetAllUnitMovement created, the last thing that should need to be done is to attach the function to the button. Save the GameplayManager.cs script and go back into Unity. Select the ResetAllMovementButton in the hierarchy and in the Inspector Window, click the “+” sign under “On Click ()”. Add the GameplayManager object tot he button.

Click on the “No Function” drop down, go to “GameplayManager”, then select ResetAllUnitMovement.

Now, the Reset All Movement button should work. Let’s see that video…

Next Steps

I want to start adding some new content to the game. I haven’t mentioned it in a post in a while, but this game is called “Card Conquest.” So, maybe time to make some cards…