Does unity process "false" if statements?

Hi all, please bear with me on this, I tried searching for the answer, but struggling to phrase the question right. Here goes…

I’m making a zombie game, and writing the AI for the zombies. There’re a lot of them, and the AI script is quite long, so I want to cut down the processing spent on them when they’re far from the player.

Do I have to make a separate script that measures distance between zombie and player, that turns the AI script on and off? I can do that, but that’s an extra script per NPC, per frame, measuring distance.

However, I already do the measuring at the beginning of the existing AI script. My question is - if I put all the rest of the script in an “if” statement tied to distance, will all those lines of code be read and processed if the distance is too great (the statement is false)? If not, it’s be cheaper to stick with the one script, with only a few lines being read. If the whole script is read and processed anyway, I’d be better off with two scripts, one turning the other on and off.
Anyone able to help please? Sorry for the long winded explanation :wink:
Regards
Ian

Nothing is executed in the scope of a “if(false)”. So that would solve your problem.

However, I’d like to make a suggestion. First, you should do an AI loop on a certain frequency, not each frame. So, coroutines. The closer the player is, the lower the frequency must be, obviously.

But instead of computing the distance, which can become quite heavy (even without the sqrt), you could put several game objects under your player, each one with a sphere collider. The first with a radius of five, that’s very close from the player, then 20, then 50 etc. That way, your AI can adjust its frequency depending of which collider it enters, or leave. You could modify the complexity of the AI as well.

No, Unity or Mono / .NET doesn’t execute the content of an if statement that is false. That’s the point of an if statement :wink:

If you worry about performance you might want to put your code in a CoUpdate function. A coroutine which just runs slower than Update.

function Start()
{
    CoUpdate();
}

function CoUpdate()
{
    while(true)
    {
        // Your code here
        yield new WaitForSeconds(0.1);
    }
}

This will make your code only being executed 10 times per sec.

You can also use InvokeRepeating(Fattie would suggest this first), but i don’t like it :wink:

One more thought, based on the fact you need to do distance checks to work stuff out, a good way around that is to use a simplified 2D representation of the world to see if something is close to the player. For instance you could check if the enemy was within 40 and 80 world units of the player (in x and z) by dividing the world into 40 world unit squares and seeing if the player is in the current cell or any adjacent one. This doesn’t require square roots and only requires that each item writes and removes itself from the grid as it moves. This is also a good technique for lots of things that involve proximity and the like. For instance I use it to keep 100s of characters apart without raycasts or built in collision detection.

I’ve built a simple(ish) class to support it.

#SupportClasses.cs

public class DefaultDictionary< TK,TR > : Dictionary< TK,TR>
{
    public new virtual TR this[TK index]
    {
        get
        {
            if (ContainsKey(index))
            {
                return base[index];
            }
            return default(TR);

        }
        set
        {
            base[index] = value;
        }
    }

    public T Get< T >(TK index) where T : TR
    {
        return (T)this[index];
    }



}


public class Index< TK,TR > : DefaultDictionary< TK,TR > where TR : class, new()
{

    public event Action< TK, TR, TR> Setting = delegate { };
    public event Action< TK, TR> Getting = delegate { };

    public override TR this[TK index]
    {
        get
        {
            if (ContainsKey(index))
            {
                return base[index];
            }
            var ret = new TR();
            if (ret is INeedParent)
            {
                (ret as INeedParent).SetParent(this, index);
            }
            base[index] = ret;
            Getting(index, ret);
            return ret;
        }
        set
        {
            if (Setting != null)
            {
                TR current = null;
                if (base.ContainsKey(index))
                {
                    current = base[index];
                }
                Setting(index, current, value);
            }
            base[index] = value;
        }
    }
}

#CollisionGrid.cs

using UnityEngine;
using System.Linq;
using System.Collections.Generic;
using System;

public class GridCellPosition
{
	public int z;
	public int x;
	
	static readonly Index< int, Index< int, GridCellPosition>> cache = new Index< int, Index< int, GridCellPosition>>();
	
	public static GridCellPosition Get(int x, int z)
	{
		GridCellPosition cell;
		if(!cache[x].TryGetValue(z, out cell))
		{
			cell = new GridCellPosition
			    {
			        x = x,
			        z = z
			    };
		    cache[x][z] = cell;
			
		}
		return cell;
	}
	
	public static implicit operator GridCellPosition(Vector3 position)
	{
		return Get(Mathf.FloorToInt(position.x),
			Mathf.FloorToInt(position.z));
	}


	public GridCellPosition Offset(int offsetX, int offsetZ)
	{
		return Get(x + offsetX, z + offsetZ );
	}
	
	public static GridCellPosition operator / (GridCellPosition pos, int value)
	{
		return Get(pos.x / value, pos.z / value );
	}
	
