How To Make A Cover System In Unity: Similar to Dawn Of War – Part 2

Tom McDonald
Updated on:
How To Make A Cover System In Unity

Welcome back to the second installment of my series on How To Make A Cover System In Unity. If you followed along with my previous post, you already have a solid understanding of the CoverSpot class. Now, it’s time to put everything together with the CoverController, the overarching system that manages our individual cover spots.

📢

This tutorial is part one of a multipart series focused on building a Dawn of War-style cover system in Unity 3D.

Why Do We Need a CoverController?

Before we get into the code, let’s briefly discuss the role of the CoverController.

Imagine a battlefield scene where a barrier of sandbags is positioned as a defensive structure. While this barrier might seem like a single entity, it can actually provide cover for multiple units at different spots along its length. For instance, the sandbags might offer four distinct CoverSpot points. Each of these points represents a place where a unit can take cover.

Now, while our CoverSpot class gives us information about an individual cover point—like whether it’s occupied or not—the CoverController offers a more overarching view. It’s responsible for managing all the cover points associated with a particular structure or barrier.

available cover spots light up as I hover over sandbags
In Last Stand, the available cover spots light up as I hover over sandbags with the selected squad

What Are The CoverController’s Responsibilities

Here are the primary responsibilities of the CoverController:

  1. Manage Multiple Cover Spots: It should know about all the cover spots associated with its barrier or structure, whether sandbags, walls, or other obstacles.
  2. Track Occupancy: At any point, the controller should be able to tell which spots are occupied and available.The CoverController keeps tabs on this, ensuring units don’t attempt to take an already-occupied position.
  3. Handle Interactions: When a unit seeks cover, the controller helps determine the best available spot, considering things like proximity to enemies and the overall battlefield layout.

The CoverController Code

Having established the need and responsibilities of the, let’s dive into the code and understand its key elements.

    public class CoverController: MonoBehaviour, IIndicator
    {
        private IndicatorController[] selectionIndicators;
        public CoverSpotConfigSO coverData;

        private void Awake()
        {
            selectionIndicators = this.GetComponentsInChildren<IndicatorController>(true);
        }
        
        public void HideIndicator()
        {
            if (selectionIndicators.Length > 0)
            {
                var x = 0;
                foreach (var item in selectionIndicators)
                {
                    item.gameObject.SetActive(false);
                    x++;
                }
        
            }
        }
        
        public void ShowIndicator(UI.Selection.IndicatorType indicatorType, Color32 color, bool rotate = false)
        {
        
            if (selectionIndicators.Length > 0)
            {
                var x = 0;
                foreach (var item in selectionIndicators)
                {
                    item.gameObject.SetActive(true);
                    item.ShowIndicator(indicatorType, color, rotate);
                    x++;
                }
        
            }
        }

        public CoverSpot[] GetCoverSpots()
        {
            var spots = GetComponentsInChildren<CoverSpot>();
            return spots;
        }

        public List<Transform> GetAllOccupiers()
        {
            var spots = GetComponentsInChildren<CoverSpot>();
            var occupiers = new List<Transform>();
            foreach (var spot in spots)
            {
                if (spot.IsOccupied())
                {
                    occupiers.Add(spot.GetOccupeir());
                }
            }

            return occupiers;
        }

        public int EmptyCoverSpotCount()
        {
            var spots = GetComponentsInChildren<CoverSpot>();
            var amount = spots.Count(i => i.IsOccupied() == false);
            return amount;
        }
    }

1. Properties and Variables

  • IndicatorController[] selectionIndicators: An array that holds all the indicators for cover spots. This is primarily used to communicate to the player which spots are available visually.
  • CoverSpotConfigSO coverData: This ScriptableObject likely contains configuration data about the cover spots. This abstraction is great as it makes it easier to manage and adjust cover-related settings.

2. Indicator Management

  • Awake(): Initializes the selectionIndicators array, gathering all the IndicatorController components in the children.
  • HideIndicator(): Hides all the indicators. It iterates through each indicator and deactivates it.
  • ShowIndicator(UI.Selection.IndicatorType indicatorType, Color32 color, bool rotate = false): Activates and configures the indicators. You can specify the type of indicator, its color, and if it should rotate.

3. Cover Spot Management

  • GetCoverSpots(): Retrieves all the CoverSpot components associated with the controller. It gives a complete list of available spots for the given barrier or structure.
  • GetAllOccupiers(): Fetches all units or entities that are currently occupying a cover spot. This is important in gameplay mechanics, especially if you need to assess which units are behind a particular cover.
  • EmptyCoverSpotCount(): Determines how many cover spots are currently unoccupied. Useful when you want to know how many units can still take cover behind a specific barrier.

Wrapping up this section

The CoverController acts as the manager of the entire cover Item or Structure. It doesn’t just track which cover spots are occupied, but it also manages how this information is visually conveyed to the player. With the ability to show and hide indicators, you can easily create intuitive gameplay mechanics. For instance, when a player moves their units close to a potential cover, the indicators light up, signaling available cover spots.

In the next section, we’ll explore how to integrate this CoverSpotConfigSO which stores configuration data for a cover spot. Stay tuned!

Photo of author

Author

With over two decades of experience in technical and developer support, Tom has expertise in troubleshooting APIs. Over the years, he has built a many websites and tools with a primary focus on web development technologies including C#, ASP.NET, Blazor, HTML, and CSS. Last year, Tom starting to learn game development and is currently working on his first game "Last Stand," a zombie base defense game designed in Unity 3D.