Turn-Based Strategy - Problem actually taking an Action

Ok all, I need some help!!

I recently completed the UI World section of the Turn-Based Strategy game course and somehow messed up all my actions.

I had a problem when going back from Visual Studio Code to Unity and think I lost some of the update but I can’t figure out what.

My problem:
On Play my main unit is selected but I cannot change to any other unit. The Move action is highlighted and correctly displays the valid grid move positions. I can change to a different action and the visual correctly identifies the new action but I cannot actually take any of the actions! I click on the grid and nothing happens. I can’t move, can’t spin, can’t shoot! I can End the turn and I get the Enemy Turn visual that displays for a couple of seconds and then goes back to my player unit but again, can’t actually take an action.

Any thoughts on where I should look? I feel like I might not have some script correctly attached to the prefab or my units but I can’t see anything.

Any other guidance you pros might have? :slight_smile:

Let’s start by taking a look at your UnitActionSystem.cs file.

Here is that file below. I added some debug logging and it never enters the If statement where the getMouseButtonDown is pressed.

Are both Player units and Enemy units supposed to be set to the ‘Units’ layer? Or only the Player units?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UnitActionSystem : MonoBehaviour
{
    // Below is Singleton pattern
    public static UnitActionSystem Instance { get; private set; }

    public event EventHandler OnSelectedUnitChanged;
    public event EventHandler OnSelectedActionChanged;
    public event EventHandler<bool> OnBusyChanged;
    public event EventHandler OnActionStarted;

    [SerializeField] private Unit selectedUnit;
    [SerializeField] private LayerMask unitLayerMask;

    private BaseAction selectedAction;

    private bool isBusy;

    private void Awake() 
    {
        if (Instance != null)
        {
            Debug.Log("There's more than one UnitActionSystem!" + transform + " - " + Instance);
            Destroy(gameObject);
            return;
        }
        Instance = this;
    }

    private void Start() 
    {
        SetSelectedUnit(selectedUnit);
    }

    private void Update() 
    {
        if (isBusy)
        {
            return;
        }

        // If not the player's turn then don't do anything.
        if (!TurnSystem.Instance.IsPlayerTurn())
        {
            return;
        }

        if (EventSystem.current.IsPointerOverGameObject())
        {
            return;
        }

        if (TryHandleUnitSelection())
        {
            return;
        }
        HandleSelectedAction();
    }

    private void HandleSelectedAction()
    {
        if (Input.GetMouseButtonDown(0))
        {
            GridPosition mouseGridPosition = LevelGrid.Instance.GetGridPosition(MouseWorld.GetPosition());

            if (!selectedAction.IsValidActionGridPosition(mouseGridPosition))
            {
                return;
            }

            if (!selectedUnit.TrySpendActionPointsToTakeAction(selectedAction))
            {
                return;
            }

            SetBusy();
            Debug.Log("Valid grid position and have action points to spend.");
            selectedAction.TakeAction(mouseGridPosition, ClearBusy);

            OnActionStarted?.Invoke(this, EventArgs.Empty);
        }
    }

    private void SetBusy()
    {
        isBusy = true;

        OnBusyChanged?.Invoke(this, isBusy);
    }

    private void ClearBusy()
    {
        isBusy = false;

        OnBusyChanged?.Invoke(this, isBusy);
    }
    private bool TryHandleUnitSelection()
    {
        Debug.Log("before the getmousebuttondown.");
        if (Input.GetMouseButtonDown(0))
        {
            Debug.Log("In the TryHandleUnitSelection function after the getmousebutton down.");
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if(Physics.Raycast(ray, out RaycastHit raycastHit, float.MaxValue, unitLayerMask))
            {
                if(raycastHit.transform.TryGetComponent<Unit>(out Unit unit))
                {
                    if (unit == selectedUnit)
                    {
                        // Unit is already selected
                        return false;
                    }
                    if(unit.IsEnemy())
                    {
                        // Clicked on an Enemy
                        return false;
                    }
                    SetSelectedUnit(unit);
                    return true;
                }
            }
        }

        return false;
    }

    private void SetSelectedUnit(Unit unit)
    {
        selectedUnit = unit;

        SetSelectedAction(unit.GetAction<MoveAction>());

        OnSelectedUnitChanged?.Invoke(this, EventArgs.Empty);
    }

    public void SetSelectedAction(BaseAction baseAction)
    {
        selectedAction = baseAction;

        OnSelectedActionChanged?.Invoke(this, EventArgs.Empty);
    }

    public Unit GetSelectedUnit()
    {
        return selectedUnit;
    }
    
    public BaseAction GetSelectedAction()
    {
        return selectedAction;
    }
}

Here is the Unit Prefab settings:

Both player and enemy units should be on the Unit layer…

What concerns me is why Input.GetMouseButtonDown(0) is not firing. Just to double check, you’re not using the new InputSystem, right? (I know this is introduced at the end of the course).

Are you getting the Debug “before the getmousebuttondown”?
If you’re not, then it’s possible that you’ve got UI getting in the way of the tiles. In this case, you’d want to go over each of the UI elements. A big culprit here is Text and TextMeshProUGUI components. Sometimes Unity makes the actual size much larger than the actual text you’re using, making the component mask other components and (and this is why I ask about that 1st debug), report IsPointerOverGameObject() as true.

Brian, thank you very much for looking into this weird situation with me.

I do have both player and enemy on the Units layer. I am not using the new Input System yet.

I do get the “before the getmousebuttondown” log but I do not get log after the GetMouseButtonDown if block in the TryHandleUnitSelection function.

Couple of other weird things –

  1. Although I can’t select another unit or have the selected one actually take an action, when I End Turn, the enemy does take a turn but he doesn’t Shoot enemies that are in range. All he does is move closer to my furthest player and just takes 2 moves.

  2. I went ahead and did some of the other lessons to see if I would find something that would fix this. When I click on the grid and then hit T it shows the path that would be taken and is correct. So there is nothing preventing seeing that click on the grid.

Very, very strange…

Zip up your project and upload it to https://gdev.tv/projectupload. Be sure to remove the Library folder to conserve space.
Here’s the catch… this needs to be tonight, as I’ll be out of town and away from my coding computer until Monday starting tomorrow.

Hopefully, I can suss out what’s going on.

I can take a look if you are pushed for time

You both are awesome!!!

Just uploaded a 7zip file with it and the Library removed.

I have completed all the way through the Grenade Visuals section.

Thank you so much!

Ok, on an initial look, it does look like it’s a UI issue… I noticed that when the Game window has focus, the “before the getmousebuttondown.” debug is NOT firing. (You can see this yourself, by setting the console to Collapse, and watching the counter when the mouse button is in the scene).

This led me on quite the wild goose chase, and I finally started turning items on and off in the Heirarchy while the game was running until I started getting the correct responses… interestingly enough, it was turning off the UNIT that did it…

So… what was the cause of this? The TextMeshPro component on the Unit for displaying the ActionPointsText.

Open the prefab in isolation and select the ActionPointsText gameobject, then scroll down and in the TextMeshPro component, you’ll find a drop down for Extra settings (click to expand). In there, uncheck RaycastTarget.

After I did this and saved the prefb, I was able to complete actions in the game.

1 Like

A thousand Thank Yous!!!

I would have never found that. I don’t know how that ever got checked to begin with. Very odd.

I really appreciate you taking the time to look through all that. Good thing about these types of things is that I’ve learned now more about RayCast and also problem solving from your comments.

Again, thank you very much!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms