If position is between two points on a line with variable width - c#

I have a coordinate grid in a 2D game.
I need to, on a line with variable width, find multiple targets for a projectile of a particular size.
The coordinates are absolute integer values.
In my grid, and for my situation, it's different from a typical X and Y axis.
For north, it's X-1, Y-1. South, X+1, Y+1. A diamond pattern.
0,0
0,1 1,1 1,0
0,2 1,2 2,2 2,1 2,0
0,3 1,3 2,3 3,3 3,2 3,1 3,0
etc...
There are no negative coordinates.
Here is a visual example of what I hope to accomplish.
The two black lines represent an individual target area of individual collections, each of the red dots represent an object which needs to be verified as an object within a black line.
This is the original functional code that I want to adapt or replace.
The collection of coordinates it makes, in a line, is of a fixed width. I need something that can make a wider line of targeted coordinates when needed.
List<coords> line(int xa, int ya, int xb, int yb)
{
int dx = xb - xa, dy = yb - ya, steps, k;
float xincrement, yincrement, x = xa, y = ya;
if (Math.Abs(dx) > Math.Abs(dy)) steps = Math.Abs(dx);
else steps = Math.Abs(dy);
xincrement = dx / (float)steps;
yincrement = dy / (float)steps;
var thisLine = new List<coords> {new coords(Math.Round(x), Math.Round(y))};
for (k = 0; k < MaxDistance; k++)
{
x += xincrement;
y += yincrement;
thisLine.Add(new coords(Math.Round(x), Math.Round(y)));
}
return thisLine;
}
Any answer should keep in mind that the collection is time sensitive and that performance is important since this will be used in a server environment.

Related

Pythagorean Theorem to check whether a cell is inside the radius

I have the dimensions of a matrix and a given cell with radius.
So let's take a look at this example:
The matrix has 5 rows and 6 columns. We are given the cell (2, 3) with radius 2. It has an impact, and it destroys all of the items in a certain radius (the impact cell is shaded black and the other cells within the radius are shaded grey). I found that I could use the Pythagorean Theorem to check whether a cell is inside the radius:
if (Math.Pow(targetRow - row, 2) + Math.Pow(targetColumn - col, 2) <= radius * radius)
{
matrix[row, col] = 1;
}
I don't understand why it works, and I would be very grateful if you could explain it to me. I tried to debug, but I still don't get it.
It works, because you can think of the radius of a circle as of the hypotenuse of a right triangle and, if the center of the circle is at the origin (0, 0) of the coordinate system, the x- and y-coordinates are the other two sides (the catheti).
Now let's call the two catheti a and b and the hypotenuse c. Then we following equation is true:
c2 = a2 + b2       (the Pythagorean theorem)
In your case a and b are targetRow - row and targetColumn - col and c is radius.
I don't know how Math.Pow is implemented, but it works on doubles and is rather expensive. Do the math with integers.
int dr = targetRow - row;
int dc = targetColumn - col;
if (dr * dr + dc * dc <= radius * radius)
{
matrix[row, col] = 1;
}
A side note: The distance calculated with the Pythagorean theorem is the Euclidean distance:
dEuclidean = √(dx2 + dy2)
It is appropriate for your problem. But there are other ways of defining the distance. Especially in a matrix.
A taxi in Manhattan first drives along the north-south axis, then makes a right angle turn and drives along the east-west axis to reach a target. This is Taxicab geometry. The shortest possible drive is called the Manhattan distance:
dManhattan = |dx| + |dy|
On a chessboard kings and queens can move horizontally, vertically and along diagonals. The minimum distance under these circumstances is called Chebyshev distance or Chess distance
dChebyshev = max(|dx|, |dy|)
I'm not sure what there is more to explain than the Pythagorean theorem just the equation for a circle x^2 +y^2 = r^2.
Thus in looping you're evaluating whether the evaluated point falls inside the circle.
Check if this helps: Pythagorean Theorem in Circles

Space represented by a single Kinect pixel at a given depth

