Help with Fire-Emblem style movement system.

Hello I’m trying to create a fire emblem-esque movement system. It works more or less finally, but there’s a severe problem. I’m working on creating the tiles that show where you can move. Basically I have an array of the entire map that controls which spots are moveable and which aren’t. Coroutines fire off the tile creation functions, which take a tile and query spots next to it to see if those spots are available to plunk down a tile on. I think this system will be great because once it’s done each tile can have a ‘breadcrumb’ list that the unit can access to get to that tile, instead of needing some big old pathfinding thing.

So here’s the problem. Each grid block has a ‘tilePresent’ variable, which is changed whether a tile is on there or not. This stops tiles from being created on top of other tiles and eating up tons of memory. But it’s not working! I cllick the unit and tiles upon tiles upon tiles… I mean it technically is functional but I worry that once it gets to 10 move spaces that would create so many tiles that it would just rip the RAM to shreds.

Here’s my code, see any problems? Also if anybody wants to see the entire game I’m sure I could put it on Github or whatever.

I’m not the most experienced coder either, so if I did something in there that’s stupid please tell me.

(Excuse the messiness, I really need to do some clean-up work):

UnitController

using UnityEngine;
using System.Collections;



public class UnitStats : MonoBehaviour {
 
    //All Unit Stats
    public int attack = 1;
    public int defense = 1;
    public int luck = 1;
    public int skill = 1;
    public int speed = 1;
    public int magic = 1;
    public int resistance = 1;
    public int move = 7;
    public int posX = 1;
    public int posZ = 1;
    public Transform blueTile;
    public GameObject gControl ;
    //public bool isFinished;

    IEnumerator OnMouseDown()
    {


            gControl = GameObject.FindGameObjectWithTag ("GameController");
        GameControllerBase controlCode = (GameControllerBase)gControl.GetComponent (typeof(GameControllerBase));
        //KILLS ALL PREVIOUS TILES
        GameObject[] tilesDoomed = GameObject.FindGameObjectsWithTag("Tile");
        for (int count = 0; count < tilesDoomed.Length; count++)
        {

            Destroy(tilesDoomed[count]);
            Debug.Log("Tile Destroyed");
        }


        for (int count = 0; count <= (controlCode.LevelRows - 1); count++)
        {
         
            for(int newCount = 0; newCount <= (controlCode.LevelColumns - 1); newCount++)
            {
                controlCode.levelMap[count, newCount].tileHereChange(false);
            }
         
        }

     
        TileCreation controlCreation = (TileCreation)gControl.GetComponent (typeof(TileCreation));

        Debug.Log ("Unit Clicked");

 
        yield return StartCoroutine (controlCreation.BeginCreation(posX, posZ, move));



    }
    /*
    IEnumerator TileCreate(int tileNum)
    {
        gControl = GameObject.FindGameObjectWithTag ("GameController");
        GameControllerBase controlCode = (GameControllerBase)gControl.GetComponent (typeof(GameControllerBase));

        Quaternion blankQ = new Quaternion (0f, 0f, 0f, 0f);
        Vector3 tilePos = new Vector3 (transform.position.x, transform.position.y, transform.position.z);
        tilePos.y -= 0.5f;


        Transform t = Instantiate (blueTile, tilePos, blankQ) as Transform;
        GameObject firstTile = t.gameObject;


        Debug.Log ("First Tile Created.");
        TileBehavior behave = (TileBehavior)firstTile.GetComponent (typeof(TileBehavior));
        behave.IsVisible = false;
        MeshRenderer renderer = (MeshRenderer)behave.GetComponent (typeof(MeshRenderer));
        renderer.enabled = false;
        //behave.tileNum = (tileNum - 1);

        behave.tilePos.x = (transform.position.x);
        behave.tilePos.y = (transform.position.y);
        behave.tilePos.z = (transform.position.z);
        behave.mapX = posX;
        behave.mapZ = posZ;
        controlCode.levelMap [posX, posZ].tileHereChange (true);
        /*
        yield return StartCoroutine(tileCreationController (t));
        //isFinished = true;
    }


    IEnumerator tileCreationController(Transform tile){
        GameObject firstTile = tile.gameObject;
        TileBehavior behave = (TileBehavior)firstTile.GetComponent (typeof(TileBehavior));
        int tileNumControl = (behave.tileNum + 1);
        yield return behave.makeMore ();
        tileNumControl--;


        for (int outCount = tileNumControl; outCount > 0; outCount--){


        GameObject[] availableTiles = GameObject.FindGameObjectsWithTag("Tile") ;
      

        TileBehavior[] tilesBehave = new TileBehavior[availableTiles.Length];
        //ArrayList.
        //    tilesBehave = (TileBehavior)availableTiles[].GetComponents (typeof(TileBehavior));
        //foreach (TilesBehavior availableTiles in tilesBehave)
     

        for (int count = 0; count < availableTiles.Length; count++)
        {
            tilesBehave[count] = (TileBehavior)availableTiles[count].GetComponent (typeof(TileBehavior));
        };


        for (int count = 0; count < availableTiles.Length; count++)
        {
            yield return tilesBehave[count].makeMore();
        }

        }

    }
        yield break;*/
}

