How to find a path from source to target with obstacle avoidance - c#

Actually my robot wants to move from source to target with obstacle avoidance. I find out the obstacle(rectangle shape) and Target(circle shape) in pixels. But i don't know how to find the path from source to target... Please help me.
Here is the code for finding obstacle and target.
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
AForge.Point center;
float radius;
// is circle ?
if (shapeChecker.IsCircle(edgePoints, out center, out radius))
{
g.DrawEllipse(whitePen, (float)(center.X - radius), (float)(center.Y - radius),
(float)(radius * 2), (float)(radius * 2));
target.Add(center.ToString());
}
else
{
List<IntPoint> corners;
// is triangle or quadrilateral
if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
{
// get sub-type
PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
Pen pen;
if (subType == PolygonSubType.Unknown)
{
pen = (corners.Count == 4) ? redPen : bluePen;
}
else
{
pen = (corners.Count == 4) ? greenPen : brownPen;
}
g.DrawPolygon(pen, ToPointsArray(corners));
}
}
}
This above coding will detect obstacle and target position pixel values and store it in a seperate array. But from these pixel values how to calculate the path? Waiting for ur suggestions.....

Trying looking up the A* search algorithm.

I have not looked into your code but it is a classic path finding problem. One suggestion could be to map the entire area the robot moves onto a grid. The grid can have discrete cells. And then you can use any graph search algorithm to find a path from start cell to goal cell.
You can use few of the algorithms, like Dijkistra, Best-first and A-Star search algorithms. It turns out that A-Star is efficient and easy to implement. Check this, contains a nice explanation about A-Star.

Related

Object spawn on procedural terrain spawns on unspecified area