Basically I want to take a fixed straight line across the devices point of view and determine if anything intercepts it but in my example I want to make the "laser line" configurable with regards to the distance from the top of the field of view.
Now it's easy enough to get the depth data at a given pixel point simply by doing this.
var depthInMM = DepthImagePixel.Depth;
and its also easy to simply say I want to focus on the 100th line of pixels from the top by doing something like this.
for (int i = 0; i < this._DepthPixels.Length; ++i) //_DepthPixels.Length is obviously 307200 for 640x480
{
if (i >= 64000 && i <= 64640) //Hundredth vertical pixel line
{
//Draw line or whatever
}
}
Which ends up with something like this.
BUT for example I might want to have the line intercept at 50 cm from the top of the field of view at 3 meters depth. Now obviously I understand that as the depth increases so does the area represented but I cannot find any reference or myself work out how to calculate this relationship.
So, how can one calculate the coordinate space represented at a given depth utilizing the Kinect sensor. Any help sincerely appreciated.
EDIT:
So if I understand correctly this can be implemented as such in C#
double d = 2; //2 meters depth
double y = 100; //100 pixels from top
double vres = 480; //480 pixels vertical resolution
double vfov = 43; //43 degrees vertical field of view of Kinect
double x = (2 * Math.Sin(Math.PI * vfov / 360) * d * y) / vres;
//x = 0.30541768893691434
//x = 100 pixels down is 30.5 cm from top field of view at 2 meters depth
2 sin(PI VFOV / 360) D Y
X = --------------------------
VRES
X: distance of your line from the top of the image in meters
D: distance - orthogonal to the image plane - of your line from the camera in meters
Y: distance of your line from the top of the image in pixels
VRES: vertical resolution of the image in pixels
VFOV: vertical field of view of the camera in degrees

c# / XNA 4.0- Move textures to give illusion of infinite plane

