/// <summary>
    /// Generate a force in the current position of the prop
    /// </summary>
    /// <param name="pf"></param>
    public void GenerateForce(ref PotentialFieldScriptableObject pf)
    {
        int pX = pf.LocalPosX(transform.position);
        int pY = pf.LocalPosY(transform.position);

        pf.AddLinearForce(pX, pY, force, rad);
    }
    public void BuildLevelPrefab()
    {
#if (UNITY_EDITOR)
        //----- Data parse
        string   mapName    = mapFile.name;
        JSONNode n          = JSON.Parse(mapFile.text);
        int      height     = n["height"].AsInt;
        int      width      = n["width"].AsInt;
        int      tileWidth  = n["tilewidth"].AsInt;
        int      tileHeight = n["tilewidth"].AsInt;

        //---- Create static potential field map
        string sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
        string pfPath    = "Assets/Scenes/" + sceneName + "/Static PF-" + gameObject.name + ".asset";
        PotentialFieldScriptableObject pf = AssetDatabase.LoadAssetAtPath <PotentialFieldScriptableObject>(pfPath);
        if (pf == null)
        {
            if (!AssetDatabase.IsValidFolder("Assets/Scenes/" + sceneName))
            {
                AssetDatabase.CreateFolder("Assets/Scenes", sceneName);
            }
            pf = ScriptableObject.CreateInstance <PotentialFieldScriptableObject>();
            AssetDatabase.CreateAsset(pf, pfPath);
        }
        pf.Init(width, height);

        //----- Tile data load
        Dictionary <int, JSONNode> tilesetDataDictionary    = new Dictionary <int, JSONNode>();
        Dictionary <int, JSONNode> tileObjectDataDictionary = new Dictionary <int, JSONNode>();

        Debug.Log("Loading data...");
        foreach (JSONNode tileset in n["tilesets"].AsArray)
        {
            int    firstId  = tileset["firstgid"].AsInt;
            string source   = tileset["source"];
            string tilePath = "Assets/Other/Tiled/" + source;

            TextAsset tilesetJSON = AssetDatabase.LoadAssetAtPath <TextAsset>(tilePath);
            JSONNode  tilesetData = JSON.Parse(tilesetJSON.text);
            tilesetDataDictionary.Add(firstId, tilesetData);
            for (int i = 0; i < tilesetData["tilecount"].AsInt; i++)
            {
                JSONNode tileNode = tilesetData["tileproperties"]["" + i];
                if (tileNode.IsObject)
                {
                    JSONNode tileObjectData = tileNode;
                    tileObjectDataDictionary.Add(i + firstId, tileObjectData);
                }
            }
        }

        //----- Creating base root map object on scene
        Debug.Log("Loading map '" + mapName + "'...");
        GameObject prev = GameObject.Find(mapName);
        if (prev)
        {
            Debug.Log("Removing previous map object...");
            Undo.DestroyObjectImmediate(prev);
        }
        GameObject rootObject = new GameObject(mapName);

        //----- Popullating map
        foreach (JSONNode layer in n["layers"].AsArray)
        {
            float tileY         = layer["properties"]["unityHeight"].AsFloat;
            bool  levelMapCheck = layer["properties"]["pathLayer"].AsBool;

            //------- Tiled Ground layer
            for (int i = 0; i < layer["data"].Count; i++)
            {
                Vector3 tilePosition = Vector3.zero;
                tilePosition.x = i % width;
                tilePosition.z = -i / width;
                tilePosition.y = tileY;
                int id = layer["data"][i];
                if (id != 0)
                {
                    JSONNode tileObjectData;
                    if (tileObjectDataDictionary.TryGetValue(id, out tileObjectData))
                    {
                        string unityObject = tileObjectData["unityObject"];
                        if (unityObject != null)
                        {
                            GameObject prefab = InstantiatePrefab(unityObject);

                            if (prefab)
                            {
                                prefab.transform.position = tilePosition;
                                prefab.transform.parent   = rootObject.transform;
                            }
                        }

                        // Layer modifies static potential field?
                        if (levelMapCheck)
                        {
                            bool walkable = tileObjectData["walkable"];
                            int  pX       = i % pf.Width;
                            int  pY       = i / pf.Width;
                            if (!walkable)
                            {
                                pf.AddLinearForce(pX, pY, -6, 3);
                                pf.SetCellValue(pX, pY, PotentialFieldScriptableObject.BLOCKED);
                            }
                        }
                    }
                }
            }

            //------ Tiled Object layer
            for (int i = 0; i < layer["objects"].Count; i++)
            {
                JSONNode tileObject   = layer["objects"][i];
                Vector3  tilePosition = Vector3.zero;
                tilePosition.x = tileObject["x"].AsInt / tileWidth;
                tilePosition.z = 1 - tileObject["y"].AsInt / tileHeight;
                tilePosition.y = tileY;
                int      id         = tileObject["gid"];
                JSONNode properties = tileObject["properties"];

                // By unity object
                if (id != 0)
                {
                    JSONNode tileObjectData;
                    if (tileObjectDataDictionary.TryGetValue(id, out tileObjectData))
                    {
                        string unityObject = tileObjectData["unityObject"];

                        Debug.Log("Creating " + unityObject);
                        if (unityObject != null)
                        {
                            GameObject prefab = InstantiatePrefab(unityObject);
                            if (prefab)
                            {
                                prefab.transform.position = tilePosition;
                                prefab.transform.parent   = rootObject.transform;

                                // Set special object properties from tiled data
                                switch (unityObject)
                                {
                                case "endpointPrefab":
                                    prefab.GetComponent <EndpointController>().nextLevel = GetTiledProperty("nextLevel", properties, id, tileObjectDataDictionary);
                                    break;

                                case "keyPrefab":
                                    prefab.GetComponent <KeyController>().outSignalId = GetTiledProperty("outSignal", properties, id, tileObjectDataDictionary).AsInt;
                                    break;

                                case "doorPrefab":
                                    prefab.GetComponent <DoorController>().inSignalId = GetTiledProperty("inSignal", properties, id, tileObjectDataDictionary);
                                    prefab.GetComponent <DoorController>().isOpen     = GetTiledProperty("open", properties, id, tileObjectDataDictionary);
                                    break;

                                case "gatePrefab":
                                    prefab.GetComponent <DoorController>().inSignalId = GetTiledProperty("inSignal", properties, id, tileObjectDataDictionary).AsInt;
                                    prefab.GetComponent <DoorController>().isOpen     = GetTiledProperty("open", properties, id, tileObjectDataDictionary).AsBool;
                                    break;

                                case "dialogZonePrefab":
                                    prefab.GetComponent <DialogZoneController>().dialogCanvas.dialogTitle = GetTiledProperty("textTitle", properties, id, tileObjectDataDictionary);
                                    prefab.GetComponent <DialogZoneController>().dialogCanvas.dialogBody  = GetTiledProperty("textBody", properties, id, tileObjectDataDictionary);
                                    break;
                                }

                                // Set object facing direction
                                if (GetTiledProperty("direction", properties, id, tileObjectDataDictionary) != null)
                                {
                                    int dir = GetTiledProperty("direction", properties, id, tileObjectDataDictionary);// properties["direction"].AsInt;
                                    prefab.transform.rotation = Quaternion.AngleAxis(-dir * 90, Vector3.up);
                                }

                                // Check for walkable flag
                                bool walkable = GetTiledProperty("walkable", properties, id, tileObjectDataDictionary);
                                if (!walkable)
                                {
                                    int range = GetTiledProperty("blockSize", properties, id, tileObjectDataDictionary) - 1;
                                    Debug.Log("Trying " + (tileObject["x"].AsInt / tileWidth) + " " + tileObject["y"].AsInt / tileHeight);
                                    pf.SetSquareAreaValue(tileObject["x"].AsInt / tileWidth, (tileObject["y"].AsInt / tileHeight) - 1, PotentialFieldScriptableObject.BLOCKED, range);
                                }
                            }
                        }
                    }
                }
                else
                {
                    // By types
                    string type = tileObject["type"];
                    switch (type)
                    {
                    case "Spawner": {
                        GameObject prefab = (GameObject)PrefabUtility.InstantiatePrefab(spawnerPrefab);
                        tilePosition.z           -= 1;
                        prefab.transform.position = tilePosition;
                        prefab.transform.parent   = rootObject.transform;
                        string enemy = properties["spawnObject"];
                    } break;

                    case "Enemy Check": {
                        GameObject prefab = (GameObject)PrefabUtility.InstantiatePrefab(enemyDetectorPrefab);
                        Debug.Log("Width: " + tileObject["width"].AsFloat);
                        Debug.Log(tilePosition.x);
                        tilePosition.z -= 1;
                        tilePosition.x += (1f * tileObject["width"].AsFloat / 64) / 2 - 0.5f;
                        Debug.Log(tilePosition.x);
                        tilePosition.z             -= (1f * tileObject["height"].AsFloat / 64) / 2 - 0.5f;
                        prefab.transform.position   = tilePosition;
                        prefab.transform.localScale = new Vector3(1f * tileObject["width"].AsInt / 64, 1, 1f * tileObject["height"].AsInt / 64);
                        prefab.transform.parent     = rootObject.transform;
                        EnemyDetectorController edc = prefab.GetComponent <EnemyDetectorController>();
                        edc.outSignalId = properties["outSignal"].AsInt;
                    } break;
                    }
                }
            }
        }

        // Set the static potential field reference
        GetComponent <LevelManager>().SetStaticPotentialField(pf);
        EditorUtility.SetDirty(pf);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

        Undo.RegisterCreatedObjectUndo(rootObject, "Created map");
#endif
    }