0

So, I've trying to make a 2D roguelike in Unity, I want to implement a pixel shadow based on sprites (I have a tile set containing all shadow tiles I may need), So I made that each Shadow had a "shadowType", to define either the shadow is coming from the top, bottom, etc. and I add them all to a Dictionary, with the keys being a 2x2 array (I had to declare a new class for the array), but when I try to call the ShadowType from the dictionary it gives a KeyNotFound Exception, I'd appreciate if I could get some help

ShadowObject script (apllied to all shadow prefabs):

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

public class ShadowObject : MonoBehaviour {

   public ShadowType shadowType;
}

public enum ShadowType 
{
    BottomEnd, Bottom, OutterCorner, Right, RightEnd, InnerConner, None
}   

BoardObject script (for now only defines wether a object should cast shadows or not):

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

public class BoardObject : MonoBehaviour {

    public bool castShadow = false;
}

GameManager script (calls the board initialization):

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

public class GameManager : MonoBehaviour {

    GameManager instance = null;
    BoardManager boardManager;

    void Awake () {
        if (instance == null)
            instance = this;
        else if (instance != this)
            Destroy (this);

        DontDestroyOnLoad (this);

        boardManager = GetComponent<BoardManager> ();
    }

    void Start () {
        boardManager.SetupsScene ();
    }
}

BoardManager script (Builds the Board, set ups the floor, walls and shadows):

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

public class BoardManager : MonoBehaviour {

    public int width, height;
    Camera cam;

    public GameObject[] floorTiles;
    public GameObject mainFloorTile;
    public GameObject[] wallTiles;
    public List<GameObject> shadowTiles;

    Transform boardHolder;
    List<Vector3> gridPositions = new List<Vector3>();
    Dictionary<Vector3, GameObject> boardObjects = new Dictionary<Vector3, GameObject>();

    #region ShadowHandler

//for handling 2x2 spaces, needed to know which shadow to instantiate
    class Matrix2 <T> { 
        public T[,] elements = new T[2,2];
        public Matrix2 () {}
        public Matrix2 (T m00, T m01, T m10, T m11){
            elements[0,0] = m00;
            elements[0,1] = m01;
            elements[1,0] = m10;
            elements[1,1] = m11;
        }
    }

//I tought that using this with the dictionary could solve the problem, it didn't
    class Matrix2EqualityComparer <T>: IEqualityComparer<Matrix2<T>> {

        public bool Equals (Matrix2<T> m1, Matrix2<T> m2){
            if (m1 == null && m2 == null)
                return true;
            else if (m1 == null || m2 == null)
                return false;
            else if (m1.elements == m2.elements)
                return true;
            else
                return false;
        }

        public int GetHashCode (Matrix2<T> mat){
            return base.GetHashCode ();
        }
    }