map construction

    public class mapTiles
    {
        private bool clear;
        private float height;
        //private int defBonus;
        private string terType;
        private bool isPassable;
        private bool tilePresent;
     
        //ConstructorSafeAttribute Blank
        public mapTiles()
        {
            clear = true;
            height = 0;
            //defBonus = 0;
            terType = "Plains";
            isPassable = true;
            tilePresent = false;
         
         
        }
     
        public void newHeight(float newHeight)
        {
            height = newHeight;
        }
     
        public void changeClear(bool isClearIn)
        {
            clear = isClearIn;
            isPassable = isClearIn;
        }
     
        public void changeType(string newType)
        {
            terType = newType;
        }
     
        public float heightPlease(){
            return height;
        }
     
        public bool clearPlease(){
            return clear;
        }

        public void changePassable(bool isPass)
        {
            isPassable = isPass;

        }

        public bool passPlease(){
            return isPassable;
        }

        public void tileHereChange(bool tile){
            tilePresent = tile;
        }

        public bool tilePlease()
        {
            return tilePresent;
        }

    }
}

TileCreation

public class TileCreation : MonoBehaviour {


    public GameObject gControl;
    public Transform blueTile;


    public IEnumerator BeginCreation(int posX, int posZ, int tileNum){

        gControl = GameObject.FindGameObjectWithTag ("GameController");
        GameControllerBase controlCode = (GameControllerBase)gControl.GetComponent (typeof(GameControllerBase));
     
        Quaternion blankQ = new Quaternion (0f, 0f, 0f, 0f);
        Vector3 tilePos = new Vector3 (transform.position.x, transform.position.y, transform.position.z);
        tilePos.y -= 0.5f;
     
     
        Transform t = Instantiate (blueTile, tilePos, blankQ) as Transform;
        GameObject firstTile = t.gameObject;

        Debug.Log ("First Tile Created.");




        TileBehavior behave = (TileBehavior)firstTile.GetComponent (typeof(TileBehavior));
        behave.IsVisible = false;
        MeshRenderer renderer = (MeshRenderer)behave.GetComponent (typeof(MeshRenderer));
        renderer.enabled = false;
        //behave.tileNum = (tileNum - 1);
     
        behave.tilePos.x = (transform.position.x);
        behave.tilePos.y = (transform.position.y);
        behave.tilePos.z = (transform.position.z);
        behave.mapX = posX;
        behave.mapZ = posZ;
        behave.tileNum = tileNum;
        controlCode.levelMap [posX, posZ].tileHereChange (true);



        yield return StartCoroutine(tileCreationController (t));
        //isFinished = true;
    }
 
 
    IEnumerator tileCreationController(Transform tile){
        GameObject firstTile = tile.gameObject;
        TileBehavior behave = (TileBehavior)firstTile.GetComponent (typeof(TileBehavior));

        int tileNumControl = (behave.tileNum + 1);
        yield return behave.makeMore (behave.mapX, behave.mapZ);
        tileNumControl--;
     
     
        for (int outCount = tileNumControl; outCount > 0; outCount--){
         
         
            GameObject[] availableTiles = GameObject.FindGameObjectsWithTag("Tile") ;
         
         
            TileBehavior[] tilesBehave = new TileBehavior[availableTiles.Length];
     
         
         
            for (int count = 0; count < availableTiles.Length; count++)
            {
                tilesBehave[count] = (TileBehavior)availableTiles[count].GetComponent (typeof(TileBehavior));
            }
         
         
            for (int count = 0; count < availableTiles.Length; count++)
            {
                yield return tilesBehave[count].makeMore(tilesBehave[count].mapX, tilesBehave[count].mapZ);
             
            }
         
        }

        yield break;
    }
 
    }

