Ray/AABB Intersection Incorrect - c#
I've tried to reimplement the Fast Graphics Gems Ray/AABB Intersection Method in C#:
// Based on "Fast Ray-Box Intersection" algorithm by Andrew Woo, "Graphics Gems", Academic Press, 1990
public unsafe Vector? IntersectionWith(Cuboid other) {
const int NUM_DIMENSIONS = 3;
Assure.Equal(NUM_DIMENSIONS, 3); // If that value is ever changed, this algorithm will need some maintenance
const byte QUADRANT_MIN = 0;
const byte QUADRANT_MAX = 1;
const byte QUADRANT_BETWEEN = 2;
// Step 1: Work out which direction from the start point to test for intersection for all 3 dimensions, and the distance
byte* quadrants = stackalloc byte[NUM_DIMENSIONS];
float* candidatePlanes = stackalloc float[NUM_DIMENSIONS];
float* cuboidMinPoints = stackalloc float[NUM_DIMENSIONS];
float* cuboidMaxPoints = stackalloc float[NUM_DIMENSIONS];
float maxDistance = Single.NegativeInfinity;
byte maxDistanceDimension = 0;
bool startPointIsInsideCuboid = true;
cuboidMinPoints[0] = other.X;
cuboidMinPoints[1] = other.Y;
cuboidMinPoints[2] = other.Z;
cuboidMaxPoints[0] = other.X + other.Width;
cuboidMaxPoints[1] = other.Y + other.Height;
cuboidMaxPoints[2] = other.Z + other.Depth;
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (StartPoint[i] < cuboidMinPoints[i]) {
quadrants[i] = QUADRANT_MIN;
candidatePlanes[i] = cuboidMinPoints[i];
startPointIsInsideCuboid = false;
}
else if (StartPoint[i] > cuboidMaxPoints[i]) {
quadrants[i] = QUADRANT_MAX;
candidatePlanes[i] = cuboidMaxPoints[i];
startPointIsInsideCuboid = false;
}
else {
quadrants[i] = QUADRANT_BETWEEN;
}
}
if (startPointIsInsideCuboid) return StartPoint;
// Step 2: Find farthest dimension from cuboid
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
// ReSharper disable once CompareOfFloatsByEqualityOperator Exact check is desired here: Anything other than 0f is usable
if (quadrants[i] != QUADRANT_BETWEEN && Orientation[i] != 0f) {
float thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
if (thisDimensionDist > maxDistance) {
maxDistance = thisDimensionDist;
maxDistanceDimension = i;
}
}
}
if (maxDistance < 0f) return null;
if (maxDistance - Length > MathUtils.FlopsErrorMargin) return null;
float* intersectionPoint = stackalloc float[NUM_DIMENSIONS];
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (maxDistanceDimension == i) {
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (cuboidMinPoints[i] - intersectionPoint[i] > MathUtils.FlopsErrorMargin || intersectionPoint[i] - cuboidMaxPoints[i] > MathUtils.FlopsErrorMargin) return null;
}
else intersectionPoint[i] = candidatePlanes[i];
}
Vector result = new Vector(intersectionPoint[0], intersectionPoint[1], intersectionPoint[2]);
if (!IsInfiniteLength && Vector.DistanceSquared(StartPoint, result) > Length * Length) return null;
else return result;
}
However, although it sort of works, I'm getting incorrect results on the following part of a unit test:
Cuboid cuboid = new Cuboid(frontBottomLeft: new Vector(0f, 7.1f, 0f), width: 0f, height: 5f, depth: 0f);
Ray testRayC = new Ray(startPoint: new Vector(30f, 30f, 30f), orientation: new Vector(-1f, -1f, -1f));
Assert.AreEqual(
null,
testRayC.IntersectionWith(cuboid)
);
I am expecting null from the call to testRayC.IntersectionWith(cuboid), but instead it returns a Vector(0, 12.1, 0), which is not a point on the ray at all.
So is it just a case of adding a final check that the calculated point is on the ray? Or (and this is what I suspect), have I made an error in transcribing the code? I have double and triple checked but didn't see anything obvious...
The problem in your code is when you do if (maxDistanceDimension == i) {. The original code checks if (whichPlane != i) {. I don't have your data structures, but a fix should look like:
for (byte i = 0; i < NUM_DIMENSIONS; ++i)
{
if (maxDistanceDimension != i)
{
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (intersectionPoint[i] < cuboidMinPoints[i] - MathUtils.FlopsErrorMargin || intersectionPoint[i] > cuboidMaxPoints[i] + MathUtils.FlopsErrorMargin)
return null;
}
else
{
intersectionPoint[i] = candidatePlanes[i];
}
}
Next, the following isn't in the original code. What is this for?
if (maxDistance - Length > MathUtils.FlopsErrorMargin)
return null;
If you are trying to check if the hit is within the extent of the ray, this may be a bug. Given that your Orientation does not appear to be normalized, maxDistance is not necessarily in units of length. This may not matter in the original algorithm, but if you are going to check maxDistance against some other length you need to normalize Orientation (make it dimensionless) so that
thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
will have units of length.
Incidentally, in the original I think the following is wrong:
if(inside) {
coord = origin;
return (TRUE);
}
Assuming this code is c and not c++, this simply sets the the coord pointer to have the same reference as the origin pointer, which will have no effect on the caller. This issue doesn't apply to your version, however.
Also, in the course of looking at this, I made a more literal c# transcription of the algorithm here:
public static class RayXCuboid
{
enum HitQuadrant
{
Right = 0,
Left = 1,
Middle = 2,
}
const int Dimension = 3;
[Conditional("DEBUG")]
static void AssertValidArguments<TDoubleList>(params TDoubleList[] args) where TDoubleList : IList<double>
{
Debug.Assert(Dimension == 3);
foreach (var list in args)
Debug.Assert(list != null && list.Count == Dimension);
}
public static bool HitBoundingBox<TDoubleList>(TDoubleList minB, TDoubleList maxB, TDoubleList origin, TDoubleList dir, TDoubleList coord) where TDoubleList : IList<double>
{
AssertValidArguments(minB, maxB, origin, dir, coord);
HitQuadrant[] quadrant = new HitQuadrant[Dimension];
double[] maxT = new double[Dimension];
double[] candidatePlane = new double[Dimension];
/* Find candidate planes; this loop can be avoided if
rays cast all from the eye(assume perpsective view) */
bool inside = true;
for (int i = 0; i < Dimension; i++)
if (origin[i] < minB[i])
{
quadrant[i] = HitQuadrant.Left;
candidatePlane[i] = minB[i];
inside = false;
}
else if (origin[i] > maxB[i])
{
quadrant[i] = HitQuadrant.Right;
candidatePlane[i] = maxB[i];
inside = false;
}
else
{
quadrant[i] = HitQuadrant.Middle;
}
/* Ray origin inside bounding box */
if (inside)
{
CopyTo(origin, coord);
return true;
}
/* Calculate T distances to candidate planes */
for (int i = 0; i < Dimension; i++)
if (quadrant[i] != HitQuadrant.Middle && dir[i] != 0.0)
maxT[i] = (candidatePlane[i] - origin[i]) / dir[i];
else
maxT[i] = -1.0;
/* Get largest of the maxT's for final choice of intersection */
int whichPlane = 0;
for (int i = 1; i < Dimension; i++)
if (maxT[whichPlane] < maxT[i])
whichPlane = i;
/* Check final candidate actually inside box */
if (maxT[whichPlane] < 0.0)
{
FillWithDefault(coord);
return false;
}
for (int i = 0; i < Dimension; i++)
if (whichPlane != i)
{
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if (coord[i] < minB[i] || coord[i] > maxB[i])
{
FillWithDefault(coord);
return false;
}
}
else
{
coord[i] = candidatePlane[i];
}
return true; /* ray hits box */
}
static void FillWithDefault<T>(IList<T> list)
{
for (int i = 0; i < list.Count; i++)
list[i] = default(T);
}
static void CopyTo<T>(IList<T> from, IList<T> to)
{
int arrayIndex = 0;
foreach (var item in from)
to[arrayIndex++] = item;
}
}
Related
C# Tic-Tac-Toe Minimax
I am currently trying my hand at making a minimax AI for tictactoe. My goal was that it should suffice for larger boards as well. However, I am having quite a hard time wrapping my head around how to implement the algorithm. I have read countless different descriptions of the algorithm but I still don't seem to be able to make it work. My result as of yet is an incredibly stupid AI. Here is my code for it. Edit: The main point I am wondering about is how I make the AI value me not winning over forwarding itself towards the win. As of now it doesn't really care that I will win the next turn. namespace TicTacToe_AI { public class Move //A class for moves { public int x, y, value, MoveNumber; void SetMove(int a, int b) { x = a; y = b; } public Move(int a, int b) { SetMove(a, b); } public Move() { } } class AI //AIClass { //The minimax algorithm public Move CalculateMoves(int[,] Board, int BoardSize, int Depth, Move BestMoveAI, Move BestMovePlayer, int OriginalDepth, int CurrentTurn) { Depth--; //Decrease the depth for each iteration bool Alpha = false; //Alpha-beta pruning - needs improvement bool Beta = false; bool WinningMove = false; if (CurrentTurn == 1) CurrentTurn = 2; if (CurrentTurn == 2) CurrentTurn = 1; List<Move> DifferentMoves = new List<Move>(); List<Move> PossibleMoves = new List<Move>(); for (int i = 0; i < BoardSize; i++) //Add all possible moves to a list { for (int j = 0; j < BoardSize; j++) { if (Board[i, j] == 0) { Move Possible = new Move(i, j); PossibleMoves.Add(Possible); } } } if (CurrentTurn == 2 && Depth >= 0 && Depth < BestMoveAI.MoveNumber) Alpha = true; //Alpha-beta pruning if (CurrentTurn == 1 && Depth >= 0 && Depth < BestMovePlayer.MoveNumber) Beta = true; if(Alpha || Beta) { foreach (Move TryMove in PossibleMoves) //Try every possible move to see if they are a winning move { int[,] Trying = new int[BoardSize, BoardSize]; Trying = (int[,])Board.Clone(); Trying[TryMove.x, TryMove.y] = CurrentTurn; TryMove.MoveNumber = OriginalDepth - Depth; if (Form1.Win(Trying) == 2) { TryMove.value = -1; DifferentMoves.Add(TryMove); if (Depth + 1 == OriginalDepth) { if (TryMove.MoveNumber < BestMoveAI.MoveNumber) BestMoveAI = TryMove; WinningMove = true; break; } else { WinningMove = true; if (TryMove.MoveNumber < BestMoveAI.MoveNumber) BestMoveAI = TryMove; return TryMove; } } else if (Form1.Win(Trying) == 1) { WinningMove = true; TryMove.value = 1; BestMovePlayer = TryMove; DifferentMoves.Add(TryMove); return TryMove; } } if (!WinningMove) // If no winning move was found, try recursively searching for a winning move { if (Alpha || Beta) { foreach (Move TryMove2 in PossibleMoves) { int[,] TestMove = new int[BoardSize, BoardSize]; TestMove = (int[,])Board.Clone(); TestMove[TryMove2.x, TryMove2.y] = CurrentTurn; TryMove2.value = CalculateMoves(TestMove, BoardSize, Depth, BestMoveAI, BestMovePlayer, OriginalDepth, CurrentTurn).value; DifferentMoves.Add(TryMove2); } } } } //Find the best possible move and return it BestMoveAI.value = 0; BestMoveAI.MoveNumber = OriginalDepth; BestMovePlayer.value = 0; BestMovePlayer.MoveNumber = OriginalDepth; if (CurrentTurn == 2) { foreach (Move AllMoves in DifferentMoves) { if (AllMoves.value <= BestMoveAI.value && AllMoves.MoveNumber <= BestMoveAI.MoveNumber) { BestMoveAI = AllMoves; } } return BestMoveAI; } else if(CurrentTurn == 1) { foreach (Move AllMoves in DifferentMoves) { if (AllMoves.value >= BestMovePlayer.value && AllMoves.MoveNumber <= BestMovePlayer.MoveNumber) { BestMovePlayer = AllMoves; } } return BestMovePlayer; } Move BadMove = new Move(); BadMove.value = 0; BadMove.MoveNumber = Depth; return BadMove; } } }
Neural Net - Feed Forward, Matrix Multiplication in C#
I'm attempting to make a Neural Network in C#, I based the design in a python code I made a while back. But somehow the end result is not the same. I'm new to C# and I'm using it in Unity, so I have limitation to library uses. In python numpy can do matrix multiplications with the numpy.dot() method. I Haven't found something similar in C#, especially in Unity. So I had to do it by hand. The Python code: import numpy as np class NN: def __init__(self, n_input, n_hidden_layers, n_hidden_nodes, n_output): self.weights_hidden = [] for n in range(n_hidden_layers + 1): if n == 0: size = n_input, n_hidden_nodes elif n == n_hidden_layers: size = n_hidden_nodes, n_output else: size = n_hidden_nodes, n_hidden_nodes self.weights_hidden.append( np.random.random(size) ) #staticmethod def activation(x): return np.tanh(x) def feed_forward(self, ip): input_values = (ip - np.mean(ip, axis=0)) / np.std(ip, axis=0) for w, weights in enumerate(self.weights_hidden): if w == 0: result = input_values result = np.array( map(self.activation, result.dot(weights)) ) return result ANN = NN(n_input=5, n_hidden_layers=2, n_hidden_nodes=3, n_output=1) print ANN.feed_forward([1, 2, 3, 4, 5]) My attempt to convert it to C#. using UnityEngine; using System.Collections; public class neural_net : MonoBehaviour { int n_inputs; int n_hidden_layers; int n_hidden_nodes; int n_outputs; float[] inputs; ArrayList hidden_weights; ArrayList hidden_results; float[] output_results; public void init(int n_inputs, int n_hidden_layers, int n_hidden_nodes, int n_outputs){ this.n_inputs = n_inputs; this.n_hidden_layers = n_hidden_layers; this.n_hidden_nodes = n_hidden_nodes; this.n_outputs = n_outputs; this.hidden_weights = new ArrayList (); this.hidden_results = new ArrayList (); this.output_results = new float[n_outputs]; int rows; int columns; for (int h = 0; h < n_hidden_layers + 2; h++) { if (h == 0){ // input -> hidden rows = n_inputs; columns = n_hidden_nodes; } else if(h == n_hidden_layers + 1){ // hidden -> output rows = n_hidden_nodes; columns = n_outputs; } else { // hidden -> hidden rows = n_hidden_nodes; columns = n_hidden_nodes; } float[] hidden_result = new float[rows*columns]; hidden_results.Add(hidden_results); float[,] target = new float[rows,columns]; string test = ""; for(int r = 0; r < rows; r++){ for(int c = 0; c < columns; c++){ target[r,c] = Random.Range(0.0f, 1.0f); test += target[r,c] + ", "; } } hidden_weights.Add(target); } } float activation(float x){ // tanh(x); return (1 - Mathf.Exp (-2 * x)) / (1 + Mathf.Exp (-2 * x)); } float[] _dot_matrix(float[] results, float[,] weights){ float[] new_matrix = new float[weights.GetLength(1)]; string t0 = ""; for (int r = 0; r < weights.GetLength(1); r++){ float res = 0; for (int c = 0; c < weights.GetLength(0); c++) { res += results[c] * weights[c,r]; } new_matrix[r] = res; } return new_matrix; } float[] _map_activation(float[] pre_results){ float[] results = new float[pre_results.Length]; for (int i = 0; i < results.Length; i++) { results[i] = activation(pre_results[i]); } return results; } float[] feed_forward(){ int h; for (h = 0; h < n_hidden_layers + 2; h++) { float[] dot_matrix_result; if(h == 0){ dot_matrix_result = _dot_matrix(inputs, (float[,])hidden_weights[h]); } else if (h == n_hidden_layers +1){ dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]); output_results = _map_activation(dot_matrix_result); break; } else { dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]); } float[] result = _map_activation(dot_matrix_result); hidden_results[h] = _map_activation(result); } return output_results; } float[] normalize_input(float[] inputs){ float sum = 0.0f; for (int i = 0; i < inputs.Length; i++) { sum += inputs[i] ; } float average = sum / inputs.Length; float[] deviations = new float[inputs.Length]; for (int i = 0; i < inputs.Length; i++) { deviations[i] = Mathf.Pow(inputs[i] - average,2); } float sum_deviation = 0; for (int i = 0; i < deviations.Length; i++) { sum_deviation += deviations[i]; } float variance = sum_deviation / deviations.Length; float std = Mathf.Sqrt (variance); for (int i = 0; i < inputs.Length; i++) { inputs[i] = (inputs[i] - average)/std; } return inputs; } public void start_net(float[] inputs){ this.inputs = normalize_input(inputs); feed_forward (); } } I run the net from other script using the init method and then the start_net() method. I made a test with not random weights and fixed input data, but it didn't came to the same result as the python code. What's wrong with the C# code?
Marshal.Copy() causes System.StackOverflowException
I encountered a System.StackOverflowException problem when I was trying to Marshal.Copy() Here is the screen shot of the code where exception happens: Here is the function: private static void ImageUpdate(IntPtr returnArray, ref int channels) { if (_prevTickCount == 0) { _sumTickCount = 0; } else { _sumTickCount = _sumTickCount * .75 + (Environment.TickCount - _prevTickCount) * .25; } //only copy to the buffer when pixel data is not being read if (_pixelDataReady == false) { int width = 0; int height = 0; if (false == GetImageDimensions(ref width, ref height)) { return; } _dataLength = width * height; _colorChannels = channels; if ((_pixelData == null) || (_pixelData.Length != (_dataLength * _colorChannels))) { _pixelData = new short[_dataLength * _colorChannels]; //_pixelDataHistogram = new int[_colorChannels][]; _pixelDataHistogram = new int[MAX_CHANNELS][]; if (_colorChannels == 1) { _pixelDataByte = new byte[_dataLength]; } else { _pixelDataByte = new byte[_dataLength * 3]; } //for (int i = 0; i < _colorChannels; i++) for (int i = 0; i < MAX_CHANNELS; i++) { _pixelDataHistogram[i] = new int[PIXEL_DATA_HISTOGRAM_SIZE]; } } //2^n == FULL_RANGE_NORMALIZATION_FACTOR const int SHIFT_VALUE = 6; switch (_colorChannels) { case 1: { Marshal.Copy(returnArray, _pixelData, 0, _dataLength * _colorChannels); //factor is derived by taking CAMERA_MAX_INTENSITY_VALUE/256 //const double FULL_RANGE_NORMALIZATION_FACTOR = 64.0; //clear the histogram for (int i = 0; i < PIXEL_DATA_HISTOGRAM_SIZE; i++) { _pixelDataHistogram[0][i] = 0; } for (int i = 0; i < _dataLength * _colorChannels; i++) { double valHist; if (_pixelData[i] < 0) { valHist = (_pixelData[i] + 32768) >> SHIFT_VALUE; } else { valHist = (_pixelData[i]) >> SHIFT_VALUE; } _pixelDataHistogram[0][(byte)valHist]++; } } break; default: { Marshal.Copy(returnArray, _pixelData, 0, _dataLength * _colorChannels); } break; } _dataWidth = width; _dataHeight = height; _pixelDataReady = true; ThorLog.Instance.TraceEvent(TraceEventType.Verbose, 1, "ImageUpdate pixeldata updated"); } else { ThorLog.Instance.TraceEvent(TraceEventType.Verbose, 1, "ImageUpdate pixeldata not ready"); } _prevTickCount = Environment.TickCount; } The whole idea is to copy image buffer from native code. This exception occurs only when image size is large 4K X 4K, but I dont have a problem processing a size below that. I have no idea how I should correct this. Anyone care to educate? Thanks!
I traced it down, eventually, if was the returnArray which is not newed large enough to cause this problem.
how to multiply a given Matrix by its transpose?
I have to create a method to multiply a given Matrix by its transpose. Consider my matrix is 2d array double [][] matrix; public double[][] MultiplyByTranspose(double[][] matrix) { return newMatrix; } If you need my Matrix class check it in the answer of this question
Well, the simplest way is just to implement Transpose and Multiplication. Of course, when combined, it could be done more efficient, but I think that you'll need Transpose and Multiplication as separated routine further in your code (you've asked about matrix rotation) public static Boolean IsRectangle(Double[][] value) { if (Object.ReferenceEquals(null, value)) return false; else if (value.Length <= 0) return false; Double[] line = value[value.Length - 1]; if (Object.ReferenceEquals(null, line)) return false; int size = line.Length; for (int i = value.Length - 2; i >= 0; --i) if (Object.ReferenceEquals(null, value[i])) return false; else if (value[i].Length != size) return false; return true; } public static Double[][] Transpose(Double[][] value) { if (Object.ReferenceEquals(null, value)) throw new ArgumentNullException("value"); if (!IsRectangle(value)) throw new ArgumentException("value should be a rectangular matrix.", "value"); int colCount = value.Length; int rowCount = value[value.Length - 1].Length; Double[][] result = new Double[rowCount][]; for (int i = rowCount - 1; i >= 0; --i) { Double[] line = new Double[colCount]; result[i] = line; for (int j = colCount - 1; j >= 0; --j) line[j] = value[j][i]; } return result; } // Simple quibic algorithm public static Double[][] Multiply(Double[][] left, Double[][] right) { if (Object.ReferenceEquals(null, left)) throw new ArgumentNullException("left"); else if (Object.ReferenceEquals(null, right)) throw new ArgumentNullException("right"); if (!IsRectangle(left)) throw new ArgumentException("left should be a rectangular matrix", "left"); else if (!IsRectangle(right)) throw new ArgumentException("right should be a rectangular matrix", "right"); int leftRows = left.Length; int leftCols = left[0].Length; int rightRows = right.Length; int rightCols = right[0].Length; if (leftCols != rightRows) throw new ArgumentOutOfRangeException("right"); Double[][] result = new Double[leftRows][]; for (int r = leftRows - 1; r >= 0; --r) { Double[] leftLine = left[r]; Double[] line = new Double[rightCols]; result[r] = line; for (int c = rightCols - 1; c >= 0; --c) { Double s = 0.0; for (int i = leftCols - 1; i >= 0; --i) s += leftLine[i] * right[i][c]; line[c] = s; } } return result; } ... public double[][] MultiplyByTranspose(double[][] matrix) { //TODO: Check the order! Which matrix should be the first and which the second, // In Linear Algebra A * B != B * A return Multiply(matrix, Transpose(matrix)); // Or // return Multiply(Transpose(matrix), matrix); }
how can i drag a 2d level array from a txt file
i am working on improving this tower defence gtame that i finished from this tutorial http://xnatd.blogspot.com/ i now wish to load the levels from a text file but not quite sure how i would do this using a streamreader, any tips? heres the source code for my level class; public class Level { protected int temperature; protected int levelNo; private Queue<Vector2> waypoints = new Queue<Vector2>(); public Queue<Vector2> Waypoints { get { return waypoints; } } int[,] map = new int[,] { {0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,}, {0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,}, }; public int Temperature // get the width of the level (how many numbers are in a row) { get { return temperature; } } public int LevelNo // get the width of the level (how many numbers are in a row) { get { return levelNo; } set { levelNo = value; } } public int Width // get the width of the level (how many numbers are in a row) { get { return map.GetLength(1); } } public int Height // get the height of our level (how many numbers are there in a column) { get { return map.GetLength(0); } } public int GetIndex(int cellX, int cellY) // return the index of the requested cell. { if (cellX < 0 || cellX > Width - 1 || cellY < 0 || cellY > Height - 1) { return 0; } else { return map[cellY, cellX]; } } public List<Texture2D> tileTextures = new List<Texture2D>(); // list to contain all the textures /// <summary> /// CONSTRUCTOR NEW LEVEL /// </summary> public Level() { SetWayPoints(map); this.temperature = 1000; this.levelNo = 2; } private void SetWayPoints(int[,] map) { int currentPosVal = map[0, 0]; int lPos = 0; int rPos = 0; int uPos = 0; int dPos = 0; int storedXPos = 99; int storedYPos = 99; int endstoredXPos = 99; int endstoredYPos = 99; int lastY = 0; int lastX = 0; //Search top ROW for start for (int i = 0; i < Width; i++) { currentPosVal = map[0, i]; if (currentPosVal == 1) { storedXPos = i; storedYPos = 0; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); lastX = storedXPos; lastY = storedYPos; break; } } //if start not set if (storedXPos == 99 && storedXPos == 99) { //look in 1st coloum for start for (int i = 0; i < Height; i++) { currentPosVal = map[i, 0]; if (currentPosVal == 1) { storedXPos = 0; storedYPos = i; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); lastX = storedXPos; lastY = storedYPos; break; } } } //search end COLOUM for end for (int i = 0; i < Height; i++) { currentPosVal = map[i, Width - 1]; if (currentPosVal == 1) { endstoredXPos = Width - 1; endstoredYPos = i; } } //If end not set look in bottom row for end if (endstoredXPos == 99 && endstoredYPos == 99) { for (int i = 0; i < Width; i++) { currentPosVal = map[7, i]; if (currentPosVal == 1) { endstoredXPos = i; endstoredYPos = Height - 1; } } if (endstoredXPos == 99 && endstoredYPos == 99) { } } // start midlle loop while (true) { lPos = 0; rPos = 0; uPos = 0; dPos = 0; //If current pos is not down the left hand edge if (storedXPos > 0) { lPos = map[storedYPos, storedXPos - 1]; } //If current pos square is not down the right hand edge if (storedXPos < Width - 1) { rPos = map[storedYPos, storedXPos + 1]; } //If current pos square is not in the top row if (storedYPos > 0) { uPos = map[storedYPos - 1, storedXPos]; } //If current pos square is not in the bottom row if (storedYPos < Height - 1) { dPos = map[storedYPos + 1, storedXPos]; } if (lPos == 1 && (lastX != storedXPos - 1 || lastY != storedYPos)) { lastX = storedXPos; lastY = storedYPos; storedXPos--; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (rPos == 1 && (lastX != storedXPos + 1 || lastY != storedYPos)) { lastX = storedXPos; lastY = storedYPos; storedXPos++; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (dPos == 1 && (lastX != storedXPos || lastY != storedYPos + 1)) { lastX = storedXPos; lastY = storedYPos; storedYPos++; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (uPos == 1 && (lastX != storedXPos || lastY != storedYPos - 1)) { lastX = storedXPos; lastY = storedYPos; storedYPos--; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } if (storedXPos == endstoredXPos && storedYPos == endstoredYPos) { break; } } } public void AddTexture(Texture2D texture) // method adds a texture to our texture list. { tileTextures.Add(texture); } //Reads number from array, store its value in textureIndex, Use textureIndex to get the texture from tileTextures, public void Draw(SpriteBatch batch) //Draw appropiate texture, Repeat through all elements of the array { int textureIndex; Texture2D texture; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { if (levelNo == 0) { textureIndex = map[y, x]; if (textureIndex == -1) continue; texture = tileTextures[textureIndex]; batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White); } if (levelNo > 0) { textureIndex = map[y, x]; textureIndex += (levelNo * 2); if (textureIndex == -1) continue; texture = tileTextures[textureIndex]; batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White); } } } } } }
Since C# is compiled and can't do evals like scripted languages can (not that you should be doing that anyway) you should probably use streamreader to read the data from file (formatted perhaps as delimited text: csv or tsv) Assuming you're loading something similar to the map you have up there then a map file could look something like 0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0 0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0 0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1 where you would then loop through the file and read each line As each line is read in, you can then split the line by "," to create a 1d array which can then be assigned to an index in the 2d array. Loop for each line to create the entire 2d map array Take a look at this if you need help splitting strings in C#; note that the sample code splits at spaces " " and that you should use s.Split(','); for csv
With a file that small i would use: File.ReadAllLines , and after readling it loop over the lines with a foreach loop.