    static Matrix2EqualityComparer<bool> mat2EqC = new Matrix2EqualityComparer<bool> ();
    Dictionary<Matrix2<bool>, ShadowType> shadowListOrganizer = new Dictionary<Matrix2<bool>, ShadowType>(mat2EqC);

//adds all 16 posible states of the boardObjects to the dictioanry, with the shadowType that should be instantiate in that case
    void SetupShadowListOrganizer () {
        shadowListOrganizer.Clear ();
        shadowListOrganizer.Add (new Matrix2<bool> (false, false, false, false), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (false, false, false, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (false, false, true, false), ShadowType.RightEnd);
        shadowListOrganizer.Add (new Matrix2<bool> (false, false, true, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (false, true, false, false), ShadowType.BottomEnd);
        shadowListOrganizer.Add (new Matrix2<bool> (false, true, false, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (false, true, true, false), ShadowType.InnerConner);
        shadowListOrganizer.Add (new Matrix2<bool> (false, true, true, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (true, false, false, false), ShadowType.OutterCorner);
        shadowListOrganizer.Add (new Matrix2<bool> (true, false, false, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (true, false, true, false), ShadowType.Right);
        shadowListOrganizer.Add (new Matrix2<bool> (true, false, true, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (true, true, false, false), ShadowType.Bottom);
        shadowListOrganizer.Add (new Matrix2<bool> (true, true, false, true), ShadowType.None);
        shadowListOrganizer.Add (new Matrix2<bool> (true, true, true, false), ShadowType.InnerConner);
        shadowListOrganizer.Add (new Matrix2<bool> (true, true, true, true), ShadowType.None);
    }

    #endregion

    void Awake () {
        cam = Camera.main;
        cam.orthographicSize = height > width ? ( height + 2) / 2 + 1: ( width + 2 ) / 2 + 1;
        cam.transform.position = new Vector3(width / 2, height / 2, -10f);
    }

    void InitialiseList() {
        gridPositions.Clear ();

        for (int y = 0; y < height; y++){
            for (int x = 0; x < width; x++){
                gridPositions.Add (new Vector3 (x, y, 0f));
            }
        }
    }

    void BoardSetup () {
        boardHolder = Instantiate (new GameObject ("BoardHolder").transform);

        for (int y = -1; y <= height; y++){
            for (int x = -1; x <= width; x++){
                GameObject toInstantiate = ( x == -1 || y == -1 || x == width || y == height ) ?
                    wallTiles[Random.Range (0, wallTiles.Length)] :
                    Random.Range(0, 101) <= 66 ?
                    mainFloorTile :
                    floorTiles[Random.Range (0, floorTiles.Length)];
                GameObject instance = Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
                instance.transform.SetParent (boardHolder);
                boardObjects.Add (new Vector3 (x, y, 0f), instance);
            }
        }
    }

    void SetupShadow () {
        SetupShadowListOrganizer ();

        for (int y = 0; y <= height; y++){ //this loop will go on for a 2x2 grid, with the (x, y) tile being the right bottom corner of that grid
            for (int x = 0; x <= width; x++){
                bool m00 = boardObjects[new Vector3 (x - 1, y + 1, 0f)].GetComponent<BoardObject>().castShadow;
                bool m01 = boardObjects[new Vector3 (x, y + 1, 0f)].GetComponent<BoardObject>().castShadow;
                bool m10 = boardObjects[new Vector3 (x - 1, y, 0f)].GetComponent<BoardObject>().castShadow;
                bool m11 = boardObjects[new Vector3 (x, y, 0f)].GetComponent<BoardObject>().castShadow;
                GameObject toInstantiate = shadowTiles.SingleOrDefault (shadow => shadow.GetComponent<ShadowObject> ().shadowType == shadowListOrganizer[new Matrix2<bool> (m00, m01, m10, m11)]);
                if (toInstantiate == null)
                    continue;
                GameObject instance = Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity);
                instance.transform.SetParent (boardHolder);
            }
        }
    }

    public void SetupsScene () {
        InitialiseList ();
        BoardSetup ();
        SetupShadow ();
    }
}

1 Answers1

0

First of all, you don't pass your comparer to your dictionary indexer.

Second, you can't do it since indexing is not comparision.

Third, it would not work anyway.

object.Equals returns result of object.ReferenceEquals for reference types. Two different objects have two different references (and you create new Matrix2<T> every time). Two different instances of Matrix2<T> have two different instances of Matrix2<T>.elements, and == operator on two T[,] objects calls for Equals method (which calls ReferenceEquals), as well.

You have to override Matrix2<T>.Equals() method and compare content of Matrix2<T>.elements. Handy way to do so is Enumerable.SequenceEqual extention method.

Supert
  • 88
  • 1
  • 7
  • Already solved it, but thanks, since I wanted a way to store a 2 by 2 grid of boolean values I made so each tile got a number from 0 to 3, then , if it was true I would set a coeficients value for that tile to be 1, 0 otherwise, so I mulplied coeficient[i]*Mathf.Pow(2, i), so I would get a number between 0 and 15, then I added all posible states of the grid to the corresponding shadowType and made the ShadowListOrganizer an array instead of a dictioanry, so I could enter with the key I got from 0 to 15, it worked – João Vítor Costa Dec 15 '17 at 13:57