	public static GridCellPosition operator * (GridCellPosition pos, int value)
	{
		return Get(pos.x * value,  pos.z * value );
	}
	
}


public class CollisionGrid< T>
{
	public int size = 5;
	public virtual bool Add(GridCellPosition position, T item) {return false; }
	public virtual IEnumerable< T> Get(GridCellPosition position) { return null; }
	public virtual IEnumerable< T> Get(GridCellPosition position, float width, float height) {return null;}
	
	public IEnumerable< T> this[GridCellPosition position]
	{
		get
		{
			return Get(position);
		}
	}

	public virtual bool CheckCell(GridCellPosition position) { return false; }

    readonly List< T> _emptyList = new  List<T>();
	
	public IEnumerable< T> this[Component position]
	{
		get
		{
		    return position == null ? _emptyList : Get(position.transform.position);
		}
	}
	
	public virtual bool Add(T item)
	{
	    if (item == null)
	        throw new Exception("Trying to add null to a grid");
        if (item is Transform)
        {
            return Add((item as Transform).position, item);
        }
		if(item is Component)
		{
			return Add((item as Component).transform.position, item);
		}
	    if(item is GameObject)
	    {
	        return Add((item as GameObject).transform.position, item);
	    }
	    throw(new Exception("Cannot get a position from " + item.GetType().FullName));
	}
	public virtual void Clear() {}
	public virtual void Remove(T item) {}
	public virtual void Remove(GridCellPosition position, T item) {}
	
}

public class SparseCollisionGrid< T>  : CollisionGrid< T> {
    readonly Index< GridCellPosition, HashSet<T>> _grid = new Index< GridCellPosition, HashSet< T>>();
	
	public override bool Add(GridCellPosition position, T item)
	{
		position /= size;
		var result = InternalCheck(position, item);
		_grid[position].Add(item);
		return result;
	}
	
	public override void Remove(GridCellPosition position, T item)
	{
		position /= size;
		_grid[position].Remove(item);
	}
	
	public override void Remove(T item)
	{
	    if (item is Transform)
	    {
	        Remove((item as Transform).position, item);
	    }
	    if(item is Component)
		{
			Remove((item as Component).transform.position, item);
		}
		else if(item is GameObject)
		{
		    Remove((item as GameObject).transform.position, item);
		}
		else throw(new Exception("Cannot get a position from " + item.GetType().FullName));
	}
	
	public override IEnumerable< T> Get(GridCellPosition position)
	{
		position /= size;
		//var list = Factory.New< List< T>>();
	    var list = new List< T>();
		list.AddRange(_grid[position.Offset(0,0)]);
		list.AddRange(_grid[position.Offset(0,1)]);
		list.AddRange(_grid[position.Offset(1,0)]);
		list.AddRange(_grid[position.Offset(1,1)]);
		list.AddRange(_grid[position.Offset(-1,0)]);
		list.AddRange(_grid[position.Offset(0,-1)]);
		list.AddRange(_grid[position.Offset(1,-1)]);
		list.AddRange(_grid[position.Offset(-1,1)]);
		list.AddRange(_grid[position.Offset(-1,-1)]);
		return list;
	}
	
	public override IEnumerable< T> Get (GridCellPosition position, float width, float height)
	{
		width = Mathf.FloorToInt(width/size)+1;
		height = Mathf.FloorToInt(height/size)+1;
		position /= size;
		//var list = Factory.New< List< T>>();
	    var list = new List< T>();
		for(var x = 0; x < width + 2; x++)
		{
			for(var z = 0; z < height+2; z++)
			{
				var result = _grid[position.Offset(x, -z)];
				if(result!=null)
					list.AddRange(result);
			}
		}
		return list;
	}
	
	
	
	public override bool CheckCell(GridCellPosition position)
	{
		return _grid[position].Count > 0;
	} 
	
	
	
	public override void Clear()
	{
		_grid.Clear();
	}
	
}

#Using it

You use it by defining a collision grid and giving it a size

 public static CollisionGrid< AnyScriptOrComponent> collisionGrid = new SparseCollisionGrid< AnyScriptOrComponent>();
 ...
 collisionGrid.size = 40;

Then thing that wants to be detected adds and removes itself as it moves (removing first really)

 void Update()
 {
      collisionGrid.Remove(this);
      ...
      transform.position += Vector3.right * 2;
      ...
      collisionGrid.Add(this);
 }

Then to get all of the items within adjacent cells (or the current cell)

  foreach(var item in collisionGrid[this])
  {
      if(item == this) continue;
      //Do something with the neighbour
  }

If you were just looking for the player then you could not add the enemies at all and just have the player in there, then its a simple check

  if(collision.CheckCell(transform.position))
  {
      //Player is close
  }
  else
  {
      //Not so much
  }