I've managed to put together a procedural terrain with defined regions and I am looking to procedurally place objects within the world within these regions. The regions are defined by their height and I am trying to utilise this to correctly place certain objects in certain regions however my result seems to come out slightly odd where objects are able to spawn outside the defined region height. I am using an AnimationCurve as a mesh height curve to prevent water areas from becoming terrain like. I am unsure if this is causing the issue behind in the correct placement. Would appreciate any insight into where I might be going wrong
Defined regions:
The Rock region is defined with a height of 0.7 and I try to spawn trees on the map only at a Rock location
Spawning object (Spawn 10) at rock location
int amount = 0;
for (int y = 0; y < mapHeight; y++)
{
if(amount < 10)
{
for (int x = 0; x < mapWidth; x++)
{
float currentHeight = noiseMap[x, y];
if(currentHeight.ToString("f1") == (0.7f).ToString())
{
Debug.Log(currentHeight.ToString("f1"));
Vector3 spawnPosition = new Vector3(Random.Range((x), (mapWidth / 2)), currentHeight, Random.Range(y, (mapHeight / 2)));
var block = Instantiate(AssetsToSpawn[0].AssetPrefab, spawnPosition, Quaternion.identity);
block.transform.SetParent(this.transform);
amount++;
break;
}
}
} else
{
return;
}
Result
Some seem to spawn in the right location albeit looking slightly weird but the one on the far left is finding itself on flat land, with water and sand; an area not defined as 0.7 or Rock type.
I think the issue lies in the line
Vector3 spawnPosition = new Vector3(Random.Range((x), (mapWidth / 2)), currentHeight, Random.Range(y, (mapHeight / 2)));
you seem to already iterate your map grid using x and y so why pick random positions on your map that might be anywhere between this current position and the center of the map?
I think you would rather want a random position within the current field and do e.g.
Vector3 spawnPosition = new Vector3(x + Random.Range(-0.5f, 0.5f), currentHeight, y + Random.Range(-0.5f, 0.5f));
Besides that why go through strings in
if(currentHeight.ToString("f1") == (0.7f).ToString())
I see that it's probably for the rounding but I would still prefer to rather do e.g.
if(Mathf.Abs(currentHeight - 0.7f) <= 0.05f)
which would have about the same effect but the threshold is better to control.
However, sounds to me like rock rather would be anything between 0.49 and 0.7 actually so actually it should be
if(currentHeight > 0.49f && currentHeight <= 0.7f)
Finally, unless you store somewhere which map position you already populated with a tree your outer for loop will always over and over enter at the exact same grid position, the first one that is encountered to fulfill your inner loop's condition!
So far you where always using the exact se position for all 10 trees, only the random position caused that it didn't seem so.

C# - Per Pixel Collision Detection

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

Find the direction of one rectangle relative to other

Problem
How can i find the direction of one rectangle w.r.t to the other. The directions i am interested is up, down, left, and right. My rectangle is represented by a Cell class. I am trying to write a function in that cell class. Function accepts a parameter of Cell type the returns the direction either 1(up) 2(down) 3(left), or 4(right) of the passed cell w.r.t to the calling cell.
What i tried
I found the mid point of both the rectangles, and then compared the x, and y coordinates. But this technique is not working in all the cases. whenever i find a missing case, i have to include more and more if statements which i think is not a good programming practice. its becoming more and more error prone and difficult to understand.
While searching for the solution: maybe math.atan2() can work in my case. Maybe i can find the angle between mid points of these 2 rectangles and use the value of angle to determine the direction. But i am not sure if my thinking is correct.
Please guide me. Should i keep using my function and rectify it, or is there a better solution such as math.atan2()? A helping image for better understanding and a required solution is demonstrated below after the code.
Code
public int dirOfThisCell(Cell cell)
{
int dir = 0;
//find mid points of both cells
PointF midPointThis = this.computeAndGetMidPoint();
PointF midPointCell = cell.computeAndGetMidPoint();
//MessageBox.Show(mess);
//if x of both points is same or with little variance because of variance in sizes of cells
===>> //Comparison Starts!!
if (midPointThis.X > midPointCell.X)
{
//this cell is to the right.
if ((midPointCell.Y) == (midPointThis.Y))
{
dir = 3;
}
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) < 5) { dir = 3; }
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) > 5) {
if (midPointThis.Y > midPointCell.Y) { dir = 1; }
else if (midPointThis.Y < midPointCell.Y) dir = 2;
}
// a considerable difference
else { dir = 3; }
//some small variations in y
//else if(Math.Abs()
}
else if (midPointThis.X < midPointCell.X)
{
// this cell is to the left
if ((midPointCell.Y) == (midPointThis.Y))
{
dir = 4;
}
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) <= 10)
{
dir = 4;
}
}
//if this cell is below
else if (midPointThis.Y > midPointCell.Y)
{
//this cell is down than the cell
if ((midPointCell.X) == (midPointThis.X))
{
dir = 1;
}
//else if (Math.Abs(midPointCell.X) - Math.Abs(midPointThis.X) < 2) { dir = 1; }
}
else if (midPointThis.Y < midPointCell.Y)
{
if ((midPointCell.X) == (midPointThis.X))
{
dir = 2;
}
}
return dir;
}
Image
Sample Image
Sample rectangles are shown in the picture number wise. The rectangle can be of single cell or made by combining multiple numbered cells.
Sample Solution required
Direction of cell 18 w.r.t to 8 should be up(1)
Direction of cell 18 w.r.t to 10 should be up(1)
Direction of cell 14 w.r.t to 13 should be right(4)
Direction of cell 9 w.r.t to 31 should be down(1)
Direction of cell 15 w.r.t to 9 should be left(3)
I am working in c#.
Any help would be much appreciated.
Thank You
Calculating the angle of the center of a rectangle compared to the center of another does not seem to be a very good idea, because the center of those rectangles are only telling you where their center is and the solution is completely reluctant to the width, height and direction of the sides. I know that the third one is not a concern in your specific case as you can safely assume that the sides are horizontal XOR vertical, but in general terms, that could be an issue as well. To calculate the relative position of Shape1 (which is a rectangle in our particular case) compared to Shape2, you need to calculate the minimum and maximum x and y for both.
Shape1 is to the left of Shape2 <=> Shape1.maxX <= Shape2.minX
Shape1 is to the right of Shape2 <=> Shape2.minX >= Shape2.maxX
Shape1 is above Shape2 <=> Shape1.maxY <= Shape2.minY
Shape2 is below Shape2 <=> Shape2.minY >= Shape1.maxY

XNA Simple Tile Map collisions

