Hello, I have been working on implementing a fog of war feature, similar to CodeMonkey’s version shown in his 25-hour XCOM game but I’ve been running into an issue. I’ve been receiving a NullReferenceException on this FogOfWarVisual script when I call the
public void HideAllGridPositions()
{
for (int x = 0; x < LevelGrid.Instance.GetWidth(); x++)
{
for (int z = 0; z < LevelGrid.Instance.GetHeight(); z++)
{
Debug.Log("Hiding GridPositions!");
fogOfWarVisualSingleArray[x, z].Show();
}
}
}
I’ve been replicating the GridSystemVisual but I always am getting this issue.
Here are my scripts if anyone was wanting to try and replicate. I created the an empty game object and added a quad as the child which serves as my fog of war visual.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FogOfWarVisual : MonoBehaviour
{
public static FogOfWarVisual Instance { get; private set; }
[SerializeField] private Transform FogOfWarVisualSinglePrefab;
[SerializeField] private FogOfWarVisualSingle[,] fogOfWarVisualSingleArray;
private void Awake()
{
if (Instance != null)
{
Debug.LogError("More than one FogOfWarVisual" + transform + " - " + Instance);
Destroy(gameObject);
return;
}
Instance = this;
}
private void Start()
{
fogOfWarVisualSingleArray = new FogOfWarVisualSingle[
LevelGrid.Instance.GetWidth(),
LevelGrid.Instance.GetHeight()];
for(int x = 0; x<LevelGrid.Instance.GetWidth(); x++)
{
for(int z = 0; z<LevelGrid.Instance.GetHeight(); z++)
{
GridPosition gridPosition = new GridPosition(x,z);
Transform fogOfWarVisualSingleTransform =
Instantiate(FogOfWarVisualSinglePrefab, LevelGrid.Instance.GetWorldPosition(gridPosition), Quaternion.identity);
fogOfWarVisualSingleTransform.parent = transform;
//This literally matches the Grid System Visual WHY WONT IT WORK
fogOfWarVisualSingleArray[x,z] = fogOfWarVisualSingleTransform.GetComponent<FogOfWarVisualSingle>();
}
}
}
//Hide all Grid positions, which means you show the Fog
public void HideAllGridPositions()
{
for (int x = 0; x < LevelGrid.Instance.GetWidth(); x++)
{
for (int z = 0; z < LevelGrid.Instance.GetHeight(); z++)
{
Debug.Log("Hiding GridPositions!");
fogOfWarVisualSingleArray[x, z].Show();
}
}
}
//Show the GridPositions, which means hiding certain Fog
public void ShowGridPositionList(List<GridPosition> fogPositionList)
{
foreach(GridPosition gridPosition in fogPositionList)
{
fogOfWarVisualSingleArray[gridPosition.x,gridPosition.z].Hide();
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CodeMonkey.Utils;
public class FogOfWar : MonoBehaviour {
[SerializeField] private LayerMask obstaclesLayerMask;
private void Start()
{
UnitManager.Instance.OnAnyUnitMovedGridPosition += UnitManager_OnAnyUnitMovedGridPosition;
UpdateAllFogOfWar();
}
private void UnitManager_OnAnyUnitMovedGridPosition(object sender, System.EventArgs e)
{
UpdateAllFogOfWar();
}
private void UpdateAllFogOfWar()
{
FogOfWarVisual.Instance.HideAllGridPositions();
List<GridPosition> revealedGridPositionList = new List<GridPosition>();
foreach(Unit unit in UnitManager.Instance.GetFriendlyUnitList())
{
GridPosition unitGridPosition = unit.GetGridPosition();
var unitWorldPosition = LevelGrid.Instance.GetWorldPosition(unitGridPosition);
revealedGridPositionList.Add(unitGridPosition);
TestFogOfWarOnPosition(unitWorldPosition, ref revealedGridPositionList);
List<GridPosition> neighbourGridOffsetList = new List<GridPosition>
{
new GridPosition(+1, +0),
new GridPosition(-1, +0),
new GridPosition(+0, +1),
new GridPosition(+0, -1),
new GridPosition(+1, +1),
new GridPosition(-1, +1),
new GridPosition(+1, -1),
new GridPosition(-1, -1),
};
foreach(GridPosition neighbourGridOffset in neighbourGridOffsetList)
{
GridPosition neighbourGridPosition = unitGridPosition + neighbourGridOffset;
if(LevelGrid.Instance.IsValidGridPosition(neighbourGridPosition))
{
//Valid Position
Vector3 neighbourWorldPosition = LevelGrid.Instance.GetWorldPosition(neighbourGridPosition);
TestFogOfWarOnPosition(neighbourWorldPosition, ref revealedGridPositionList);
}
}
}
FogOfWarVisual.Instance.ShowGridPositionList(revealedGridPositionList);
/*
//Show/Hide all enemies in the revealed grid positions
foreach (Unit enemyUnit in UnitManager.Instance.GetEnemyUnitList())
{
if (revealedGridPositionList.Contains(enemyUnit.GetGridPosition())) {
// Enemy visible
enemyUnit.ShowVisual();
} else {
// Enemy invisible
enemyUnit.HideVisual();
}
}
*/
}
private void TestFogOfWarOnPosition(Vector3 unitWorldPosition, ref List<GridPosition> revealedGridPositionList)
{
Vector3 baseDir = new Vector3(1,0,0);
float angleIncrease = 10;
for(float angle = 0; angle<360; angle += angleIncrease)
{
Vector3 dir = UtilsClass.ApplyRotationToVectorXZ(baseDir, angle);
float viewDistanceMax = 14f;
float viewDistanceIncrease = .4f;
for(float viewDistance = 0f; viewDistance<viewDistanceMax; viewDistance += viewDistanceIncrease)
{
Vector3 targetPosition = unitWorldPosition + dir * viewDistance;
GridPosition targetGridPosition = LevelGrid.Instance.GetGridPosition(targetPosition);
foreach(Unit unit in UnitManager.Instance.GetFriendlyUnitList())
{
GridPosition unitGridPosition = unit.GetGridPosition();
if(LevelGrid.Instance.IsValidGridPosition(targetGridPosition))
{
//Valid Grid Position
if(ObstacleInTheWay(unitGridPosition, targetGridPosition)) break;
}
if(!revealedGridPositionList.Contains(targetGridPosition))
{
revealedGridPositionList.Add(targetGridPosition);
}
}
}
}
}
private bool ObstacleInTheWay(GridPosition unitGridPosition, GridPosition targetGridPosition)
{
// Get the unit world position
var unitWorldPosition = LevelGrid.Instance.GetWorldPosition(unitGridPosition);
// Get the target world position
var targetWorldPosition = LevelGrid.Instance.GetWorldPosition(targetGridPosition);
// Get the direction to the target
var directionToTarget = (targetWorldPosition - unitWorldPosition).normalized;
// Get the distance to the target
var distanceToTarget = Vector3.Distance(unitWorldPosition, targetWorldPosition);
// Create the ray - with height offset
var offset = Vector3.up * 1f; // <- magic number. sorry
var ray = new Ray(unitWorldPosition + offset, directionToTarget);
// Check if there is an obstacle in the way and return
return Physics.Raycast(ray, distanceToTarget, obstaclesLayerMask);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FogOfWarVisualSingle : MonoBehaviour
{
[SerializeField] private MeshRenderer meshRenderer;
public void Show()
{
meshRenderer.enabled = true;
}
public void Hide()
{
meshRenderer.enabled = false;
}
}
I will continue to mess with it but if anyone has any suggestions I’m always willing to listen!