public float whatIsHeight(int x, int z){

return levelMap[x, z].heightPlease();

}

}

TileBehavior

using UnityEngine;
using System.Collections;

public class TileBehavior : MonoBehaviour {


    public bool IsVisible;
    public int tileNum;
    public Vector3 tilePos;
    public int mapX;
    public int mapZ;
    public Transform blueTile;
    public GameObject gControl ;
    Quaternion blankQ = new Quaternion (0f, 0f, 0f, 0f);





    void tileMakerInside(int mapX, int mapZ, int tileNum)
    {
        gControl = GameObject.FindGameObjectWithTag ("GameController");
        GameControllerBase controlCode = (GameControllerBase)gControl.GetComponent (typeof(GameControllerBase));
        float newPositionX = gControl.transform.position.x + mapX - 0.5f;
        float newPositionZ = gControl.transform.position.z  + mapZ - 0.5f;
        float newPositionY = gControl.transform.position.y + controlCode.whatIsHeight(mapX, mapZ);
        Vector3 tilePosNew = new Vector3(newPositionX, newPositionY, newPositionZ);
     
        Transform t = Instantiate (blueTile, tilePosNew, blankQ) as Transform;
        GameObject firstTile = t.gameObject;

        TileBehavior behave = (TileBehavior)firstTile.GetComponent (typeof(TileBehavior));
 
        if (!controlCode.levelMap [mapX, mapZ].passPlease ()) {

            MeshRenderer renderer = (MeshRenderer)behave.GetComponent (typeof(MeshRenderer));
            renderer.enabled = false;
            behave.IsVisible = false;

        } else {
            MeshRenderer renderer = (MeshRenderer)behave.GetComponent (typeof(MeshRenderer));
            renderer.enabled = true;
            behave.IsVisible = true;
        }


        behave.tileNum = (tileNum - 1);

     
        behave.mapX = mapX;
        behave.mapZ = mapZ;

        controlCode.levelMap [mapX, mapZ].tileHereChange (true);

     
     
     
        Debug.Log ("Tile Created.");


    }

    public object makeMore(int mapX, int mapZ)
    {
        Debug.Log ("Making More...");
        gControl = GameObject.FindGameObjectWithTag ("GameController");
        GameControllerBase controlCode = (GameControllerBase)gControl.GetComponent (typeof(GameControllerBase));



        if (tileNum > 0)
        {
            //Creates a tile up 1.
            if (mapZ > 1)
            {
                if (!(controlCode.levelMap[mapX, (mapZ - 1)].tilePlease())){
                    tileMakerInside((mapX), (mapZ - 1), tileNum);
                }
            }
            else
            {
                Debug.Log ("Up Tile Canceled.");

            }


            //Creates a tile Left 1.
            if (mapX > 1)
            {
                    if (!(controlCode.levelMap[mapX, (mapZ - 1)].tilePlease())){
                    tileMakerInside((mapX - 1), mapZ, tileNum);
                    }
            }
            else
            {
                Debug.Log ("Left Tile Canceled.");

            }

            //Creates a tile down 1.
            if (mapZ < 10)
            {
                        if (!(controlCode.levelMap[mapX, (mapZ + 1)].tilePlease())){
                            tileMakerInside((mapX), (mapZ + 1), tileNum);

                        }
            }
            else
            {
                Debug.Log ("Down Tile Canceled.");

            }

            //Creates a tile right 1.
            if (mapX < 10)
            {
                if (!(controlCode.levelMap[(mapX + 1), mapZ].tilePlease()))
                {
                    tileMakerInside((mapX + 1), mapZ, tileNum);
                }
             
            }
            else
            {
                Debug.Log ("Right Tile Canceled.");

            }



        }
        return null;
    }
}

GameController

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

public class GameControllerBase : MonoBehaviour
{
    //Size of Level
    public static int LevelRows = 10;
    public static int LevelColumns = 10;
 