I've been having trouble implementing an algorithm to shift my textures given their positions and the cameras position. The first two pictures in the image explain what I'm trying to accomplish, but I can't figure out how to move them accordingly. I had created a program once upon a time that did this, but I've gone and lost it. Any ideas?
If it helps any, the Cameras/Viewports width and height are the same as the textures' width and height. The goal is the get them to shift positions, giving the illusion of an infinite plane. (With out having to draw an infinite plane, lol.)
You do not really need to move your regions, enough to decide where to draw them. Lets assume you have a terrain containing N*M blocks (in this case N=M=2), each of them are size of A*A (in this case the screen hase the same size, but this doesn't matter), and the Tiles are continously following each other.
int LeftColumn = Camera.X / A; // let it round to nearest lower int
int TopRow = Camera.Y / A;
LeftColumn = LeftColumn % N; // Calculate the first tile
TopRow = TopRow % M;
for (int i = LeftColumn+N; i < LeftColumn+2*N; i++)
for (int l = TopRow+M; l < TopRow+2*M; l++)
// you may check here if the tile is visible or not based on the screen size
{
Tile[i % N, l % M].Draw(i*A, l*A); // Or do whatever you like
}
Is this clear?
After a couple hours of trial and error, I finally figured out how to get the regions/textures/rectangles to move accordingly. For those who want the solution,
if ((int)Math.Abs(region.X - camPos.X) > region.Width * 2)
{
region.X += region.Width * 2;
}
if (camPos.X < region.X - region.Width)
{
region.X -= region.Width * 2;
}
if ((int)Math.Abs(region.Y - camPos.Y) > region.Height * 2)
{
region.Y += region.Height * 2;
}
if (camPos.Y < region.Y - region.Height)
{
region.Y -= region.Height * 2;
}
Where camPos is the camera position, and region is the region/texture/rectangle/whatever.
This code works for a 4 square region (2 regions by 2 regions). To change for more regions, simply change all the *2s to *3s or *4s for a 9 square region and 16 square region, respectively.

C# / XNA - 2D collision engine glitch?

I've got quite a lot of code here, but it's relatively straightforward.
This is all snippets from different classes, all references are right, but I think I've done a math-based error somewhere and I can't find it. It always finds a collision on the y axis a pixel before it should. I haven't tried it with different X axis positions but it seems to fall past blocks next to it fine.
The struct "mapSection" just contains two Vector2s- A top-left block and bottom-left block coordinate.
tileManager.def_ts is the default tile width and height (32). The player's size is 32x64.
The toWorldSpace function does nothing right now other than return so that's not the problem.
When I say block coordinate I mean which index the block is in the tile array (Ex 0, 0 is the first block, 0, 1 is the second block on the Y axis, 1, 3 is 1 block in on the X axis and 3 on the Y axis, I do not mean actual pixels.)
From tile engine class:
public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
position = toWorldSpace(position);
position.X = (float)Math.Floor(position.X / tileManager.def_ts);
position.Y = (float)Math.Floor(position.Y / tileManager.def_ts);
size.X = (float)Math.Floor(size.X / tileManager.def_ts);
size.Y = (float)Math.Floor(size.Y / tileManager.def_ts);
return new mapSection(position, position + size);
}
public bool collision(Vector2 screenPosition, Vector2 size)
{
mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size);
for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++)
{
for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++)
{
if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count)
{
if (tileManager.tileTypes[tiles[y][x]].collideable == true)
{
return true;
}
}
}
}
return false;
}
And this is the code from the player class:
if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64)))
{
position.Y += 1;
}
I add "Vector2(0, 1)" because I want to see if there's a collision a pixel further down; so that he falls until he hits something. It's very basic right now but it's only to test the collision engine, which isn't working.
There's a picture of the error. You can see the player is a pixel too high.
In the picture, "X:" is the top-left block coordinate on X axis, "X2:" is the bottom-right block coordinate on the X axis, and same with "Y:" and "Y2: except Y axis. They're read from the mapSection directly.
If anyone can notice why this is happening, it would be massively appreciated.
Thanks.
If you cannot understand any section of the code just post in the comments and I'll be happy to explain, or if you think I've been a bit too unspecific in some area of this post.
EDIT: For the tile coordinates issue, your toMapMinMax code should be more like this:
EDIT2: have subtracted (1, 1) from bottomRight, since it is a size we are adding.
public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
Vector2 topLeft = position;
Vector2 bottomRight = position + size - new Vector2(1, 1);
topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts);
topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts);
bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts);
bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts);
return new mapSection(topLeft, bottomRight);
}
Also, I was wrong in my above comment; you do want <= signs in your two for loops, because most of the time you will be checking 6 tiles.
for the off-by-one-pixel issue:
In order for you to see the character off by some amount of pixels, the draw code and the collision code must be different. If they were identical, for example if they were both off by 15 pixels (you collide 15 pixels too early, but you are also drawing 15 pixels ahead), you wouldn't see any change.
The 1 pixel gap indicates a 1 pixel difference between the draw coordinate calculation and the collision coordinate calculation. This 1 pixel difference is most likely caused by differences in rounding, probably that you are calling Math.Floor in the collision code, but are not rounding the coordinates in the draw code. (I would guess you are probably just passing the position Vector2 straight to the SpriteBatch.Draw method).

Per Pixel Collision - Code explanation

I'm currently trying to understand per pixel collision detection.
This is the code I don't understand:
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
I really haven't understood the all loop. I'll be glad for some explanation how it works.
First up, it finds the region the two image rectangles intersect, then it iterates through each pixel in that region, and compares the alpha values of each image of each pixel. If neither has an alpha value of 0, they are both considered 'solid' and therefore colliding.
it's not that hard (in this case) - you give the algorithm the two bounding-boxes of your objects (so the hole object is inside this box), and a array with color-information for them.
Tha algorithm assumes that a point belongs to the object IFF it is not transparent - this is important.
The first step is to calculate the intersecting rectangle - if you intersect two rectangles that have sides parallel to the axes like in this case - you will get a rectangle again or an empty set.
The next step is to iterate in this intersecting rectangle for all (x,y) -coordinates insiede - first y, then x -so you get your normal first x, then y inside, but this is minor point and not important.
Then finally the algorithm gets the color for object A and B at the current pixel (x,y) - if both colors are NOT transparent then the pixel is in both objects and the objects have to intersect at this point - so the algorithm terminates with "YES they intersect"
If all pixels in the intersection of the bounding boxes where checked and no common (e.g. not transparent) pixel was found the object don't intersect and so the algorithm terminates with "NO they don't intersect"
I hope this helps.
for (int y = top; y < bottom; y++) loops over the lines of the resulting rectangle from top to bottom, and for (int x = left; x < right; x++) loops over pixels inside each line, left to right.

Categories

Resources