I am needing to do a lookup on a large bool set using x,y,z coordinates(integers only). I am trying to determine if a block is traversable at x,y,z location.
Currently I am using an array bool[,,]. However, this is not very flexible, and the size quickly gets massive for a decent sized map.
I thought a dictionary that only holds the true values would be much more flexible and less memory hungry. I created a struct Vector3Int to hold the x,y,z values and use as a dictionary key. Dictionary looks like Dictionary<Vector3Int, bool>.
However, doing Dictionary lookups with this key appears to be 20-100 times slower than the array lookups with x,y,z integers.
Is there a faster/better way to do this? I am using the lookups for pathfinding, so the lookup needs to be quite fast as there may be hundreds/thousands of lookups for a single path.
Vector3Int code:
public struct Vector3Int { public int x,y,z; public Vector3Int(int x, int y, int z) { this.x =x; this.y=y; this.z=z; } //checks for equality public static bool operator ==(Vector3Int a, Vector3Int b) { return a.x==b.x && a.y ==b.y && a.z ==b.z; } public override bool Equals(object obj) { return obj is Vector3Int && this == (Vector3Int)obj; } public override int GetHashCode () { return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); } //checks the two vectors for non-equality public static bool operator !=(Vector3Int a, Vector3Int b) { return !(a==b); } } Array lookup:
bool[,,] worldWalkable= new bool[1000,1000,1000]; public bool CheckWalkable(int x, int y, int z) { return worldWalkable[x,y,z]; } Vs Dictionary Lookup:
Dictionary<Vector3Int, bool> worldTraversable = new Dictionary<Vector3Int, bool>(); public bool CheckTraversable(Vector3Int block) { bool tempBool; worldTraversable.TryGetValue(block, tempBool); return tempBool; } Test code:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class SpeedTest : MonoBehaviour { Dictionary<Vector3Int, bool> testDict; bool[,,] testArray; // Use this for initialization void Start () { InitializeContainers(); RunTest(); } void InitializeContainers() { testDict= new Dictionary<Vector3Int, bool>(1000); for(int i=0; i<10; i++) { for(int j=0; j<10; j++) { for(int k=0; k<10; k++) { testDict[new Vector3Int(i,j,k)]=true; } } } testArray=new bool[10,10,10]; } void RunTest() { bool tempBool; float timer1, timer2; timer1=Time.realtimeSinceStartup; for(int i=0; i<10; i++) { for(int j=0; j<10; j++) { for(int k=0; k<10; k++) { tempBool= testDict[new Vector3Int(i,j,k)]; } } } timer2=Time.realtimeSinceStartup; Debug.Log("Dictionary completion time: "+(timer2-timer1)*1000+"ms"); timer1=Time.realtimeSinceStartup; for(int i=0; i<10; i++) { for(int j=0; j<10; j++) { for(int k=0; k<10; k++) { tempBool=testArray[i,j,k]; } } } timer2=Time.realtimeSinceStartup; Debug.Log("Array completion time: "+(timer2-timer1)*1000+"ms"); } } Edit: Revised struct that fixes the problem:
using UnityEngine; using System.Collections; using System; using System.Collections.Generic; //makes a Vector3 of integers public struct Vector3Int : IEquatable<Vector3Int> { public int x,y,z; public Vector3Int(int x, int y, int z) { this.x =x; this.y=y; this.z=z; } public bool Equals(Vector3Int other) { return other.x==this.x && other.y==this.y && other.z==this.z; } public static bool operator ==(Vector3Int a, Vector3Int b) { return a.Equals(b); } public override bool Equals(object obj) { if(obj==null || !(obj is Vector3Int)) return false; return Equals((Vector3Int)obj); } public override int GetHashCode () { return x ^ (y<<10) ^ (z<<10); } public override string ToString () { return string.Format ("("+x+", "+y+", "+z+")"); } public static bool operator !=(Vector3Int a, Vector3Int b) { return !(a==b); } } The issue was boxing/unboxing like Alexei suggested. Used the directions from this link to fix the issue.
O(1)falsevalues in anarray(ideally sorted) an just check whether the coordinate is in it or not. This would consume less space but is a little slowerreturn worldWalkable[x,y,z];Few other ideas which come to mind is, use a bitarray, or a sparse bitarray to store the information.