    public LevelMapper.mapTiles[,] levelMap = new LevelMapper.mapTiles[LevelRows, LevelColumns];
 
    // Use this for initialization
    void Start ()
    {
     
        //GameObject controlPoint = GameObject.FindGameObjectWithTag ("Origin");
     
        //This section creates the tile array.
     
        for (int count = 0; count <= (LevelRows - 1); count++)
        {
         
            for(int newCount = 0; newCount <= (LevelColumns - 1); newCount++)
            {
                levelMap[count, newCount] = new LevelMapper.mapTiles();
            }
         
        }
     
        Debug.Log ("Array Finished");
     
     
        //This Section Assigns values to the array.
        //THIS SECTION SHOULD BE CHANGED FOR EACH LEVEL
        //--------------------------------------------------------

        //First the Heights
        levelMap [4, 4].newHeight(1);
        levelMap [5, 4].newHeight(1);
        levelMap [4, 5].newHeight(1);
     
        //Next Obstacles Also changes if passable or not.
        levelMap [5, 5].changeClear (false);
     
        //next Types.
        levelMap [5, 5].changeType ("Mountain");

        //--------------------------------------------------------
     
        Debug.Log ("Array Created successfully.");
     


        //UnitStarter beginUnitPlacement = (UnitStarter)controlPoint.GetComponent (typeof(UnitStarter));
        beginUnitPlacement();
     
     
     
    }

    private void beginUnitPlacement()
    {

        //GameObject controlPoint = GameObject.FindGameObjectWithTag ("GameController");
     
     
        //Sorts the units into places.
        GameObject[] units = GameObject.FindGameObjectsWithTag("Unit");  //returns GameObject[]
     
        for (int count = 0; count < units.Length; count++)
        {

         
            Debug.Log("Unit Loaded");

            UnitStats stats;
            stats = units [count].GetComponent<UnitStats> ();
            float newPositionX = transform.position.x + stats.posX;
            float newPositionZ = transform.position.z + stats.posZ;
            float newPositionY = transform.position.y;
            float newHeight = whatIsHeight ((int)(stats.posX), (int)(stats.posZ));
         
            Vector3 startPos = new Vector3 ((newPositionX - 0.5f), (newHeight + 0.5f), (newPositionZ - 0.5f));
         
         
            units[count].transform.position = startPos;
            levelMap[((int)(stats.posX - 1)), ((int)(stats.posZ - 1))].changePassable(false);
                    }
     
        Debug.Log ("Units Placed");
    }

Upload a sample of the problem to dropbox or something and Ill try to take a look. I think it would be easier for me to play around with it myself to see what the problem may be :wink:

Here’s the link: Dropbox - File Deleted - Simplify your life

Hopefully I uploaded it right.

On screen you should see a cube, which is the unit I’m testing on. There’s also an invisible object that both controls the game and marks the corner of the game grid. The unit will snap to that grid at the start of the game. If you click it, the tiles will be created. It will only create them in two directions, since the character is in the corner and obviously can’t go off the map. That part is fine. What isn’t fine is the thousand tiles being placed over each other in the same places, and the craziness that happens if you click the same unit a second time. I’d sure appreciate any help!

I get a bunch of errors and what not when I had to upgrade your files to unity 5. I fixed the errors, but all that happens is each time I click the box, 1 tile spawns in the middle of the map.

The scripts you gave me in the download also don’t seem to match the ones you have above here. I had to copy and paste them in. I was also missing a script on the MovementTile object. I thought maybe it was the TileBehavior script so I copied it from here and put it on, but I am only getting 1 tile spawning.

I can’t really help if the files don’t work =(

Huh I don’t know why that is. But I did find the problem. What was going on was that every time the tile creation routine was fired, it accessed every tile, not just the ones on the outside. The coroutines were all messing with each other and creating junk. This

if (tilesBehave[count].tileNum == outCount)

was all I had to do, for each time the tile creation routine was fired. Thanks for your help anyways. And I did find the errors you had, the problem was I forgot to save the files before uploading so you got the mid-coded version.

Also, for the help of people using htis later, a MUCH more valid method for this code is to use a list of the items, and each time an item is created it is added to the list. The list is checked for new items for each loop of the creating process, and the new tiles are activated. This requires many less lookups and speeds it up way faster. I’ve changed to this process and it is MUCH better.