Skip to content

Instantly share code, notes, and snippets.

@sabresaurus
Last active June 18, 2026 16:47
Show Gist options
  • Select an option

  • Save sabresaurus/e9195cb5370ddb26f0b10a025ee4f893 to your computer and use it in GitHub Desktop.

Select an option

Save sabresaurus/e9195cb5370ddb26f0b10a025ee4f893 to your computer and use it in GitHub Desktop.
Cover System from Revengard
// MIT License
//
// Copyright (c) 2026 Sabresaurus
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using UnityEngine;
using System.Collections;
using UnityEngine.Assertions;
using System;
using System.Collections.Generic;
public class CoverSystem : SerializedSingleton<CoverSystem>
{
[SerializeField]
CoverQuery[] queries;
List<CoverNode> coverNodes;
public string[] GetAllQueryNames()
{
string[] names = new string[1 + queries.Length];
names[0] = "None";
for (int i = 0; i < queries.Length; i++)
{
names[i + 1] = queries[i].Name;
}
return names;
}
// Use this for initialization
void Start()
{
coverNodes = LevelController.Instance.CoverNodes;
Assert.IsTrue(coverNodes.Count >= 1, "There must be cover nodes in the level (game objects with the CoverNode script attached)");
}
public CoverQuery FindQueryByName(string name)
{
CoverQuery activeQuery = null;
for (int i = 0; i < queries.Length; i++)
{
if (queries[i].Name == name)
{
activeQuery = queries[i];
break;
}
}
return activeQuery;
}
public CoverNode FindCover(EnemyAgent currentAgent, Squad squad, string queryName)
{
CoverQuery activeQuery = null;
for (int i = 0; i < queries.Length; i++)
{
if (queries[i].Name == queryName)
{
activeQuery = queries[i];
break;
}
}
Assert.IsNotNull(activeQuery, "There must be a valid CoverQuery to use");
CoverNode bestNode = null;
float bestWeight = -1;
for (int i = 0; i < coverNodes.Count; i++)
{
float weight = coverNodes[i].CalculateWeightAndCache(activeQuery, currentAgent, squad);
if (weight > bestWeight)
{
bestWeight = weight;
bestNode = coverNodes[i];
}
}
if(bestWeight < activeQuery.MinimumWeight)
{
// Try a secondary query approach
if(!string.IsNullOrEmpty(activeQuery.FallbackQueryName))
{
return FindCover(currentAgent, squad, activeQuery.FallbackQueryName);
}
else
{
// No fallback to try
return null;
}
}
return bestNode;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment