I am personally not a big fan of switch
statements, so I implemented this like this:
I combined the ShowGridPositionRange
and ShowGridPositionRangeSquare
methods into one method by adding a circular
boolean parameter
private void ShowGridPositionRange(GridPosition gridPosition, int range, GridVisualType gridVisualType, bool circular)
{
var gridPositions = new List<GridPosition>();
for (var z = -range; z <= range; z++)
{
for (var x = -range; x <= range; x++)
{
var offsetGridPosition = new GridPosition(x, z);
var testGridPosition = gridPosition + offsetGridPosition;
if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition)) continue;
if (circular) // if we want a circular range, trim the corners
{
// This creates a 'manhatten' circle.
//could also use Mathf.Sqrt((x * x) + (z * z))
var testDistance = Mathf.Abs(x) + Mathf.Abs(z);
if (testDistance > range) continue;
}
gridPositions.Add(testGridPosition);
}
}
ShowGridPositions(gridPositions, gridVisualType);
}
Then I created an interface
public interface IGridVisualRange
{
bool RangeIsCircular();
int GetMaxDistance();
GridVisualType GetRangeGridVisualType();
}
which I only implemented on ShootAction
, SwordAction
and InteractAction
(I left out all the other code in here for brevity)
public class ShootAction : BaseAction, IGridVisualRange
{
// These values can be [SerializeField] instead of hard-coded
public bool RangeIsCircular() => true;
public int GetMaxDistance() => _maxShootDistance;
public GridVisualType GetRangeGridVisualType() => GridVisualType.RedSoft;
}
Note I moved the GridVisualType
enum out of GridSystemVisual
but that is not necessary
Then, lastly, I changed the code where the switch
was
private void UpdateGridVisual()
{
HideAllGridPositions();
var selectedUnit = UnitActionSystem.Instance.GetSelectedUnit();
var selectedAction = UnitActionSystem.Instance.GetSelectedAction();
// This checks if the selectedAction implements the IGridVisualRange interface
if (selectedAction is IGridVisualRange rangedAction)
{
// It does, so show the range
ShowGridPositionRange(selectedUnit.GetGridPosition(), rangedAction.GetMaxDistance(), rangedAction.GetRangeGridVisualType(), rangedAction.RangeIsCircular());
}
ShowGridPositions(selectedAction.GetValidActionGridPositions(), selectedAction.GetGridVisualType());
}
With this it is simple for me to add range to an action without too much fuss. I only need to implement the interface
Note I have changed the code slightly from my own implementation, so there may be a typo somewhere
Edit: Oh, I left out that I added a method to BaseAction
to define the GridVisualType
. This is for all actions
public abstract class BaseAction : MonoBehaviour
{
public abstract GridVisualType GetGridVisualType();
}
public class ShootAction : BaseAction, IGridVisualRange
{
// This return value can actually be a [SerializeField] instead of hard-coded
public override GridVisualType GetGridVisualType() => GridVisualType.Red;
}