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.
Related
The code i have made is hard coded and i want it to convert it into circle any snippet i can add or something
The code is in C sharp, The output is like the rectangle which i have to convert it into a circle
private void pictureBox1_Click(object sender, EventArgs e)
{
int length = 100;
int flag = 0;
int flag2 = 0;
int flag3 = 0;
Pen p = new Pen(Color.Red, 4);
Graphics g = pictureBox1.CreateGraphics();
Brush redBrush = new SolidBrush(Color.Red);
for (int i = 0; i < 20; i++)
{
if(i==0 || i<10)
{
g.DrawLine(p, 622 - 10 * i, 229+10*i, 623 - 10 * i, 229+10*i);
}
if(i==10)
{
flag = 1;
}
if(flag==1)
{
g.DrawLine(p, 622 - 10 * i, 419 - 10 * i, 623 - 10 * i, 419-10*i);
flag2 = 1;
}
if(flag2 == 1)
{
g.DrawLine(p, 622 - 10 * i, 29+10*i, 623 - 10 * i, 29+10*i);
flag3 = 1;
}
if (flag3 == 1)
{
g.DrawLine(p, 432 + 10 * i, 29+10*i, 433 + 10 * i, 29 + 10 *i);
}
}
There is a built-in function for this. Use g.DrawEllipse() instead.
You can do this
void DrawCircle(Graphics g, Pen p, Point centre, double radius=20, int sides = 360)
{
var angle = 2 * Math.PI / sides;
for (int i = 0; i < sides; i++)
{
Point from = new Point((int)(radius * Math.Sin(i * angle) + centre.X), (int)(radius * Math.Cos(i * angle) + centre.Y));
Point to = new Point((int)(radius * Math.Sin((i+1) * angle) + centre.X), (int)(radius * Math.Cos((i+1) * angle) + centre.Y));
g.DrawLine(p, from, to);
}
}
and to use
DrawCircle(g, p, new Point(100, 100), 50, 8); // 8 sides, an octagon
Increase the number of sides to make it more accurate.
Alternatively,
g.DrawEllipse(p, (float)(centre.X-radius), (float)(centre.Y-radius), (float)radius*2, (float)radius*2);
So my code I am using is below (C# in Unity)
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
public class PolygonGenerator : MonoBehaviour
{
public List<Vector3> newVertices = new List<Vector3>();
public List<int> newTriangles = new List<int>();
public List<Vector2> newUV = new List<Vector2>();
private Mesh mesh;
private float tUnitY = 0.33333f; //These are just objects I've given IDs for textures
private float tUnitX = 0.166667f;
private Vector2 tDirtBL = new Vector2(0, 0);
private Vector2 tDirtB = new Vector2(1, 0);
private Vector2 tDirtBR = new Vector2(2, 0);
private Vector2 tDirtL = new Vector2(0, 1);
private Vector2 tDirt = new Vector2(1, 1);
private Vector2 tDirtR = new Vector2(2, 1);
private Vector2 tDirtUL = new Vector2(0, 2);
private Vector2 tDirtU = new Vector2(1, 2);
private Vector2 tDirtUR = new Vector2(2, 2);
private Vector2 tStone = new Vector2(4, 1);
private int squareCount;
public byte[,] blocks;
public List<Vector3> colVertices = new List<Vector3>();
public List<int> colTriangles = new List<int>();
private int colCount;
private EdgeCollider2D col;
void Start()
{
mesh = GetComponent<MeshFilter>().mesh;
col = GetComponent<EdgeCollider2D>();
float x = transform.position.x;
float y = transform.position.y;
float z = transform.position.z;
GenTerrain();
BuildMesh();
MeshUpdate();
}
void GenSquare(int x, int y, Vector2 texture) //This creates the blocks I can apply textures to
{
newVertices.Add(new Vector3(x, y, 0));
newVertices.Add(new Vector3(x + 1, y, 0));
newVertices.Add(new Vector3(x + 1, y - 1, 0));
newVertices.Add(new Vector3(x, y - 1, 0));
newTriangles.Add(squareCount * 4);
newTriangles.Add((squareCount * 4) + 1);
newTriangles.Add((squareCount * 4) + 3);
newTriangles.Add((squareCount * 4) + 1);
newTriangles.Add((squareCount * 4) + 2);
newTriangles.Add((squareCount * 4) + 3);
newUV.Add(new Vector2(tUnitX * texture.x, tUnitY * texture.y + tUnitY));
newUV.Add(new Vector2(tUnitX * texture.x + tUnitX, tUnitY * texture.y + tUnitY));
newUV.Add(new Vector2(tUnitX * texture.x + tUnitX, tUnitY * texture.y));
newUV.Add(new Vector2(tUnitX * texture.x, tUnitY * texture.y));
squareCount++;
}
void MeshUpdate() //This merely updates the mesh
{
mesh.Clear();
mesh.vertices = newVertices.ToArray();
mesh.triangles = newTriangles.ToArray();
mesh.uv = newUV.ToArray();
mesh.RecalculateNormals();
squareCount = 0;
newVertices.Clear();
newTriangles.Clear();
newUV.Clear();
Mesh newMesh = new Mesh();
newMesh.vertices = colVertices.ToArray();
newMesh.triangles = colTriangles.ToArray();
col.sharedMaterial = newMesh;
colVertices.Clear();
colTriangles.Clear();
colCount = 0;
}
void GenTerrain() //Generates terrain based on parameters I supply and I can add in
{ //PerlinNoise to create variable terrain instead of flat
blocks = new byte[512, 128];
for (int px = 0; px < blocks.GetLength(0); px++) //Also tells which blocks are which
{
int stone = Noise(px, 0, 80, 15, 1);
stone += Noise(px, 0, 50, 30, 1);
stone += Noise(px, 0, 10, 10, 1);
stone += 75;
print(stone);
int dirt = Noise(px, 0, 25f, 35, 1);
dirt += Noise(px, 100, 50, 30, 1);
dirt += 75;
for (int py = 0; py < blocks.GetLength(1); py++)
{
if (py < stone)
{
blocks[px, py] = 1;
//The next three lines make dirt spots in random places
if (Noise(px, py, 12, 16, 1) > 10)
{
blocks[px, py] = 2;
}
//The next three lines remove dirt and rock to make caves in certain places
if (Noise(px, py * 2, 16, 14, 1) > 10)
{ //Caves
blocks[px, py] = 0;
}
}
else if (py < dirt)
{
blocks[px, py] = 2;
}
}
}
}
void BuildMesh() //Mesh Creation
{
for (int px = 0; px < blocks.GetLength(0); px++)
{
for (int py = 0; py < blocks.GetLength(1); py++)
{
if (blocks[px, py] != 0)
{
GenCollider(px, py);
}
if (blocks[px, py] == 1)
{
GenSquare(px, py, tStone);
}
else if (blocks[px, py] == 2)
{
GenSquare(px, py, tDirtU);
}
}
}
}
void GenCollider(int x, int y)
{
//Top
if (Block(x, y + 1) == 0)
{
colVertices.Add(new Vector3(x, y, 1));
colVertices.Add(new Vector3(x + 1, y, 1));
colVertices.Add(new Vector3(x + 1, y, 0));
colVertices.Add(new Vector3(x, y, 0));
ColliderTriangles();
colCount++;
}
//Bottom
if (Block(x, y - 1) == 0)
{
colVertices.Add(new Vector3(x, y - 1, 0));
colVertices.Add(new Vector3(x + 1, y - 1, 0));
colVertices.Add(new Vector3(x + 1, y - 1, 1));
colVertices.Add(new Vector3(x, y - 1, 1));
ColliderTriangles();
colCount++;
}
//Left
if (Block(x - 1, y) == 0)
{
colVertices.Add(new Vector3(x, y - 1, 1));
colVertices.Add(new Vector3(x, y, 1));
colVertices.Add(new Vector3(x, y, 0));
colVertices.Add(new Vector3(x, y - 1, 0));
ColliderTriangles();
colCount++;
}
//Right
if (Block(x + 1, y) == 0)
{
colVertices.Add(new Vector3(x + 1, y, 1));
colVertices.Add(new Vector3(x + 1, y - 1, 1));
colVertices.Add(new Vector3(x + 1, y - 1, 0));
colVertices.Add(new Vector3(x + 1, y, 0));
ColliderTriangles();
colCount++;
}
}
void ColliderTriangles()
{
colTriangles.Add(colCount * 4);
colTriangles.Add((colCount * 4) + 1);
colTriangles.Add((colCount * 4) + 3);
colTriangles.Add((colCount * 4) + 1);
colTriangles.Add((colCount * 4) + 2);
colTriangles.Add((colCount * 4) + 3);
}
byte Block(int x, int y)
{
if (x == -1 || x == blocks.GetLength(0) || y == -1 || y == blocks.GetLength(1))
{
return (byte)1;
}
return blocks[x, y];
}
int Noise(int x, int y, float scale, float mag, float exp)
{
return (int)(Mathf.Pow((Mathf.PerlinNoise(x / scale, y / scale) * mag), (exp)));
}
}
The code has been modified from its original in order to accommodate BoxCollider2D but is giving me an error. This script is used alongside a Mesh Filter, Mesh Collider (Trying to replace this with a box collider for a 2D game), and a Mesh Renderer on an Empty that was created in Unity.
Is there any viable solution I can use, instead of generating a mesh collider alongside the tiles, in order to make a box collider generate with it? If any further details are needed just ask.
So I'm stuck on how to be able to convert my mouse position in monogame/XNA to a position of my grid. What I am trying to achieve is basically to change the color of the rectangle on that specific cell in the grid to a different color when I click on them.
This is my first time working on a grid system and I don't really have a clue on how to do this.
Here is how I built my grid. What basically happens here is I first populate every cell in the grid with 0s. And depending on what value I assign in the update method in the Game1 class, the color of the rectangle will change.
Thank you!
public int[,] gridCell;
Texture2D texture;
public Rectangle rect;
int col;
int row;
const int gridSize = 32;
//Initializes the constructor
public Grid(int sizeCol, int sizeRow)
{
//texture = sprite;
col = sizeCol;
row = sizeRow;
gridCell = new int[col, row];
for(int i = 0; i<col;i++)
{
for(int j = 0; j<row;j++)
{
gridCell[i, j] = 0;
}
}
}
public void Draw(SpriteBatch spritebatch)
{
for (int i = 0; i <= col-1; i++)
{
for (int j = 0; j <= row-1; j++)
{
if (gridCell[i, j] == 0)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.CornflowerBlue, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
else if( gridCell[i,j] == 1)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Yellow, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
else if (gridCell[i, j] == 2)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Red, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
else if (gridCell[i, j] == 3)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Purple, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
else if (gridCell[i, j] == 4)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Blue, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
else if (gridCell[i, j] == 5)
{
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Black, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
}
}
}
Ok, here is how it goes: lets say your grid's one square is 8x8. Position of your mouse can be between 8 and 0, and you need it to be only 0/8/16/24/... When you divide mouse position by 8 (lets say Mposition is 4x20), you'll get 0.5x2.5, and if you multiply that with 8, you'll get 4x20 again, BUT: if you truncate division result, youll get 0x2, and that multiplied by 8 is 0x16, so that (0x16) is the real position of the square that mouse is inside of, and 0x2 is the matrix position of your mouse. Here is a simple function that will get you what you need:
public Vector2 PositionByGrid (int gridSize)
{
Vector2 result = new Vector2(MouseState.GetState().X, MouseState.GetState().Y);
result.X = (int)(result.X / gridSize) * gridSize;
result.Y = (int)(result.Y / gridSize) * gridSize;
return result;
}
This function will return position of the square. If you want the position in matrix, just put result.X = (int)(result.X / gridSize); instead of result.X = (int)(result.X / gridSize) * gridSize;
EDIT:
As #Slubberdegullion suggested, here is the function if your grid is not in squares, but in rectangles (same principle for the matrix applies):
public Vector2 PositionByGrid (int gridWidth, int gridHeight)
{
Vector2 result = new Vector2(MouseState.GetState().X, MouseState.GetState().Y);
result.X = (int)(result.X / gridWidth) * gridWidth;
result.Y = (int)(result.Y / gridHeight) * gridHeight;
return result;
}
EDIT 2:
This is a suggestion
Also, you could shorten the Draw function, to look like this (explanation in Suggestion No2):
public void Draw(SpriteBatch spritebatch)
{
for (int i = 0; i <= col-1; i++)
{
for (int j = 0; j <= row-1; j++)
{
Color newColor;
switch(gridCell[i, j])
{
case 0: newColor = Color.CornflowerBlue; break;
case 1: newColor = Color.Yellow; break;
case 2: newColor = Color.Red; break;
case 3: newColor = Color.Purple; break;
case 4: newColor = Color.Blue; break;
case 5: newColor = Color.Black; break;
default: newColor = Color.White; break;
}
spritebatch.FillRectangle(i * 32, j * 32, 31, 31, newColor, 0f);
spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
}
}
}
It is true that this will use a bit more RAM (equal to adding 4 new integer variables to the game because color is a Vector4 basicaly but with int instead of float) and CPU time, but that cost is very low for the cost of your games integrity and readability.
Suggestion No2: From your code I beleave I see that you are a beginner, and with that said, I feel my obligation is to tell you not to repeat the same (group of) lines of code, in code. Instead, create a function / do what I did with your Draw function / etc. Your way, if you get to the point where you have to change 1 thing, you'll have to change it in X places. And what if then you have to change it again, or a couple more times? By keeping repetative code in one function, when need arises, you'll have to change that 1 thing only in that function.
Generate an array of collision rectangles for your grid when you construct your grid.
Rectangle[,] gridRects = new Rectangle[row, col];
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
gridRects[i,j] = new Rectangle(i * gridSize, j * gridSize, gridSize, gridSize);
}
}
Then for every frame, in Update, check for collisions
MouseState ms = Mouse.GetState();
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (gridRects.Contains(ms.X, ms.Y))
{
// Mouse is on gridCell[i,j]
}
}
}
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 });
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector2 mouseCoord = GetMouseTilePosition();
if (mouseCoord.X > 0)
{
spriteBatch.Draw(selection, tileRect = new Rectangle((int)mouseCoord.X * 64, (int)mouseCoord.Y * 64, 64, 64),
Color.White);
}
spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
}
}
public Vector2 GetMouseTilePosition()
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (IsMouseInsideTile(x, y))
{
return new Vector2(x, y);
}
}
}
return new Vector2(-1, -1);
}
public bool IsMouseInsideTile(int x, int y)
{
MouseState MS = Mouse.GetState();
return (MS.X >= x * 64 && MS.X <= (x + 1) * 64 &&
MS.Y >= y * 64 && MS.Y <= (y + 1) * 64);
}
It is very cpu intensive. Is there a better way to do this code? Also I have a camera how can I change this to factor that in so I get the actual mouse position
Jon Skeet is right, you could directly call IsMouseInsideTile() instead of looping through your array several times. (Currently, you're checking where the mouse is in the whole tile array, for each tile, instead of only checking the current tile you're in).
public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (IsMouseInsideTile(x, y))
{
spriteBatch.Draw(selection, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
}
}
I'm sorry, it's all my fault, I submitted this code quickly earlier without double checking. This new version should improve your performance drastically.