I'm new at this and I'm making a very simple 2D platformer with a level is loaded from a text file. I'm having trouble to try how to figure out how I can have my character sprite collide with the tiles.
This is an example of a .txt that my game will run:
1,1,1,1,1,1,1,1,
1,1,1,0,0,0,0,1,
1,1,0,0,0,1,0,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,1,0,0,1,
1,S,0,1,1,0,F,1,
1,1,1,1,1,1,1,1,
I've managed to figure out how to successfully draw them onto the page, but cannot progress further.
My current model has my character colliding with the edge of the screen by having a boolean for Collision equal to true when the edge of the sprite touches the edge of the screen and setting its velocity to 0, but I'm not sure how to do that to block that are generated from a .txt
My current model of drawing a level looks like this:
if (currentState == GameState.Playing)
{
for (y = 0; y <= 7; y++)
{
string[] mapchars = maplines[y].Split(','); //where maplines is each row of characters and mapchars is each individual character//
for (x = 0; x <= 7; x++)
{
if (mapchars[x] == "1")
{
spriteBatch.Begin();
spriteBatch.Draw(block, new Vector2((200 + (50 * x)), ((50 * y))), Color.White);
spriteBatch.End();
}
if (mapchars[x] == "F")
{
spriteBatch.Begin();
spriteBatch.Draw(block, new Vector2((200 + (50 * x)), ((50 * y))), Color.Yellow);
spriteBatch.End();
}
if (mapchars[x] == "S")
{
spriteBatch.Begin();
spriteBatch.Draw(sprite, new Rectangle((200 + (50 * x)), ((50 * y)), 40, 40), Color.White*0.5f);
spriteBatch.End();
}
if (x > 7)
{
break;
}
}
if (y > 7)
{
break;
}
}
}
Where maplines[] is each line of the .txt and where mapchars[] is for each individual character on each line.
If anyone knows a solution to this problem, it would be a great help :)
Thanks.
Don't do that like this ! You are wasting a lot of speed with a game coded like this. I have an issue for you.
First, get all your .txt map into a string[] wich is line is an string. Do that with the method File.ReadAllLines(string yourtxtfilepath).
Once you have done this, create an new 2 dimensional array of Block (Block[,]). You have to create an general abstract class Block wich all your types of blocks (rock, air, grass ...) inherits from its.
Create a for loop who checks all chars in all the string of the array of string you got. In that loop check if the character is an '1' or an 'F' or something else by a case statement. For example, if it was an 'F' add a new GrassBlock to your Block 2 dimensional array.
Finally, after the loop you get your map in your 2 dimensional Block array, wich is perfect to get access to all your blocks in the map.
Just put a foreach loop in the Draw() method to draw each block to your screen by incrementing their positions by the width and the heights of your tiles.
If you don't understand what I said, just do some Google searches to get the necessary knowledge so you will understand. Start by acknowledge what I try to explain you and after, you can concentrate yourself on collisions, wich is more advanced.

Ignore external points when finding rectangles

I have some images like this where I need to find the central rectangle
Im using a variation of the EmguCV examples to find rectangles and came with this
using (MemStorage storage = new MemStorage())
{ //allocate storage for contour approximation
//Contour<Point> contours = gray.FindContours()
Contour<Point> contours = gray.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST,
storage);
for (; contours != null; contours = contours.HNext)
{
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);
//Seq<Point> currentContour = contours.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE);
if (contours.Area > MinRectangleArea) //only consider contours with area greater than 20000
{
if (currentContour.Total == 4) //The contour has 4 vertices.
{
bool isRectangle = true;
Point[] pts = currentContour.ToArray();
LineSegment2D[] edges = PointCollection.PolyLine(pts, true);
for (int i = 0; i < edges.Length; i++)
{
double angle = Math.Abs(edges[(i + 1) % edges.Length].GetExteriorAngleDegree(edges[i]));
if (angle < 90 - RectangleAngleMargin || angle > RectangleAngleMargin + 90)
{
isRectangle = false;
break;
}
}
if (isRectangle)
{
boxList.Add(currentContour.GetMinAreaRect());
}
}
}
}
}
And the result of executing that over those images sometimes finds this two rectangles:
The orange rectangle is ok, thats what I need. But I dont want the blue. Sometimes the four vertex are in the border of the image, usually one of them is out.
Changing the RETR_TYPE of the FindContours function to CV_RETR_EXTERNAL, I only get the blue rectangle, so I wonder if there is an option of NOT getting the contours with external points.
The real image actually can have smaller rectangles inside the orange (or a line appears splitting the rectangle), so after that I´m selecting the bigger rectangle to be the one I want, but cant do it that way with that blue one.
Taking a look at your sample image I would choose another approach.
Instead of classical contour detection, If you perform Hough line detection and then peform intersections of line found, you will find exactly the four vertices of the rectangle you are searching for...
If you need some help in coding let me know and I will edit my answer.

Categories