IndexOutOfRangeException: Array Index is out of Range Unity - c#

I was trying to build a Pathfinding A* code, but keep getting an Array Index error. I have tried tweaking with the x and y, but no luck so far.
Here is the code.
public int columns = 9; //Columns and rows to set up the board
public int rows = 9; //This number are the usable tiles, the complete board is 11 by 11
//With a border of 1 tile
public Node[,] graph;
//Class Node
public class Node
{
public List<Node> neighbours; //List of all the neighbours nodes (4Directions)
public Node()
{
neighbours = new List<Node>();
}
}
//Sets up the outer walls and floor (background) of the game board.
void BoardSetup()
{
for (int x = -1; x < columns + 1; x++)
{
for (int y = -1; y < rows + 1; y++)
{
Edited out Code, don't think has anything to do with my problem.
}
}
}
//Creates the graph to use Pathfinding
void GeneratePathfindingGraph()
{
//Create graph
graph = new Node[columns, rows];
for (int x = -1; x < columns + 1; x++)
{
for (int y = -1; y < rows + 1; y++)
{
graph[x, y] = new Node();
Add the 4 cardinal adjacent tiles
if (x != - 1)
graph[x, y].neighbours.Add(graph[x - 1, y]);
if (x != columns - 1)
graph[x, y].neighbours.Add(graph[x + 1, y]); //Where I am getting the error
if (y != - 1)
graph[x, y].neighbours.Add(graph[x, y - 1]);
if (y != rows - 1)
graph[x, y].neighbours.Add(graph[x, y + 1]);
}
}
}
//SetupScene initializes our level and calls the previous functions to lay out the game board
public void SetupScene(int level)
{
//Creates the outer walls and floor.
BoardSetup();
//Creates the Node map to use Pathfinding
GeneratePathfindingGraph();
}
}
I have edited out most of the code in this class, I don't think it has much to do with the problem.

Can you change all the initialization in the loop like x = -1;to x = 0;
Arrays always start's with a ZERO.

Related

Problem with world generation in unity c#

I want to create a world generation using two noise maps (altitude noise and moisture noise). I create maps of these noises and set them in the inspector to values between 0 and 1.
I want to get result like this:
If Elevation < 1000
{
If Moisture < 50: Desert
Else Forest
}
And it seems that I did it as it should, but for some reason the generation does not work correctly:
Here is my code:
for (int x=0; x < tilemap.Width; x++)
{
for (int y = 0; y < tilemap.Height; y++)
{
// Get height at this position
var height = noiseMap[y * tilemap.Width + x];
var moisureHeight = moisureMap[y * tilemap.Width + x];
// Loop over our configured tile types
for (int i = 0; i < TileTypes.Length; i++)
{
var TileType = TileTypes[i];
for (var j = 0; j < TileType.MoisureValues.Length; j++)
{
// If the height is smaller or equal then use this tiletype
if (height <= TileType.Height)
{
if (moisureHeight <=TileType.MoisureValues[j].MoisureHeight)
{
tilemap.SetTile(x, y, (int)TileType.MoisureValues[j].GroundTile);
break;
}
}
}
}
}
}

Adding values to a list with an array

