Exemplo n.º 1
0
    //based on your position and your linked flowfield, this method returns the vector you need to apply
    public int getValuefromObject(GameObject go)
    {
        /*
         * Q3 | Q0
         * -------
         * Q2 | Q1
         *
         *    +X
         * -Z    +Z
         *    -X
         */

        int id = go.GetInstanceID();

        custom_grid subGrid    = go.GetComponent <flowfield_pathfinding>().subGrid;
        int         grid_ratio = go.GetComponent <flowfield_pathfinding>().grid_ratio;

        int xCell = subGrid.worldToCell(go.transform.position).Item1 % grid_ratio; //10 is the number of cells per supergrid
        int zCell = subGrid.worldToCell(go.transform.position).Item2 % grid_ratio;

        if (xCell < 0) //compensate for negatives
        {
            xCell = grid_ratio + xCell;
        }

        if (zCell < 0)
        {
            zCell = grid_ratio + zCell;
        }

        //we have to transform our world grid coordinates (pos and neg) to the coordinates of the flowfield (pos only)
        switch (type)
        {
        case 0:
            break;

        case 1:
            xCell = xCell + grid_ratio;
            break;

        case 2:
            xCell = xCell + grid_ratio;
            zCell = zCell + grid_ratio;
            break;

        case 3:
            zCell = zCell + grid_ratio;
            break;
        }

        //DEBUG STUFF

        return(grid[xCell, zCell]);
    }
    // Update is called once per frame
    void Update()
    {
        if ((Path.Count > 0)) //is there still another item in the stack?
        {
            //Debug.Log("current_i = " + current_i + " current_j: " + current_j);

            //Are we at the next item in the stack?
            if ((superGrid.worldToCell(transform.position).Item1 == Path.Peek().first) && (superGrid.worldToCell(transform.position).Item2 == Path.Peek().second))
            {
                //dequeue Astar cell
                Path.Pop();
                current_i = superGrid.worldToCell(transform.position).Item1;
                current_j = superGrid.worldToCell(transform.position).Item2;

                int next_i;
                int next_j;

                if (Path.Count > 0)
                {
                    next_i = Path.Peek().first;
                    next_j = Path.Peek().second;
                }
                else
                {
                    next_i = superGrid.worldToCell(transform.position).Item1;
                    next_j = superGrid.worldToCell(transform.position).Item2;
                }
                getNextFlowfield(current_i, current_j, next_i, next_j);
                return;
            }
            else //if not at next grid spot
            {
                //if we are NOT still on track
                if ((current_i != superGrid.worldToCell(transform.position).Item1) || (current_j != superGrid.worldToCell(transform.position).Item2))
                {
                    //Debug.Log("crossed into a non-stack grid");
                    current_i = superGrid.worldToCell(transform.position).Item1;
                    current_j = superGrid.worldToCell(transform.position).Item2;
                    Path.Push(new Pair <int, int>(current_i, current_j)); //add our current grid space onto the stack, we will calculate a flowfield next frame
                }
            }
        }
        else //if the stack is empty
        {
            if ((transform.position - destination).magnitude > 5.0f) //if we are not at the destination
            {
                int current_i = superGrid.worldToCell(transform.position).Item1;
                int current_j = superGrid.worldToCell(transform.position).Item2;
                int next_i    = superGrid.worldToCell(transform.position).Item1;
                int next_j    = superGrid.worldToCell(transform.position).Item2;

                getNextFlowfield(current_i, current_j, next_i, next_j); //generate a flowfield for our current cell to the destination
                return;
            }
        }//while stack not empty
    }
    }//end getAStarPath

    //=====================================================================================================================//

    //Given a start and an end supergrid, we create compound flowfield between both grids and any adjacent tiles (if they are diagonal)
    public void getNextFlowfield(int curr_i, int curr_j, int nex_i, int nex_j)
    {
        //GetComponent<unit_behavior>().ff_table.deleteFF(gameObject.GetInstanceID()); //unlink the previous flowfield from this object's id

        int current_i = curr_i;
        int current_j = curr_j;
        int next_i    = nex_i;
        int next_j    = nex_j;

        int row_length = 0;
        int col_length = 0;
        int xOff       = 0; //offset for calculating global
        int zOff       = 0; //grid indices
        int destRow    = 0; //calculate local grid
        int destCol    = 0; //indices
        int type       = 0; //tells us which direction we are generating our flowfield in

        //this way we can figure out what cells are blocked when plotting a route
        generate_obstacle_grid obs = new generate_obstacle_grid();

        //row_length, col_length, xOff,zOff, and destrow and col depend
        //on which direction the next cell is in

        //[SE]
        if (current_i == next_i && current_j == next_j)
        {
            row_length = grid_ratio;
            col_length = grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j);
            destCol    = subGrid.worldToCell(destination).Item1 % grid_ratio;
            destRow    = subGrid.worldToCell(destination).Item2 % grid_ratio;

            if (destCol < 0) //deal with negatives
            {
                destCol = grid_ratio + destCol;
            }

            if (destRow < 0)
            {
                destRow = grid_ratio + destRow;
            }

            type = 0;
        }
        //[S][E]
        else if (current_i < next_i && current_j == next_j)
        {
            row_length = 2 * grid_ratio; //for dynamic sizing, use 10 * Math.abs(current_i - next_i)
            col_length = grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j);
            destCol    = grid_ratio / 2;       //these are fixed destinations, we need to dynamically
            destRow    = (2 * grid_ratio) - 1; //pick destinations based on which cells are blocked or not
            type       = 0;
        }
        //[ ][E]
        //[S][ ] 2.
        else if (current_i < next_i && current_j < next_j)
        {
            row_length = 2 * grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j);
            destCol    = (2 * grid_ratio) - 1;
            destRow    = (2 * grid_ratio) - 1;
            type       = 0;
        }
        //[E]
        //[S] 3.
        else if (current_i == next_i && current_j < next_j)
        {
            row_length = grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j);
            destCol    = (2 * grid_ratio) - 1;
            destRow    = grid_ratio / 2;
            type       = 0;
        }
        //[E][ ]
        //[ ][S] 4.
        else if (current_i > next_i && current_j < next_j)
        {
            row_length = 2 * grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i - 1);
            zOff       = grid_ratio * (current_j);
            destCol    = (2 * grid_ratio) - 1;
            destRow    = 0;
            type       = 1;
        }
        //[E][S] 5.
        else if (current_i > next_i && current_j == next_j)
        {
            row_length = 2 * grid_ratio;
            col_length = grid_ratio;
            xOff       = grid_ratio * (current_i - 1);
            zOff       = grid_ratio * (current_j);
            destCol    = grid_ratio / 2;
            destRow    = 0;
            type       = 1;
        }
        //[ ][S]
        //[E][ ] 6.
        else if (current_i > next_i && current_j > next_j)
        {
            row_length = 2 * grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i - 1);
            zOff       = grid_ratio * (current_j - 1);
            destCol    = 0;
            destRow    = 0;
            type       = 2;
        }
        //[S]
        //[E] 7.
        else if (current_i == next_i && current_j > next_j)
        {
            row_length = grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j - 1);
            destCol    = 0;
            destRow    = grid_ratio / 2;
            type       = 3;
        }
        //[S][ ]
        //[ ][E]
        else if (current_i < next_i && current_j > next_j)
        {
            row_length = 2 * grid_ratio;
            col_length = 2 * grid_ratio;
            xOff       = grid_ratio * (current_i);
            zOff       = grid_ratio * (current_j - 1);
            destCol    = 0;
            destRow    = (2 * grid_ratio) - 1;
            type       = 3;
        }

        //find the obstacles
        int[,] obstacle_grid = obs.Generate_grid(subGrid.cellSize, row_length, col_length, xOff, zOff);

        if (Path.Count == 0)                                               //if we are at the final supergrid location
        {
            destRow = subGrid.worldToCell(destination).Item1 % grid_ratio; //subgrid cells per supergrid
            destCol = subGrid.worldToCell(destination).Item2 % grid_ratio;

            //needs to be done for negative indices
            if (destRow < 0)
            {
                destRow = grid_ratio + destRow;
            }

            if (destCol < 0)
            {
                destCol = grid_ratio + destCol;
            }

            //allows us to flowfield in all 4 quadrants
            switch (type)
            {
            case 0:
                break;

            case 1:
                destRow = destRow + grid_ratio;
                break;

            case 2:
                destRow = destRow + grid_ratio;
                destCol = destCol + grid_ratio;
                break;

            case 3:
                destCol = destCol + grid_ratio;
                break;
            }
        }

        //get destination (find nearest unblocked cell)
        Pair <int, int> p = obs.find_nearest_unblocked(obstacle_grid, destRow, destCol, row_length, col_length);

        destRow = p.first;
        destCol = p.second;



        //make sure that the destination isn't entirely blocked
        //if it isn't, then we say that the cell is blocked
        switch (type)
        {
        case 0:
            if (destRow < grid_ratio && destCol < grid_ratio)
            {
                if (next_i != current_i || next_j != current_j)            //make sure we are not in the destination cell
                {
                    aStarBlocked.Add(new Pair <int, int>(next_i, next_j)); //
                    buffer++;                                              //expand our search grid
                    getAstarPath(ref Path);                                //recalculate path
                    return;
                }
            }
            break;


        case 1:
            //Debug.Log("Destrow is: " + destRow);
            //Debug.Log("Destcol is: " + destCol);
            if (destCol < grid_ratio && destRow >= grid_ratio)
            {
                aStarBlocked.Add(new Pair <int, int>(next_i, next_j)); //
                buffer++;                                              //expand our search grid
                getAstarPath(ref Path);                                //recalculate path
                return;
            }
            break;


        /*
         * case 2:
         * if (destRow >= grid_ratio && destCol >= grid_ratio)
         * {
         *  aStarBlocked.Add(new Pair<int, int>(next_i, next_j)); //
         *  buffer++; //expand our search grid
         *  getAstarPath(ref Path); //recalculate path
         *  return;
         * }
         * break;
         */


        case 3:
            if (destRow < grid_ratio && destCol >= grid_ratio)
            {
                aStarBlocked.Add(new Pair <int, int>(next_i, next_j)); //
                buffer++;                                              //expand our search grid
                getAstarPath(ref Path);                                //recalculate path
                return;
            }
            break;


        default: break;
        }



        //GENERATE FLOWFIELD WITH GIVEN PARAMETERS
        Djikstra dijk = new Djikstra();

        //Debug.Log("Type = " + type);
        //Debug.Log("row_length: " + row_length + " col_length: " + col_length);
        //Debug.Log("destCol: " + destCol + " destRow: " + destRow);
        int[,] dijkstra = dijk.generate_djikstra_grid(row_length, col_length, obstacle_grid, new Pair <int, int>(destCol, destRow));

        //these values contextualize our Dijkstra grid for future use
        djgrid.grid       = dijkstra;
        djgrid.row_length = row_length;
        djgrid.col_length = col_length;
        djgrid.type       = type;
        djgrid.xOff       = xOff;
        djgrid.zOff       = zOff;

        //if there is no path, mark this astar cell as blocked
        if (djgrid.getValuefromObject(gameObject) == -1)
        {
            //Debug.Log("next_i: " + next_i + " next_j: " + next_j);
            aStarBlocked.Add(new Pair <int, int>(next_i, next_j)); //
            buffer++;                                              //expand our search grid
            getAstarPath(ref Path);                                //recalculate path
            return;
        }
        else if (djgrid.getValuefromObject(gameObject) == 0) //if we have reached an objective, but this function is still active for some reason, reset our pathfinding
        {
            setDestination(destination);
            return;
        }

        Generate_Flowfield field_obj = new Generate_Flowfield();

        Vector3[,] field = field_obj.generate_flowfield(row_length, col_length, dijkstra, xOff, zOff, subGrid.cellSize);

        //these values also contextualize our flowfield for future use
        Flowfield ff = new Flowfield();

        ff.flowfield  = field;
        ff.row_length = row_length;
        ff.col_length = col_length;
        ff.type       = type;
        ff.xOff       = xOff;
        ff.zOff       = zOff;

        GetComponent <unit_behavior>().ff_table.addFF(gameObject.GetInstanceID(), ff);    //add flowfield to dictionary and link by ID
    }//end function