The most basic way of representing a quadrile plane (a bunch of squares) is to use a two-dimensional array.
In C# we declare this as int[,] and can make our plane as big as we want:
string[3,3] => tic-tac-toe board (or similar)
string[8,8] => chess or checkers board
To "move" an item on the plane, we would just asign it toa new "position"
//using our tic-tac-toe board:
string[0,0] = "x"; //top-left
string[1,1] = "o"; //middle-middle
//to move
string[0,1] = bN; //Black Knight's starting positon
string[2,2] = bN; //Black Knight moves
string[0,1] = String.Empty;
So, how would you represent a hexagonal plane (a bunch of hexagons) and how would movement from one position to the next be handled?
Note: This is not purely theoretical, as I have an idea for a little game in my head which would require this kind of movement, but I can't wrap my head around how it would be done. I've looked through some of the other questions here, but can't really find a good match...
I do not know if this is the optimal solution but what I would do is create a new class of board the board would be a collection of "cells" each cell would contain a pointer to each of it's neighboring cell (or null if the cell is on a edge). You could implement some iterators on the board class that would walk the cells.
You would have to treat it more like a List instead of a vector. But it is at least a start.
Another solution is set you board up like this
and still just use the [,] to access each cell but it will take a little more math to figure out if you are traversing cells (Up Right is [+1,-1], Right is [+1,0], Down Right is [0,+1], Down Left is [-1,+1], Left is [-1,0], Up Left is [0,-1])
EDIT
If you want vertical walls instead of a slant just take make your width(X) equal X + Y*2 then on each row make the current row number (y) and make the cells 0 to Y-y and X-y to X off limits.
Example:
const int X = 10;
const int Y = 10;
int grid[,] = new int[X+(2*Y), Y];
bool IsCellOffLimits(int x, int y)
{
return (x < Y-y || x > X-y || y < 0 || y > Y);
}
you waste a little memory space but it gives you a board like this
If you are Very Clever© you can just use the normal space but just have your code have anything in that Y-y or X-y range be on the opposite side of the board. But ill leave that code up to the reader.
Three directions, left/right, up/down, funny angle one way/other way.
public class Player
{
public int X { get; set; }
public int Y { get; set; }
public void MoveLeft() { X++; }
public void MoveRight() { X--; }
public void MoveUp() { Y++; }
public void MoveDown() { Y--; }
public void MoveFunny() { Y++; X++; }
public void MoveOtherFunny() { Y--; X--; }
}
Related
I'm a fan of Minecraft's old terrain generation with amazing overhangs, mountains and generally interesting worlds. My problem is that right now I'm using perlin noise, which while good for smooth terrain doesn't really give sporadic jumps that would allow mountains in a mostly flat area.
On top of that with the method I'm using gets 2d perlin noise, puts it in an array and then gets every Y value under it and sets it to a block; This stops generation of overhangs like this: Old Minecraft Terrain Image
Right now I have this:
public class GenerateIdMap : MonoBehaviour {
[Serializable] public class IBSerDict : SerializableDictionaryBase<int, byte> {};
public int size = 60;
public int worldHeight = 3;
public float perlinScale = 15f;
public int seed;
public int heightScale = 10;
public int maxHeight = 256;
public IBSerDict defaultBlocks = new IBSerDict();
void Start()
{
if (seed != 0) seed = (int)Network.time * 10;
CreateMap();
}
byte[,,] CreateMap()
{
byte[,,] map = new byte[size, maxHeight, size];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
int y = (int)(Mathf.PerlinNoise((x + seed) / perlinScale, (z + seed) / perlinScale) * heightScale) + worldHeight;
y = Mathf.Clamp(y, 0, maxHeight-1);
while (y > 0)
{
map[x, y, z] = GetBlockType(y);
y--;
}
}
}
return map;
}
byte GetBlockType(int y)
{
SortedDictionary<int, byte> s_defaultBlocks = new SortedDictionary<int, byte>(defaultBlocks);
foreach (var item in s_defaultBlocks.OrderBy(key => key.Key))
{
if (y <= item.Key)
{
print(item.Value);
return item.Value;
}
}
return 0;
} }
The GetBlockType function is new and for getting the default block at that height, I'll fix it up later but it works for now. If you instantiate a prefab at that vector3 you would see terrain. Can someone help me figure out how to make better terrain? Thanks in advance!
Both of your problems should be tackled individually.
The first issue regarding the lack of variation in the generated values can usually be fixed in one of two ways, the first way is to modify the input into the perlin noise, i.e. the octaves and persistance and the second is to mix the output of multiple functions and even use the output of one function as the input to another. By functions, I mean Perlin/Simplex/Voronoi etc.
With the former method, as you mentioned, it can be pretty difficult to get terrain with interesting features over a large area (the generated values are homogeneous), but by playing with the coordinate range and octaves/persistance, it can be possible. The second approach is probably recommended however, because by mixing the inputs and outputs of different functions you can get some really interesting shapes (Voronoi produces circular crator-like shapes).
In order to fix the problem you are having with the overhangs, you would need to change your approach to generating the world slightly. Currently, you are just generating the height values of the terrain and assigning each of those values to give you the terrain surface only. What you ideally would want to do is, generate a pseudo-random value to use as a pass flag for each of the blocks in the 3d space (also those underground). The flag would indicate whether a block should be placed or not in the 3d world.
This is slower, but would generate caves and overhangs as you need.
Here's my situation I'm making a 2D maze game(XNA 4.0). I have figured out that the best way to do collision detection is by using per-pixel detection. While searching it up on the internet I have found people explaining or showing code for two things colliding(i.e. mouse & player, player & player, two shapes). What I would like to do is have this collision detect whether the player collides with a wall or not(the background is black but the maze walls are white). Could someone explain how to do this or to give some sort of starting point with the code. Much Appreciated.
P.S. A link to a website or anything relating to my question would also be helpful
The best way to go about this CPU-intensive operation is checking for hitbox collision first, then the per-pixel collision.
Most of this code can be found in this helpful video.
static bool IntersectsPixel(Rectangle hitbox1, Texture2D texture1, Rectangle hitbox2, Texture2D texture2)
{
Color[] colorData1 = new Color[texture1.Width * texture1.Height];
texture1.GetData(colorData1);
Color[] colorData2 = new Color[texture2.Width * texture2.Height];
texture2.GetData(colorData2);
int top = Math.Max(hitbox1.Top, hitbox2.Top);
int bottom = Math.Min(hitbox1.Bottom, hitbox2.Bottom);
int right = Math.Max(hitbox1.Right, hitbox2.Right);
int left = Math.Min(hitbox1.Left, hitbox2.Left);
for(y = top; y< bottom; y++)
{
for(x = left; x < right; x++)
{
Color color1 = colorData1[(x - hitbox1.Left) + (y - hitbox1.Top) * hitbox1.Width]
Color color2 = colorData2[(x - hitbox2.Left) + (y - hitbox2.Top) * hitbox2.Width]
if (color1.A != 0 && color2.A != 0)
return true;
}
}
return false;
}
You can call this method like so:
if (IntersectsPixel(player.hitbox, player.texture, obstacle.hitbox, obstacle.texture))
{
// Action that happens upon collision goes here
}
Hope I could help you out,
- GHC
Create a matrix of bools representing your sprite and a matrix of bools representing your maze (the matrix representing your sprite needs to have the same dimensions as your maze).
then you can do something simple like iterate over all x-y coordinates and check whether or not they're both true
// as an optimization, store a bounding box to minimize the
// coordinates of what you need to check
for(int i = 0; i < width, i++) {
for(int j = 0; j < height, j++) {
if(sprite[i][j] && maze[i][j]) {
collision = true
//you might want to store the coordinates
}
}
}
If you want to be very fancy you can flatten your maze matrix and use bit operations
I'm doing a text based game for a school project and I see myself stuck with a quite stupid problem.
The concept is simple, there's a map, a player, some monsters and some items.
For the map data structure I decided to use a 2d array of char's that have a unicode for content.
On top of this, I have a camera, which has a radius. The player never moves on screen, it has a x and y, but what has motion on screen is the camera itself. This works quite fine except when I get to the corners or any outside wall.
I get my camera doing this
int size = cameraSize/2;
int top = player.GetY() - size, bottom = player.GetY() + size;
char[,] camera = new char[cameraSize, cameraSize];
Console.SetCursorPosition(0,0);
for (int i = top; i < bottom; i++)
{
for (int j = top; j < bottom; j++)
{
camera[i, j] = map.ReMapPosition(i, j);
Console.Write(camera[i,j]);
}
Console.Write("\n");
}
Console.SetCursorPosition(cameraSize,cameraSize);
Console.Write(player.GetPlayerChar());
My 'cameraSize' is declared on the beginning of the class and is filled when the constructor is called
private int cameraSize;
cameraSize = difficulty.GetCameraSize();
The class 'difficulty' is irrelevant for my problem.
My problem itself is that I can't make the player positioned on the center when I get to the border walls as there is nothing to get from the array, since these are negative positions.
There are two approaches to this sort of problem.
1) In your loop, check if a value if out of range and output the value by hand.
2) Wrap your array in a custom class which ignores out of range values.
Something like this:
class MyWrapper
{
private readonly char[,] data;
public MyWrapper(char[,] data)
{
this.data=data;
}
private bool InRange(int x, int y)
{
return x >= 0 && y >= 0 && x < data.GetLength(0) && y < data.GetLength(1);
}
public char this[int x, int y]
{
get
{
return InRange(x,y) ? data[x,y] : ' ';
}
set
{
if(InRange(x,y)) data[x,y] = value;
}
}
}
My recommendation is for set to throw an exception when called on out of range values, but my example swallows the failure instead.
C# can't "retrieve values that aren't there", but you do have a couple options
Check to see if you are trying to get a negative position, or a position that's too big, and return a space
Or
Increase the size of the array by cameraSize/2 on all sides, which would effectively increase both the width and the height by cameraSize, and then make it to where your player can only move around in the coordinates (cameraSize/2,cameraSize/2) and (mapWidth-cameraSize/2,mapHeight-cameraSize/2). (<-- The coordinates might by (y,x) because of how 2d arrays work and depending on how your code is written). That way, the camera always has a padding around it, so there shouldn't ever be negative indicies
I want to check if a Rectangle(A Player) , intersects with one of the rectangles in a list (List).
I am currently using a for loop , which makes it slow , and poor performance.
for (int i = 0; i < gameObjects.objectList.Count; i++)
{
if (gameObjects.objectList[i].IntersectsWith(gameObjects.player))
{
gameObjects.objectList.RemoveAt(i); // if the player collided with an object, remove that object
}
}
How can I make it more efficient / is there another way to do it faster?
You can try organize your rectangles in a structure called k-d-tree.
It gives you up to O(log N) complexity in a large rectangle array (> 100).
F.e. make binary tree with fixed length, say, 2. Divide your space into left and right halves, then each half divide into top and bottom quarters (and so on).
Inside leaf node create a list on rectangles. If a rectangles falls into left half and top quarter, locate it in the list of this quarter.
A rectangle may be locates in a few list at the same time (f.e. in case if it falls in left and right halves).
To check intersection you should test rectangle in responding halves and quarters.
Or, you removes too many rectangles, it's faster to copy remaining rectangles into the new list in your own code.
Small example.
public enum CheckBy
{
Horizontal,
Vertical
}
public class Node
{
public Node First { get; set; }
public Node Second { get; set; }
public int Coordinate { get; set; }
public CheckBy CheckBy { get; set; }
public List<Rectangle> Rectangles { get; set; }
}
public bool IsRectangleInFist(Node node, Rectangle rectangle)
{
if (node.CheckBy == CheckBy.Horizontal)
return rectangle.Left <= node.Coordinate;
return rectangle.Top <= node.Coordinate;
}
public bool IsRectangelInSecond(Node node, Rectangle rectangle)
{
if (node.CheckBy == CheckBy.Horizontal)
return rectangle.Right >= node.Coordinate;
return rectangle.Bottom >= node.Coordinate;
}
public void AddRectangleInSuitableNode(Node node, Rectangle rectangle)
{
if (InRectangleInFirst(node, rectangle))
AddRectangleInSuitableNode(node.First, rectangle);
if (InRectangleInSecond(node, rectangle))
AddRectangleInSuitableNode(node.Second, rectangle);
}
public void SearchIntersectedRectangles(Node node, Rectangle rectangle, List<Rectangles> result)
{
// If not-leaf node
if (node.Rectangles == null && node.First != null && node.Second != null)
{
if (IsRectangleInFirst(node, rectangle))
SearchIntersecatedRectangles(node.First, rectangle, result);
if (IsRectangleInSecond(node, rectangle))
SearchIntersecatedRectangles(node.Second, rectangle, result);
return;
}
result.AddRangle(Rectangles.Where(r => r.IsIntersect(rectangle)));
}
These all lines makes simple 2D-tree. First, make the tree:
// Say, all rectangles would be inside this "space"
const int leftest = -1000;
const int rightest = 1000;
const int bottomest = -1000;
const int toppest = 1000;
// Tree with depth == 2
var tree = new Node
{
CheckBy = CheckBy.Hozirontal,
Coordinate = (leftest + rightest)/2,
First = new Node
{
CheckBy = CheckBy.Vertical,
Coordintate = (toppest + bottomest)/2,
Rectangles = new List<Rectangle>(),
},
Second = new Node
{
CheckBy = CheckBy.Vertical,
Coordintate = (toppest + bottomest)/2,
Rectangles = new List<Rectangle>(),
},
}
Then, sort all rectangles in this tree:
foreach (var rectangle in rectangles)
AddRectangleInSuitableNode(tree, rectangle);
Now you can fast get intersecting rectangles:
var intersecting = new List<Rectangles>();
SearchIntersecatedRectangles(tree, targetRectangle, intersecting);
// Here you can remove intersecting rectangles...
Basically, you need to stop checking all of the rectangles every time. You need to somehow figure out which rectangles are located in the vicinity of the player.
You could use some kind of spatial grid to store your rectangles so you could quickly find adjacent rectangles to be checked for collision. See this tutorial for example: N Tutorial B - Broad-Phase Collision.
I doubt it will be faster but you can always do it with Ling in a one liner:
gameObjects.objectList = gameObjects.objectList
.Select(go => go)
.Where(go => !go.IntersectsWith(gameObjects.player))
.ToList();
This essentially sets the list to one where any gameObject that collides with player is removed.
Also note that it is usually faster to process a sorted list first, so doing this:
gameObjects.objectList = gameObjects.objectList
.OrderBy(go => go.X)
.ThenBy(go => go.Y)
.ToList();
may help speed things up a bit. Doing this ordering every frame will be slow though so it will be worth ordering the objects as they are added to the list.
I'm looking for a way to convert 3D xyz coordinates to 2D xy (pixel) coordinates. I'm getting a list of coordinates which I need to plot on a 2d plane.
The plane will always be a top-down view width the following dimensions width:800 px, height 400px
The 3D world coordinates can contain negative values aswell ranging from -4000 to 4000. I have read a few conversion articles on Wikipedia and a couple of SO threads but they either didn't fit my needs or they were too complex for my limited math knowledge.
I hope someone can help me.
Thank you for your time.
Regards,
Mark
you can use something like [(x/z),(y/z)] to project 3d to 2d - I believe this is a fairly crude method and I would think that 3d to 2d Googlings would return some fairly standard algorithms
Rob is more or less correct, just that normally a scaling factor needs to be used (i.e [k*(x/z), k*(y/z)]). If you never change your point or direction of view, all the math you need to fully understand why this works are the intercept theorems.
I think the standard implementation of this uses so-called homogenous coordinates, which is a bit more complicated. But for a quick-and-dirty implementation just using 'normal' 3D coordinates works fine.
You also need to be a bit careful when dealing with coordinates that are behind your point of view. In fact, this is what I have found the most ugly part of (polygon-based) 3D graphics.
You may find this interesting: A 3D Plotting Library in C#.
Something that may help: Some code i'm working on...
// Location in 3D space (x,y,z), w = 1 used for affine matrix transformations...
public class Location3d : Vertex4d
{
// Default constructor
public Location3d()
{
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 1; // w = 1 used for affine matrix transformations...
}
// Initiated constructor(dx,dy,dz)
public Location3d(double dx, double dy, double dz)
{
this.x = dx;
this.y = dy;
this.z = dz;
this.w = 1; // w = 1 used for affine matrix transformations...
}
}
// Point in 2d space(x,y) , screen coordinate system?
public class Point2d
{
public int x { get; set; } // 2D space x,y
public int y { get; set; }
// Default constructor
public point2d()
{
this.x = 0;
this.y = 0;
}
}
// Check if a normal vertex4d of a plane is pointing away?
// z = looking toward the screen +1 to -1
public bool Checkvisible(Vertex4d v)
{
if(v.z <= 0)
{
return false; // pointing away, thus invisible
}
else
{
return true;
}
}
// Check if a vertex4d is behind you, out of view(behinde de camera?)
// z = looking toward the screen +1 to -1
public bool CheckIsInFront(Vertex4d v)
{
if(v.z < 0)
{
return false; // some distans from the camera
}
else
{
return true;
}
}
Some clipping to be done if the vertecies are outside the screen area !!!