I'm trying to make a list using this class:
public class Edges
{
public int no_piece;
public int edge;
public int[,] edge_pixels;
}
This is to assemble a puzzle. I am trying to save the characteristics of each piece this way: no_piece - the number of the piece /// edge - which edge (top as '0', left as '1', bottom as '2' and right as '3') /// edge_pixels - the number of pixels for each channel, for example:
edge_pixels[0,x] would have the values of each pixel of an edge, of n piece);
This is the way I tried;
List<Edges> edges_list = new List<Edges>();
for (i = 0; i < number of pieces; i++)
{
for (y = vector_coordinates[i,1]; y < vector_coordinates[i,3]; y++)
{//vectors with top and bottom coordinates of the piece in the original image
for (x = vector_coordinates[i,0]; x < vector_coordinates[i,2]; x++)
{// the same goes for x but left and right
if (y == vector_coordinates[i, 1]) //top
{
for (aux_rgb = 0; aux_rgb < 3; aux_rgb++)
{
Edges edge = new Edges();
edge.no_piece = i;
edge.edge = 1;
edge.edge_pixels[aux_rgb, aux_count_pixel] = (int)dataPtr[aux_rgb];
edges_list.Add(edge);
}
}
aux_count_pixel++;
}
(...)
But it doesn't work and I donĀ“t understand why. I'm not sure if I made myself clear. Thank you
Try following.
List<Edges> edges_list = new List<Edges>();
for (i = 0; i < number of pieces; i++)
{
for (y = vector_coordinates[i,1]; y < vector_coordinates[i,3]; y++)
{//vectors with top and bottom coordinates of the piece in the original image
for (x = vector_coordinates[i,0]; x < vector_coordinates[i,2]; x++)
{// the same goes for x but left and right
if (y == vector_coordinates[i, 1]) //top
{
Edges edge = new Edges();
edges_list.Add(edge);
edge.no_piece = i;
for (aux_rgb = 0; aux_rgb < 3; aux_rgb++)
{
edge.edge = 1;
edge.edge_pixels[aux_rgb, aux_count_pixel] = (int)dataPtr[aux_rgb];
}
}
aux_count_pixel++;
}

Dijkstra's Algorithm Ineffeciencies on a Hex Grid, C#, Unity3D

I'm attempting to create a turn based strategy game using a 3D HexGrid map, I've implemented dijkstra's algorithm but it doesn't run 100% efficiently and I can't work out why. I also attempted to implement A* but have had to stop as I can't work out how to properly implement it, so any help with that would also be massively appreciated.
My unit passes it's GameObject and the Vector3 of it's target to the generate path function and each Node in the graph list is populated with its x,y,z and all of it's neighbors.
The inefficiencies are such that when moving; in a -X direction when on an odd Z plane or in a +X when on an even Z plane, an extra step is made, shown in the screenshots. Another Inefficiency is that when moving in the Z plane an extra step is often taken as the code seems to prefer keeping it's X value the same for as long as possible before approaching on the Z plane. This is leading to the unit being 1 tile further from the goal when it starts it's Z movement than it would have been has it moved 1 X negatively to start with.
I'll add my path generation code, neighbor generation code and my node class code as well as screenshots of where the inefficiencies are occurring as I know my explanations are unclear at best. The neighbor code ensures that the highest adjacent tile is the one stored as the neighbor (it also has to search through types as i have a variety of tile types.
Thank you so much in advance, to anyone that might be able to offer some help or insight in to what is going wrong.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Linq;
public class UnitMasterScript : MonoBehaviour {
// private int Number_of_neighbours = 6;
private int Number_of_neighbours = 6;
private GameObject[] Neighbours;
Node[,,] graph;
public bool MapMakerDone = false;
void Update()
{
if (MapMakerDone == true)
{
// Wait for MapMaker to change MapMakerDone to true then allow rest of script to run
GameObject Map = GameObject.Find("MapMaker");
int WidthVal = Map.GetComponent<MapMakerFromFile>().WidthVal;
int HeightVal = Map.GetComponent<MapMakerFromFile>().HeightVal;
int DepthVal = Map.GetComponent<MapMakerFromFile>().DepthVal;
// Graph of node generation code
// Code to find which hex is to each side of this hex
// Need to find hex to left, right, ul, ur, ll, lr
// Need to find hex at the top of the stack adjacent
// 0:L 1:R 2:UL 3:UR 4:LL 5:LR
graph = new Node[WidthVal, HeightVal, DepthVal];
for (int x = 0; x < WidthVal; x++)
{
for (int y = 0; y < HeightVal; y++)
{
for (int z = 0; z < DepthVal; z++)
{
graph[x, y, z] = new Node();
graph[x, y, z].x = x;
graph[x, y, z].y = y;
graph[x, y, z].z = z;
}
}
}
for (int x = 0; x < WidthVal; x++)
{
for (int y = 0; y < HeightVal; y++)
{
for (int z = 0; z < DepthVal; z++)
{
// Set up the x and y for the neighbour as the source so it can be used
int neighbourX = x;
int neighbourY = 0; // must always start from 0 to ensure a downstep isn't missed
int neighbourZ = z;
int neighbourType = 0;
int correct_type = 0;
GameObject Hex_Present_checker = null;
// First needs to check if there even is a tile at this coordinate location
for (neighbourType = 0; neighbourType < 5; neighbourType++)
{
Hex_Present_checker = GameObject.Find("Hex_" + x + "_" + y + "_" + z + "_" + neighbourType);
if (Hex_Present_checker != null)
{
correct_type = neighbourType;
}
Hex_Present_checker = null;
}
if (correct_type != 0)
{
neighbourType = correct_type;
// int Number_of_neighbours = 6;
// GameObject[] Neighbours;
Neighbours = new GameObject[Number_of_neighbours];
// For each value of each tile in neighbours find what the tile coordinates are in XYZ
for (int q = 0; q < Number_of_neighbours; q++)
{
// Finds X and Z values of the neighbours
if (q < 2)
{
if (q == 0) { neighbourX = x + 1; }
if (q == 1) { neighbourX = x - 1; }
}
if (z % 2 == 1)
{
if (q == 2) { neighbourX = x; neighbourZ = z + 1; }
if (q == 3) { neighbourX = x + 1; neighbourZ = z + 1; }
if (q == 4) { neighbourX = x; neighbourZ = z - 1; }
if (q == 5) { neighbourX = x + 1; neighbourZ = z - 1; }
}
else
{
if (q == 2) { neighbourX = x - 1; neighbourZ = z + 1; }
if (q == 3) { neighbourX = x; neighbourZ = z + 1; }
if (q == 4) { neighbourX = x - 1; neighbourZ = z - 1; }
if (q == 5) { neighbourX = x; neighbourZ = z - 1; }
}
// Checks for the highest tile for the XZ coordinate and gets its Y value
GameObject potential_highest_ring;
int highest_Y = 0;
int correct_neighbour_type = 0;
for (neighbourY = 0; neighbourY < HeightVal; neighbourY++)
{
for (neighbourType = 0; neighbourType < 5; neighbourType++)
{
potential_highest_ring = null;
potential_highest_ring = GameObject.Find("Hex_" + neighbourX + "_" + neighbourY + "_" + neighbourZ + "_" + neighbourType);
if (potential_highest_ring != null)
{
highest_Y = neighbourY;
correct_neighbour_type = neighbourType;
}
}
}
// Need to check if there is a neighbour at the given coordinates
// Debug.Log("Hex_" + neighbourX + "_" + highest_Y + "_" + neighbourZ + "_" + neighbourType);
Neighbours[q] = GameObject.Find("Hex_" + neighbourX + "_" + highest_Y + "_" + neighbourZ + "_" + correct_neighbour_type);
// While there is a neighbour in the neighbours array
// add it's coordinates to the graph node as a part of its neighbours sublist
if (Neighbours[q] != null)
{
graph[x, y, z].neighbours.Add(graph[neighbourX, highest_Y, neighbourZ]);
}
}
}
}
}
}
MapMakerDone = false;
}
}
// List<Node> currentPath = null;
public List<Node> GeneratePathTo(GameObject SelectedUnit, Vector3 targetVec)
{
// Dijkstra's Algorithm Implementation
Dictionary<Node, float> dist = new Dictionary<Node, float>();
Dictionary<Node, Node> prev = new Dictionary<Node, Node>();
List<Node> unvisited = new List<Node>();
Node source = graph[
SelectedUnit.GetComponent<UnitBasicScript>().HexX,
SelectedUnit.GetComponent<UnitBasicScript>().HexY,
SelectedUnit.GetComponent<UnitBasicScript>().HexZ];
// TargetNode float to int conversion
int targetVecXInt = (int)targetVec.x;
int targetVecYInt = (int)targetVec.y;
int targetVecZInt = (int)targetVec.z;
Node targetNode = graph[
targetVecXInt,
targetVecYInt,
targetVecZInt];
// Debug.Log(targetVecXInt + "_" + targetVecYInt + "_" + targetVecZInt);
dist[source] = 0;
prev[source] = null;
// Initialise everything to have infinity distance since no other
information available
// Some nodes might not eb erachable therefore infinity is reasonable
foreach (Node v in graph)
{
if (v != source)
{
dist[v] = Mathf.Infinity;
prev[v] = null;
}
unvisited.Add(v);
}
while (unvisited.Count > 0)
{
// u is unvisited node with shortest distance
Node u = null;
foreach (Node possibleU in unvisited)
{
if (u == null || dist[possibleU] < dist[u])
{
u = possibleU;
}
}
unvisited.Remove(u);
if (u == targetNode)
{
break;
}
foreach (Node v in u.neighbours)
{
float alt = dist[u] + u.Distanceto(v);
if (alt < dist[v])
{
dist[v] = alt;
prev[v] = u;
}
}
}
if (prev[targetNode] == null)
{
// No route to target
return null;
}
List<Node> currentPath = new List<Node>();
Node curr = targetNode;
while (prev[curr] != null)
{
currentPath.Add(curr);
curr = prev[curr];
}
currentPath.Reverse();
return currentPath;
} // End of generate path function
public class Node
{
public int x = 0;
public int y = 0;
public int z = 0;
public List<Node> neighbours;
public Node()
{
neighbours = new List<Node>();
}
public float Distanceto(Node n)
{
if (n == null)
{
Debug.Log("Error");
}
return Vector2.Distance(
new Vector3(x, y, z),
new Vector3(n.x, n.y, n.z));
}
}
}
That concludes the code, I understand everything within monobehaviour has to be indented and it is in my code but upon copying into stackoverflow it lost that indentation. Next are the pictures showing the incorrect paths the units take.
https://imgur.com/a/wEChdq3
If any other information is needed please let me know and I will be more than happy to provide it. Thank you so much again!
You are using a List instead of a priority queue, which is massively inefficient. Also, since your grid has a simple heuristic, you should consider using A* which will be much faster.
Despite all the glaring inefficiencies which i still haven't resolved, I have resolved the problems with the algorithm implementation. I was getting the distance between the tile grid coordinates which didn't take into account that on a hex grid a diagonal movement has the exact same distance cost as a horizontal movement. Therefore the solution was to get the distance once the node grid coordinates had been converted to world coordinates as this will ensure all distances between adjacent tiles are equal.
Hope this helps if anyone gets stuck with the same problem!

How can I create a square hextilemap?

I have this code:
int tX = 1;
for (int y = 0; y < ROWS; y++)
{
for (int x = 0; x < tX; x++)
{
Tile t = new Tile()
{
Texture = tile,
Position = new Microsoft.Xna.Framework.Point(x, y),
Troops = rnd.Next(1, 4),
OwnedByPlayerIndex = 0
};
t.Tap += tile_Tap;
if (t.Position.Y < ROWS)
tiles.Add(t);
}
tX += 2;
tX = (int)MathHelper.Clamp(tX, 0, COLS);
}
And what im trying to do is create a map within a rect, limiting the map by number of rows and cols.
But it does not work as it does not follow up and finishes the last corner, leaving it uncomplete
You appear to have some redudant logic in there, and your inner loop is not iterating over all columns. If you want to fill the entire rectangle then you don't need tX at all. Example:
for (int y = 0; y < ROWS; y++)
{
for (int x = 0; x < COLS; x++)
{
Tile t = new Tile()
{
Texture = tile,
Position = new Microsoft.Xna.Framework.Point(x, y),
Troops = rnd.Next(1, 4),
OwnedByPlayerIndex = 0
};
t.Tap += tile_Tap;
tiles.Add(t);
}
}
Additionally, from your screenshot it looks like if the entire bottom row were filled then the lower staggered hexes would overlap the bottom of the red rectangle. If you don't want to add those lower hexes then you'll need to add them conditionally:
...
if (y > 0 || 0 == (x & 1))
tiles.Add(t);

keeping array in an array

i want to save kingarray[x1+1,y1-1],king array[x1+1,y1],etc in an array(ways that king in chess game can go).how can i do it?or if its not possible what do you suggest me to keep the ways that king can go?thanks
int[,] kingarray = new int[8, 8];
for (i = 0; i < 1; i++)
{
return kingarray[x1 + 1, y1];
}
for (i = 1; i > 0; i--)
{
return kingarray[x1 - 1, y1];
}
for (j = 0; j < 1; j++)
{
return kingarray[x1, y1 + 1];
}
for (j = 1; j > 0; j--)
{
return kingarray[x1, y1 - 1];
}
for (i = 0; i < 1; i++)
for (j = 1; j > 0; j--)
{
return kingarray[x1 + 1, y1 - 1];
}
for (i = 1; i > 0; i--)
for (j = 0; j < 1; j++)
{
return kingarray[x1 - 1, y1 + 1];
}
for (i = 0; i < 1; i++)
for (j = 0; j < 1; j++)
{
return kingarray[x1 + 1, y1 + 1];
}
for (i = 1; i > 0; i--)
for (j = 1; j > 0; j--)
{
return kingarray[x1 - 1, y1 - 1];
}
what do you suggest me to keep the ways that king can go?
This may not answer your question directly, and that you have already marked the correct answer. But just to answer the above.
Rather than keeping the all the positions a king can go, I would keep the positions it is allowed to go and calculate the possible routes during run-time.
For any piece(King, Pawn, etc), there are 8 places that it can move. Left, right, up, down, top-left, top-right, bottom-left, bottom-right. Based upon the type of piece, you can control the movement.
For You can create a ChessPiece class. Declare 8 positional flags, bool flags probably, that would define the possible positions that a piece can move.
Declare the number of blocks a piece can skip, for instance directions(; and drive the types from the ChessPiece and allow.
--EDIT--
For instance, following:
//Class that contains the position of the Piece over the Tile
class PiecePosition
{
//Set the bounds an image/vector can move.
public int X, Y;
public PiecePosition(int x, int y) { this.X = x; this.Y = y; }
public PiecePosition(int x, int y, int width, int height) { this.X = x; this.Y = y; }
}
//Base ChessPeice class that shall be used to drive all types of chess pieces.
//Sixteen pieces: one king, one queen, two rooks, two knights, two bishops, and eight pawns
//http://en.wikipedia.org/wiki/Chess
abstract class ChessPiece
{
public object Image;//This is an "optional" object that contains the Picture of the Peice,
//alternatively, it may contain vector of the image that you want
//to draw. Right now this is object is here just for the sake of
//understanding that you can use this object here to Draw() it
//based upon its position.
//Possible movements of the unhindered piece=8
protected const int MaxDirectionsCount = 8;
public enum PieceType { King, Pawn, SomeOtherType }//Types of chess peice.
public enum Moves { Up, Down, Left, Right, TopLeft, Etc }//Possible positions a piece can move
protected PieceType Type; //Contains type of piece
protected Moves MoveableDirections;//Shall contain the allowable directions
public List<PiecePosition> listPositions;//List of possible positions to be calculated during runtime
//Defines a piece can skip
protected int SkippableBlocks;
public abstract void PossiblePositions(PiecePosition CurrentPosition);//Calculates possible positions
public abstract void Draw();//Draws the piece
}
//The King Chess piece
//http://en.wikipedia.org/wiki/King_%28chess%29
class King : ChessPiece
{
//Constructor that sets the type of piece
public King()
{
//Set the directions a King can move.
base.MoveableDirections = Moves.Down | Moves.Left | Moves.Right;
base.Type = PieceType.King;
SkippableBlocks = 1; //Max a king can move is one block in the base.Directions set above.
}
//Calculates possible available positions to move to, during runtime; based upon current position.
public override void PossiblePositions(PiecePosition CurrentPosition)
{
//Calculate position
//Since you know this is king piece, you can calculate the possible positions
//And add that the list of possible positions.
//For instance, a King can move
int X = 0; int Y = 0;
for (int i = 0; i < MaxDirectionsCount; i++)
{
//Calculate directions.
if (base.MoveableDirections == Moves.Down) { X = CurrentPosition.X - 1; Y = CurrentPosition.Y; }
if (base.MoveableDirections == Moves.Up) { X = CurrentPosition.X + 1; Y = CurrentPosition.Y; }
//Rest of the directions go here...
//...Btw, what would you do for cross directions?
//One way could be to pass a Rectangle in the ChessTile(x,y,width,height) constructor
//Add to list of possible directions.
listPositions.Add(new PiecePosition(X, Y));
}
}
public override void Draw()
{
//You can actually draw/redraw using the Image object
//based upon the current/moved position.
}
}
Btw, if you just started writing the code, I would suggest you stop. Look around for Chess class designs first, and see if you want make sense out of Chess Objects. For instance, ChessBoard, Game, Players, Piece, Movements, AllowablePositions, etc.
Take a look at questions related to Chess/Google abit, and see if the questions/answers and your logic is already inline.
Array?
It is rather easy to determine a King's possible movement.
class position { public int x, y }
...
public ArrayList<position> KingPossibleMove(position current)
{
var list = new ArrayList();
if (current.x>0) {
list.add(new position() { x= current.x - 1, y = current.y });
if (current.x<8) {
list.add(new position() { x= current.x + 1, y = current.y });
// The rest follows, try to determine if the move is within bound
// you can also look for if the move will cause immediate checkmate.
return list;
}
int[,][] declares a 1D array containing a 2D array of int. Is that what you want?
And the kingmoves can simply be calculated as:
IEnumerable<Position> ValidKingTargets(Position p)
{
int top=Math.Max(0,y-1);
int left=Math.Max(0,x-1);
int bottom=Math.Min(8,y+2);
int right=Math.Min(8,x+2);
for(int y=top;y<bottom;y++)
for(int x=left;x<right;x++)
if(x!=p.X || y!=p.Y)
yield return new Position(x,y);
}

Categories