I am struggling a bit with a list which is defined in a particular way. This is the situation:
I have a Struct called Edge that is formed by two Points defined in the struct Point in the code (below).
My input list is called "EDGE". Using that list I would like to produce two outputs:
List POINTS : contains the non-repeated points that appear in the list "EDGE".
Int[,] edgeIndices: represents the same thing as the input list "EDGE" but instead of the points, I want the indices of such points as defined in the list "POINTS" previously created.
Can you please help me on this?
Please note that it is very important to use a List and a Int[,] and not other types.
Many thanks!
using System;
using System.Collections.Generic;
namespace Test
{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
///////////////////////EXPECTED OUTPUTS/////////////////////////////
///
///POINTS (EXPECTED) as List<double[]>
///Index X Y
/// 0 5 50
/// 1 20 100
/// 2 30 50
/// 3 10 0
/// 4 80 100
///
///MULTIARRAY (EXPECTED)
///static int[,] edgeIndices =
/// {
/// {0, 1}, {1, 2}, {2, 3}, {0, 2},
/// {0, 3}, {1, 4}, {3, 4}
/// };
}
}
}
I suggest you to store distinct point values in List(). You can use following code to achieve it:
using System;
using System.Collections.Generic;
namespace Test
{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
//FLL POINTS CACHE
var distinctPoints = new List<Point>();
foreach (Edge edge in EDGES)
{
if (!distinctPoints.Contains(edge.First))
distinctPoints.Add(edge.First);
if (!distinctPoints.Contains(edge.Second))
distinctPoints.Add(edge.Second);
}
//POINTS LIST OUTPUT
for (int i = 0; i < distinctPoints.Count; i++)
{
Console.WriteLine("{0} {1} {2}", i, distinctPoints[i].X, distinctPoints[i].Y);
}
//FILL 2D ARRAY OF INDICES
int[,] edgeIndices = new int[EDGES.Count, 2];
for (int i = 0; i < EDGES.Count; i++)
{
edgeIndices[i, 0] = distinctPoints.IndexOf(EDGES[i].First);
edgeIndices[i, 1] = distinctPoints.IndexOf(EDGES[i].Second);
}
//2D ARRAY OUTPUT
for (int i = 0; i < edgeIndices.GetLength(0); i++)
{
Console.WriteLine("({0}, {1})", edgeIndices[i, 0], edgeIndices[i, 1]);
}
Console.ReadKey();
}
}
}
Here is my output:
Here is mine implementation:
using System;
using System.Collections.Generic;
namespace Test{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
var POINTS = new List<double[]>(EDGES.Count * 2);
FillPoints(EDGES, ref POINTS);
for (int i = 0; i < POINTS.Count; i++)
{
Console.WriteLine("{0} {1} {2}", i, POINTS[i][0], POINTS[i][1]);
}
Console.WriteLine();
var edgeIndices = new int[EDGES.Count, 2];
FillEdges(EDGES, POINTS, ref edgeIndices);
for (int i = 0; i < edgeIndices.GetLength(0); i++)
{
Console.WriteLine("({0}, {1})", edgeIndices[i, 0], edgeIndices[i, 1]);
}
Console.ReadKey(true);
}
static bool ListContainsPoint(List<double[]> POINTS, double[] POINT)
{
bool found = false;
for (int i = 0; i < POINTS.Count; i++)
{
var current = POINTS[i];
if (current[0] == POINT[0] && current[1] == POINT[1])
{
found = true;
break;
}
}
return found;
}
static int FindFirst(List<double[]> POINTS, double[] POINT)
{
int index = -1;
for (int i = 0; i < POINTS.Count; i++)
{
if (POINTS[i][0] == POINT[0] && POINTS[i][1] == POINT[1])
{
index = i;
break;
}
}
return index;
}
static void FillPoints(List<Edge> EDGES, ref List<double[]> POINTS)
{
for (int i = 0; i < EDGES.Count; i++)
{
var current = EDGES[i];
var firstPoint = new double[]{current.First.X, current.First.Y};
var secondPoint = new double[]{current.Second.X, current.Second.Y};
var firstCheck = ListContainsPoint(POINTS, firstPoint);
var secondCheck = ListContainsPoint(POINTS, secondPoint);
if (!firstCheck) POINTS.Add(firstPoint);
if (!secondCheck) POINTS.Add(secondPoint);
}
}
static void FillEdges(List<Edge> EDGES, List<double[]> POINTS, ref int[,] edgeIndices)
{
for (int i = 0; i < EDGES.Count; i++)
{
edgeIndices[i, 0] = FindFirst(POINTS, new double[] { EDGES[i].First.X, EDGES[i].First.Y });
edgeIndices[i, 1] = FindFirst(POINTS, new double[] { EDGES[i].Second.X, EDGES[i].Second.Y });
}
}
}
}
Related
so, I'm making a terraria-like game in unity 2019 on windws 10 using c# which has procedurally generated tilemaps and i have this script attached to a grid:
using UnityEngine;
using AccidentalNoise;
using System.Collections.Generic;
using UnityEngine.Tilemaps;
using System;
public class CompileTerrain : MonoBehaviour
{
public TileBase dirtTile;
public TileBase grassTile;
public TileBase stoneTile;
public List<GameObject> fractalLayers = new List<GameObject>();
public Tilemap grid;
public int width;
public int height;
public float seed;
public int caveSmoothness = 2;
void Start()
{
grid.ClearAllTiles();
int touchCount = 0;
Vector3Int newPos;
double nx, ny;
ModuleBase combinedTerrain = CavesAndMountains((uint)seed);
List<Vector3Int> terrainCoords = new List<Vector3Int>();
SMappingRanges ranges = new SMappingRanges();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
nx = (ranges.mapx0 + ((double)x / (double)width) * (ranges.mapx1 - ranges.mapx0)) * 3;
ny = (ranges.mapy0 + ((double)y / (double)height) * (ranges.mapy1 - ranges.mapy0)) * 3;
if (combinedTerrain.Get(nx, ny) > 0f)
{
terrainCoords.Add(new Vector3Int(x, height - y, 0));
}
}
}
List<Tuple<int, int>> neighbors = new List<Tuple<int, int>>() {Tuple.Create(1, 1), Tuple.Create(-1, -1),
Tuple.Create(0, 1), Tuple.Create(1, 0),
Tuple.Create(0, -1), Tuple.Create(-1, 0),
Tuple.Create(-1, 1), Tuple.Create(1, -1)};
for (int index = 0; index < terrainCoords.Count; index++)
{
if (index == terrainCoords.Count)
{
break;
}
touchCount = 0;
for (int posAdd = 0; posAdd < neighbors.Count; posAdd++)
{
newPos = new Vector3Int(terrainCoords[index].x + neighbors[posAdd].Item1, terrainCoords[index].y + neighbors[posAdd].Item2, 0);
touchCount += terrainCoords.Contains(newPos) ? 1 : 0;
}
if (touchCount < 2)
{
terrainCoords.Remove(terrainCoords[index]);
}
}
for (int j = 0; j < caveSmoothness; j++)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (!terrainCoords.Contains(new Vector3Int(x, y, 0)))
{
touchCount = 0;
for (int posAdd = 0; posAdd < neighbors.Count; posAdd++)
{
newPos = new Vector3Int(x + neighbors[posAdd].Item1, y + neighbors[posAdd].Item2, 0);
touchCount += terrainCoords.Contains(newPos) ? 1 : -1;
}
if (touchCount > 1)
{
terrainCoords.Add(new Vector3Int(x, y, 0));
}
}
}
}
}
foreach (Vector3Int blck in terrainCoords)
{
grid.SetTile(blck, stoneTile);
}
terrainCoords.Sort((x, y) => x.x == y.x ? x.y.CompareTo(y.y) : x.x.CompareTo(y.x));
terrainCoords.Reverse();
TileBase selectedTile;
int depth = 0;
int lastx = 0;
int lasty = terrainCoords[0].y + 1;
foreach (Vector3Int blck in terrainCoords)
{
depth = blck.x != lastx ? 0 : depth;
lasty = blck.x != lastx ? blck.y + 1 : lasty;
selectedTile = depth < 4 ? grassTile : stoneTile;
selectedTile = 3 < depth && depth < 30 ? dirtTile : selectedTile;
grid.SetTile(blck, selectedTile);
lastx = blck.x;
depth += lasty - blck.y;
lasty = blck.y;
}
int layerNum = 1;
List<Vector3Int> posList = new List<Vector3Int>();
foreach (GameObject layer in fractalLayers)
{
GetPerlinLayer component = layer.GetComponent<GetPerlinLayer>();
for (int k = 0; k < component.populateCount; k++)
{
layerNum++;
foreach (Vector3Int pos in component.GetFractalCoords(width, height, (uint)(seed * layerNum)))
if (grid.GetTile(pos) != null && grid.GetTile(pos) != grassTile)
{
grid.SetTile(pos, component.defaultTile);
}
}
}
}
public static ModuleBase CavesAndMountains(uint seed)
{
AccidentalNoise.Gradient ground_gradient = new AccidentalNoise.Gradient(0, 0, 0, 1);
// lowlands
Fractal lowland_shape_fractal = new Fractal(FractalType.BILLOW, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 2, 0.25, seed);
AutoCorrect lowland_autocorrect = new AutoCorrect(lowland_shape_fractal, 0, 1);
ScaleOffset lowland_scale = new ScaleOffset(0.125, -0.45, lowland_autocorrect);
ScaleDomain lowland_y_scale = new ScaleDomain(lowland_scale, null, 0);
TranslatedDomain lowland_terrain = new TranslatedDomain(ground_gradient, null, lowland_y_scale);
// highlands
Fractal highland_shape_fractal = new Fractal(FractalType.FBM, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 4, 2, seed);
AutoCorrect highland_autocorrect = new AutoCorrect(highland_shape_fractal, -1, 1);
ScaleOffset highland_scale = new ScaleOffset(0.25, 0, highland_autocorrect);
ScaleDomain highland_y_scale = new ScaleDomain(highland_scale, null, 0);
TranslatedDomain highland_terrain = new TranslatedDomain(ground_gradient, null, highland_y_scale);
// mountains
Fractal mountain_shape_fractal = new Fractal(FractalType.RIDGEDMULTI, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 8, 1, seed);
AutoCorrect mountain_autocorrect = new AutoCorrect(mountain_shape_fractal, -1, 1);
ScaleOffset mountain_scale = new ScaleOffset(0.3, 0.15, mountain_autocorrect);
ScaleDomain mountain_y_scale = new ScaleDomain(mountain_scale, null, 0.15);
TranslatedDomain mountain_terrain = new TranslatedDomain(ground_gradient, null, mountain_y_scale);
// terrain
Fractal terrain_type_fractal = new Fractal(FractalType.FBM, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 3, 0.125, seed);
AutoCorrect terrain_autocorrect = new AutoCorrect(terrain_type_fractal, 0, 1);
ScaleDomain terrain_type_y_scale = new ScaleDomain(terrain_autocorrect, null, 0);
AccidentalNoise.Cache terrain_type_cache = new AccidentalNoise.Cache(terrain_type_y_scale);
Select highland_mountain_select = new Select(terrain_type_cache, highland_terrain, mountain_terrain, 0.55, 0.2);
Select highland_lowland_select = new Select(terrain_type_cache, lowland_terrain, highland_mountain_select, 0.25, 0.15);
AccidentalNoise.Cache highland_lowland_select_cache = new AccidentalNoise.Cache(highland_lowland_select);
Select ground_select = new Select(highland_lowland_select_cache, 0, 1, 0.5, null);
// caves
Fractal cave_shape = new Fractal(FractalType.RIDGEDMULTI, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 1, 4, seed);
Bias cave_attenuate_bias = new Bias(highland_lowland_select_cache, 0.65);
Combiner cave_shape_attenuate = new Combiner(CombinerTypes.MULT, cave_shape, cave_attenuate_bias);
Fractal cave_perturb_fractal = new Fractal(FractalType.FBM, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 6, 3, seed);
ScaleOffset cave_perturb_scale = new ScaleOffset(0.5, 0, cave_perturb_fractal);
TranslatedDomain cave_perturb = new TranslatedDomain(cave_shape_attenuate, cave_perturb_scale, null);
Select cave_select = new Select(cave_perturb, 1, 0, 0.75, 0);
return new Combiner(CombinerTypes.MULT, cave_select, ground_select) as ModuleBase;
}
}
which i have so graciously borrowed and modified from the fine folks at accidental noise, and i made an empty gameobject which i attached this script to:
using UnityEngine;
using AccidentalNoise;
using System.Collections.Generic;
using UnityEngine.Tilemaps;
public class GetPerlinLayer : MonoBehaviour
{
public TileBase defaultTile;
public float threshold = 0.5f;
public int populateCount = 5;
public List<Vector3Int> GetFractalCoords(int width, int height, uint seed)
{
double nx, ny;
ModuleBase combinedTerrain = new Fractal(FractalType.FBM, BasisTypes.GRADIENT, InterpTypes.QUINTIC, 6, 2, seed);
List<Vector3Int> fractalCoords = new List<Vector3Int>();
SMappingRanges ranges = new SMappingRanges();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
nx = (ranges.mapx0 + ((double)x / (double)width) * (ranges.mapx1 - ranges.mapx0)) * 3;
ny = (ranges.mapy0 + ((double)y / (double)height) * (ranges.mapy1 - ranges.mapy0)) * 3;
if (combinedTerrain.Get(nx, ny) > threshold)
{
fractalCoords.Add(new Vector3Int(x, height - y, 0));
}
}
}
return fractalCoords;
}
}
and i attached different colored square sprites for each of those gameobjects, and saved them as a prefab. Once i had that prefab, i attached that to the fractalLayers list in my previous script to generate ores. And although it runs fine on a lower scale, I cant run it on a larger scale. And since there's no cure-all for making code run faster (aside from refactoring, which i don't know how to do), and i probably could've made parts of my code more efficient since I'm a novice, i would really like some insight from the eyes of a professional on how to make my code run better. I know i didn't explain everything about my project but its really just a bare-bones project those are the only scripts and unique parts about it, you can just infer what i did and fill in the blanks. Any help is appreciated. And if you could give me the extra push along with some information on the subject, I would love to have some videos recommended along with your insight to guide me along this process, since i am more of a visual learner. Thank you! =)
(For reference, it took me about 4 minutes to build this, with the settings shown here.)
So apparently my word generation method was fine, just the loop I was using to smoothen the terrain took too long.
I am searching the shortest way in my polygon (route). It starts on the center border on bottom left (blue) and ends on the center border on the top right (red). It is not allowed to leave the route.
Which algorithm i can use to calculate this route? I need a list of points to draw the shortest way. A example code would be great.
Example of my polygon with start and end
var points = new List<Point> { new Point(210, 540), new Point(330, 420), new Point(360, 420), new Point(420, 390), new Point(450, 330), new Point(480, 315), new Point(510, 270), new Point(570, 240), new Point(630, 240), new Point(690, 180), new Point(750, 150), new Point(810, 120), new Point(864, 120), new Point(864, 60), new Point(810, 60), new Point(750, 90), new Point(690, 120), new Point(630, 150), new Point(570, 150), new Point(510, 210), new Point(480, 255), new Point(450, 270), new Point(420, 330), new Point(360, 360), new Point(330, 360), new Point(156, 480) };
var image = new Bitmap(1000, 600);
using (var graphics = Graphics.FromImage(image))
{
graphics.Clear(Color.White);
graphics.FillPie(Brushes.Blue, 190, 500, 10, 10, 0, 360);
graphics.FillPie(Brushes.Red, 840, 80, 10, 10, 0, 360);
graphics.DrawPolygon(new Pen(Color.Black, 2), points.ToArray());
}
image.Save("example.bmp");
Solution
Thanks #gusman
Add Raster
Calculate distance between points
Search best route with Dijkstra.NET
using Dijkstra.NET.Contract;
using Dijkstra.NET.Model;
using Dijkstra.NET.ShortestPath;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Test.Polygon
{
class Program
{
static void Main(string[] args)
{
var points = new List<Point> { new Point(210, 540), new Point(330, 420), new Point(360, 420), new Point(420, 390), new Point(450, 330), new Point(480, 315), new Point(510, 270), new Point(570, 240), new Point(630, 240), new Point(690, 180), new Point(750, 150), new Point(810, 120), new Point(864, 120), new Point(864, 60), new Point(810, 60), new Point(750, 90), new Point(690, 120), new Point(630, 150), new Point(570, 150), new Point(510, 210), new Point(480, 255), new Point(450, 270), new Point(420, 330), new Point(360, 360), new Point(330, 360), new Point(156, 480) };
var start = new Point(190, 500);
var target = new Point(840, 80);
var image = new Bitmap(1000, 600);
using (var graphics = Graphics.FromImage(image))
{
graphics.Clear(Color.White);
graphics.FillPie(Brushes.Blue, 190, 500, 10, 10, 0, 360);
graphics.FillPie(Brushes.Red, 840, 80, 10, 10, 0, 360);
graphics.DrawPolygon(new Pen(Color.Black, 2), points.ToArray());
}
var path = new GraphicsPath(FillMode.Winding);
path.AddPolygon(points.ToArray());
var pointsForConnect = DrawRaster(5, image, path);
var dictionary = new Dictionary<uint, Point>();
dictionary.Add(0, start);
dictionary.Add(1, target);
var graph = new Graph<int, string>();
var i = 2;
foreach (var point in pointsForConnect)
{
dictionary.Add((uint)i, point);
graph.AddNode(i);
i++;
}
foreach (var point in dictionary)
{
foreach (var point2 in dictionary)
{
if (point.Equals(point2))
{
continue;
}
double dist = Math.Sqrt(Math.Pow(point2.Value.X - point.Value.X, 2) + Math.Pow(point2.Value.Y - point.Value.Y, 2));
if (dist > 50)
{
continue;
}
graph.Connect(point.Key, point2.Key, (int)dist, null);
//graph.Connect()
}
}
var dijkstra = new Dijkstra<int, string>(graph);
IShortestPathResult result = dijkstra.Process(0, 1); //result contains the shortest path
var shortestRouteIds = result.GetPath();
var shortestRoutePoints = new List<Point>();
foreach(var x in shortestRouteIds)
{
shortestRoutePoints.Add(dictionary[x]);
}
DrawDriver(shortestRoutePoints, image);
image.Save("example.bmp");
}
private static void DrawDriver(List<Point> points, Bitmap image)
{
var pen = new Pen(Color.LightGreen, 5);
for (var i = 0; i < points.Count - 1; i++)
{
var x = points[i].X;
var y = points[i].Y;
var x1 = points[i + 1].X;
var y1 = points[i + 1].Y;
DrawLineInt(image, new Point(x, y), new Point(x1, y1), pen);
}
}
private static void DrawLineInt(Bitmap bmp, Point p1, Point p2, Pen pen)
{
using (var graphics = Graphics.FromImage(bmp))
{
graphics.DrawLine(pen, p1.X, p1.Y, p2.X, p2.Y);
}
}
private static List<Point> DrawRaster(int edge, Bitmap image, GraphicsPath path)
{
var points = new List<Point>();
var countHorizontal = image.Width / edge;
var countVertical = image.Height / edge;
using (var graphics = Graphics.FromImage(image))
{
for (int x = 0; x < countHorizontal; x++)
{
for (int y = 0; y < countVertical; y++)
{
var boxX = (x * edge) + (edge / 2);
var boxY = (y * edge) + (edge / 2);
if (!path.IsVisible(boxX, boxY))
{
continue;
}
points.Add(new Point(boxX, boxY));
graphics.DrawRectangle(Pens.LightGray, x * edge, y * edge, edge, edge);
}
}
}
return points;
}
}
}
I'm drawing multiple lines by using this code, but I feel there is a better way of doing this.
E.g. by using a multidimensional array? or a list?
private void drawLines()
{
int[] x1 = { 0, 0, 112, 222, 0, 333, 0, 1};
int[] x2 = { 334, 334, 112, 222, 334, 333, 334, 1 };
int[] y1 = { 100, 200, 300, 300, 1, 300, 300, 300 };
int[] y2 = { 100, 200, 0, 0, 1, 0, 300, 0 };
for (int i = 0; i < x1.Length; i++)
{
Line line = new Line();
Grid myGrid = gg;
line.Stroke = Brushes.Black;
line.X1 = x1[i];
line.X2 = x2[i];
line.Y1 = y1[i];
line.Y2 = y2[i];
line.StrokeThickness = 2;
myGrid.Children.Add(line);
}
}
I would make a Line class having start and end point of the line in struct Point and make list of that class instead of having four arrays.
public class MyLine
{
public Point StartPoint {get; set;}
public Point EndPoint {get; set;}
public void DrawLine()
{
//Draw line code goes here
}
}
Now you have line class with required field and method to draw line. You drawLines method that might be in some other class will create list of MyLine class and can draw that list of Lines using Line class method DrawLine
private void DrawLines()
{
List<MyLine> listMyLines = new List<MyLine>();
listMyLines.Add(new MyLine{StartPoint = new Point(0, 100), EndPoint = new Point(334, 100)});
for (int i = 0; i < listMyLines.Count; i++)
{
listMyLines[i].DrawLine();
}
}
This might be better.
private void drawLInes()
{
drawLines(
new int[] { 0, 334, 100, 100 },
new int[] { 0, 334, 200, 200 },
new int[] { 112, 112, 300, 0 }
// ...
);
}
private void drawLines(params int[][] lines)
{
for (int i = 0; i < lines.Length; i++)
{
Line line = new Line();
Grid myGrid = gg;
line.Stroke = Brushes.Black;
line.X1 = lines[i][0];
line.X2 = lines[i][1];
line.Y1 = lines[i][2];
line.Y2 = lines[i][3];
line.StrokeThickness = 2;
myGrid.Children.Add(line);
}
}
Hey so I have this code here and what i am trying to do is make 2 more similar levels so when i have tile map 2 and 3 i would have a menu where the player could choose to play on a certain map... i am wondering how i would make this menu, would you please give me some insight on where to begin what type of code i could use etc.
Simple choice menu look:
Levels
Level 1
Level 2
Level 3
and the user would click on it and it would trigger/open one of the tilemaps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MarsCitadel
{
static class Tilemap
{
#region declarations
public const int TileWidth = 32;
public const int TileHeight = 32;
public const int MapWidth = 50;
public const int MapHeight = 50;
public const int FloorTileStart = 0; // 32 x 32 rectangle from sprite sheet
public const int FloorTileEnd = 3;
public const int WallTileStart = 4;
public const int WallTileEnd = 7;
static private Texture2D texturebarrens;
static private Texture2D textureroad;
//static private List<Rectangle> tiles = new List <Rectangle> ();
static private int[,] mapSquares = new int[MapWidth, MapHeight];
static private Random rand = new Random();
#endregion
#region intialization
static public void intialization(Texture2D tiletexture, Texture2D tiletexture2)
{
texturebarrens = tiletexture;
textureroad = tiletexture2;
//tiles.Clear();
//tiles.Add(new Rectangle(0, 0, TileWidth, TileHeight));
for (int x = 0; x < MapWidth; x++)
{
for (int y = 0; y < MapHeight; y++)
{
mapSquares[x, y] = FloorTileStart;
}
}
GenerateRandomMap();
}
#endregion
#region information about map squares
static public int getsquareatpixelX(int pixelX)
{
return pixelX / TileWidth;
}
static public int getsquareatpixelY(int pixelY)
{
return pixelY / TileHeight;
}
static public Vector2 getsquarebypixel(Vector2 pixellocation)
{
return new Vector2(getsquareatpixelX((int)pixellocation.X), getsquareatpixelY((int)pixellocation.Y));
}
static public Vector2 Getsquarecenter(int squareX, int squareY)
{
return new Vector2((squareX * TileWidth) + (TileWidth / 2), (squareY * TileHeight) + (TileHeight / 2));
}
static public Vector2 Getsquarecenter(Vector2 square)
{
return Getsquarecenter((int)square.X, (int)square.Y);
}
static public Rectangle Squareworldrectangle(int x, int y)
{
return new Rectangle(x * TileWidth, y * TileHeight, TileWidth, TileHeight);
}
static public Rectangle Squareworldrectangle(Vector2 square)
{
return Squareworldrectangle((int)square.X, (int)square.Y);
}
public static Rectangle Squarescreenrectangle(int x, int y)
{
return Camera.Transform(Squareworldrectangle(x, y));
}
public static Rectangle Squarescreenrectangle(Vector2 square)
{
return Squareworldrectangle((int)square.X, (int)square.Y);
}
#endregion
#region information about map tiles
static public int GetTileAtSquare(int tileX, int tileY)
{
if (((tileX >= 0) && (tileX <= MapWidth)) && ((tileX >= 0) && (tileX <= MapHeight)))
{
return mapSquares[tileX, tileY];
}
else return -1;
}
static public void SetTileAtSquare(int tileX, int tileY, int tile)
{
if (((tileX >= 0) && (tileX <= MapWidth)) && ((tileX >= 0) && (tileX <= MapHeight)))
{
mapSquares[tileX, tileY] = tile;
}
}
static public int GetTileAtPixel(int pixelX, int pixelY)
{
return GetTileAtSquare(getsquareatpixelX(pixelX), getsquareatpixelY(pixelY));
}
static public int GetTileAtPixel(Vector2 pixelLocation)
{
return GetTileAtPixel((int)pixelLocation.X, (int)pixelLocation.Y);
}
static public bool IsWallTile(int tileX, int tileY)
{
int tileindex = GetTileAtSquare(tileX, tileY);
if (tileindex == -1) return false;
return tileindex >= WallTileStart;
}
static public bool IsWallTile(Vector2 square)
{
return IsWallTile((int)square.X, (int)square.Y);
}
static public bool IsWallTileByPixel(Vector2 pixelLocation)
{
return IsWallTile(getsquareatpixelX((int)pixelLocation.X), getsquareatpixelY((int)pixelLocation.Y));
}
#endregion
#region drawing
static public void Draw(SpriteBatch spritebatch)
{
//int startX = getsquareatpixelX((int)Camera.Position.X);
//int endX = getsquareatpixelX((int)Camera.Position.X + Camera.ViewPortWidth);
//int startY = getsquareatpixelY((int)Camera.Position.Y);
//int endY = getsquareatpixelY((int)Camera.Position.Y + Camera.ViewPortHeight);
int startX = 0; int endX = 50;
int startY = 0; int endY = 50;
for (int x = startX; x <= endX; x++)
{
for (int y = startY; y <= endY; y++)
{
if ((x >= 0) && (y >= 0) && (x < MapWidth) && (y < MapHeight))
{
spritebatch.Draw(texturebarrens, new Rectangle(x * 32, y * 32, 32, 32), Color.White);
}
}
}
spritebatch.Draw(textureroad, new Rectangle(0 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(1 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(2 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(3 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(4 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(5 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(6 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(7 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(8 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(9 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(10 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(11 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(12 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(13 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(14 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(15 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(16 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(17 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(18 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(19 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(20 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(21 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(22 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(23 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(24 * 32, 7 * 32, 32, 32), Color.White);
}
#endregion
#region map generation
static public void GenerateRandomMap()
{
int WallchancePerSquare = 10;
int floorTile = rand.Next(FloorTileStart, FloorTileEnd + 1);
int wallTile = rand.Next(WallTileStart, WallTileEnd + 1);
for (int x = 0; x < MapWidth; x++)
{
for (int y = 0; y < MapHeight; y++)
{
mapSquares[x, y] = floorTile;
// if (x == 0 || y == 0 || x == MapWidth - 1 || y == MapHeight - 1)
//{
//mapSquares[x, y] = wallTile;
// continue;
// }
if (x == 1 || y == 1 || x == MapWidth - 2 || y == MapHeight - 2)
{
continue;
}
if (rand.Next(0, 100) < WallchancePerSquare)
{
mapSquares[x, y] = wallTile;
}
}
}
}
#endregion
}
}
Make the Tilemap class abstract, then each version of your map can be a different sub-class of Tilemap (there may be other ways to optimize this, try looking up some design pattern such as "decorator" or "strategy" patterns). Create a Menu class which allows the user to select a map, say with a variety of buttons. Clicking a button should then instantiate the corresponding sub-class of Tilemap, any other code can refer to these objects as Tilemap without knowing which sub-class is implemented.
I am having a crash issue with the VertexBuffer line. If I comment out the line, my program will iterate through this code 49 times. The code is from Riemer's tutorial for XNA 4.0 and does work in that solution. I have checked the 'using' statements and don't see any thing different between the two projects. I can't figure out why the VertexBuffer will crash the program while the IndexBuffer is just fine. Does anyone have any ideas?
public void CopyToTerrainBuffers()
{
for (int x = 0; x < 7; x++)
for (int y = 0; y < 7; y++)
{
if (!gpu_buffer_std[x, y].initialized)
{
VertexBuffer temp = new VertexBuffer( device,
typeof(VertexMultitextured),
tiles_std[x + 1, y + 1].terrainVertices.Length * VertexMultitextured.SizeInBytes,
BufferUsage.WriteOnly);
// size = 3,698,744
gpu_buffer_std[x, y].terrainVertexBuffer = new VertexBuffer(device,
typeof(VertexMultitextured),
tiles_std[x + 1, y + 1].terrainVertices.Length * VertexMultitextured.SizeInBytes,
BufferUsage.WriteOnly);
gpu_buffer_std[x, y].terrainIndexBuffer = new IndexBuffer( device,
typeof(int),
tiles_std[x + 1, y + 1].indices.Length,
BufferUsage.WriteOnly);
gpu_buffer_std[x, y].initialized = true;
}
if (!tiles_std[x + 1, y + 1].toGPU)
{
//gpu_buffer_std[x, y].terrainVertexBuffer.SetData(tiles_std[x + 1, y + 1].terrainVertices);
gpu_buffer_std[x, y].terrainIndexBuffer.SetData(tiles_std[x + 1, y + 1].indices);
gpu_buffer_std[x, y].terrainVertexDeclaration = VertexMultitextured.VertexDeclaration;
tiles_std[x + 1, y + 1].toGPU = true;
}
}
}
The 'temp' was to see if it was the pointer causing the problem. This is the whole function (brute force method). Here is the struct being used.
public struct VertexMultitextured : IVertexType
{
public Vector3 position;
public Vector3 normal;
public Vector4 textureCoordinate;
public Vector4 texWeights;
public static int SizeInBytes = sizeof(float) * (3 + 3 + 4 + 4);
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
new VertexElement(sizeof(float) * (3 + 3), VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(sizeof(float) * (3 + 3 + 4), VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1)
);
public VertexMultitextured(Vector3 position, Vector3 normal, Vector4 textureCoordinate, Vector4 texWeights)
{
this.position = position;
this.normal = normal;
this.textureCoordinate = textureCoordinate;
this.texWeights = texWeights;
}
public Vector3 Position
{
get { return position; }
set { position = value; }
}
public Vector3 Normal
{
get { return normal; }
set { normal = value; }
}
public Vector4 TextureCoordinate
{
get { return textureCoordinate; }
set { textureCoordinate = value; }
}
public Vector4 TexWeights
{
get { return texWeights; }
set { texWeights = value; }
}
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
}
Update: I have taken the code in question and placed it in Reimers code, and have produced the same results. The debugger shows the following:
System.OutOfMemoryException was unhandled
HResult=-2147024882
Message=Insufficient memory to continue the execution of the program.
Source=Microsoft.Xna.Framework
StackTrace:
at Microsoft.Xna.Framework.Helpers.GetExceptionFromResult(UInt32 result)
at Microsoft.Xna.Framework.Graphics.GraphicsHelpers.GetExceptionFromResult(UInt32 result)
at Microsoft.Xna.Framework.Graphics.VertexBuffer.CreateBuffer(VertexDeclaration vertexDeclaration, UInt32 dwVertexCount, UInt32 usage, _D3DPOOL pool)
at Microsoft.Xna.Framework.Graphics.VertexBuffer..ctor(GraphicsDevice graphicsDevice, Type vertexType, Int32 vertexCount, BufferUsage usage)
at Series3D4.Game1.CopyToTerrainBuffers(VertexMultitextured[] vertices, Int32[] indices) in D:\C#Programs\Series3D4\Series3D4\Series3D4\Game1.cs:line 494
at Series3D4.Game1.LoadVertices() in D:\C#Programs\Series3D4\Series3D4\Series3D4\Game1.cs:line 190
at Series3D4.Game1.LoadContent() in D:\C#Programs\Series3D4\Series3D4\Series3D4\Game1.cs:line 172
at Microsoft.Xna.Framework.Game.Initialize()
at Series3D4.Game1.Initialize() in D:\C#Programs\Series3D4\Series3D4\Series3D4\Game1.cs:line 154
at Microsoft.Xna.Framework.Game.RunGame(Boolean useBlockingRun)
at Microsoft.Xna.Framework.Game.Run()
at Series3D4.Program.Main(String[] args) in D:\C#Programs\Series3D4\Series3D4\Series3D4\Program.cs:line 13
InnerException:
Here is the class being used:
public class DisplayTileChunk
{
// Header info for tile control
public bool beenmoved; // x,z been updated after move
public bool isvisible; // render the tile on screen
public bool loaded; // tile loaded/processed in memory
public bool toGPU; // tile data transfered to GPU
// Terrain info
public int[] texture_index = new int[4];
public VertexMultitextured[] terrainVertices = new VertexMultitextured[4225]; // 65 x 65
public int[] indices = new int[24576]; // 64 x 64 x 6
public VertexBuffer terrainVertexBuffer;
public IndexBuffer terrainIndexBuffer;
public VertexDeclaration terrainVertexDeclaration;
public int noVertices; // = terrainVertexBuffer.VertexCount;
public int noTriangles; // = terrainIndexBuffer.IndexCount / 3;
// Water Info
public VertexBuffer waterVertexBuffer;
public VertexDeclaration waterVertexDeclaration;
// Vegetation Info
public VertexBuffer treeVertexBuffer;
public VertexDeclaration treeVertexDeclaration;
}
And the modified function from Reimers code:
private void CopyToTerrainBuffers(VertexMultitextured[] vertices, int[] indices)
{
terrainVertexBuffer = new VertexBuffer(device, typeof(VertexMultitextured), vertices.Length * VertexMultitextured.SizeInBytes, BufferUsage.WriteOnly);
terrainVertexBuffer.SetData(vertices);
terrainIndexBuffer = new IndexBuffer(device, typeof(int), indices.Length, BufferUsage.WriteOnly);
terrainIndexBuffer.SetData(indices);
for (int x = 0; x < 36; x++)
for (int y = 0; y < 36; y++)
{
gpu_buffer_std[x, y] = new DisplayTileChunk();
VertexBuffer test = new VertexBuffer(device, typeof(VertexMultitextured), 4225 * VertexMultitextured.SizeInBytes, BufferUsage.None);
//gpu_buffer_std[x, y].terrainVertexBuffer = new VertexBuffer(device, typeof(VertexMultitextured), gpu_buffer_std[x, y].terrainVertices.Length * VertexMultitextured.SizeInBytes, BufferUsage.WriteOnly);
//gpu_buffer_std[x, y].terrainIndexBuffer = new IndexBuffer(device, typeof(int), gpu_buffer_std[x, y].indices.Length, BufferUsage.WriteOnly);
}
}
And some interesting numbers from the debugger:
vertices.Length = 16384
terrainVertexBuffer.VertexCount = 917504
terrainVertexBuffer._vertexCount = 917504
terrainVertexBuffer._size = 51380224
test.VertexCount = 236600
test._vertexCount = 236600
test._size = 13249600
Found the problem, original line:
terrainVertexBuffer = new VertexBuffer(device,
typeof(VertexMultitextured),
vertices.Length * VertexMultitextured.SizeInBytes,
BufferUsage.WriteOnly);
Correct line:
terrainVertexBuffer = new VertexBuffer(device,
typeof(VertexMultitextured),
vertices.Length, // error was here
BufferUsage.WriteOnly);
I couldn't see the error for looking at it, took a few days off and 'boom', there it was.