public void Add(CollisionRect[] walls, byte mi, int x, int y) { Walls[x, y] = new CollisionRect[walls.Length]; WallInformation[x, y] |= mi; if (x > 0 && y > 0 && !CanMoveTo(new Point(x, y), Direction.XNZN)) { WallInformation[x - 1, y - 1] |= Direction.XPZP; } if (x < numCells.X - 1 && y > 0 && !CanMoveTo(new Point(x, y), Direction.XPZN)) { WallInformation[x + 1, y - 1] |= Direction.XNZP; } if (x > 0 && y < numCells.Y - 1 && !CanMoveTo(new Point(x, y), Direction.XNZP)) { WallInformation[x - 1, y + 1] |= Direction.XPZN; } if (x < numCells.X - 1 && y < numCells.Y - 1 && !CanMoveTo(new Point(x, y), Direction.XPZP)) { WallInformation[x + 1, y + 1] |= Direction.XNZN; } Array.Copy(walls, Walls[x, y], Walls[x, y].Length); }
public CollisionGrid(int w, int h) { cellSize = RTSConstants.CGRID_SIZE; numCells = new Point(w, h); size = new Vector2(w, h) * cellSize; EDynamic = new List <RTSUnit> [numCells.X, numCells.Y]; EStatic = new RTSBuilding[numCells.X, numCells.Y]; for (int x = 0; x < numCells.X; x++) { for (int y = 0; y < numCells.Y; y++) { EDynamic[x, y] = new List <RTSUnit>(); } } ActiveGrids = new List <Point>(); Fog = new uint[numCells.X, numCells.Y]; Collision = new bool[numCells.X, numCells.Y]; Walls = new CollisionRect[numCells.X, numCells.Y][]; WallInformation = new byte[numCells.X, numCells.Y]; Array.Clear(WallInformation, 0, WallInformation.Length); heights = new HeightTile[numCells.X, numCells.Y]; }
private static void HandleCollision(CollisionRect rect1, CollisionRect rect2) { if(rect1.IsStatic && rect2.IsStatic) return; // bottom1 means the bottom Y coordinate of rect1 // left2 means the left X coordinate of rect2 float bottom1 = rect1.Center.Y - rect1.Depth / 2; float bottom2 = rect2.Center.Y - rect2.Depth / 2; float top1 = rect1.Center.Y + rect1.Depth / 2; float top2 = rect2.Center.Y + rect2.Depth / 2; float left1 = rect1.Center.X - rect1.Width / 2; float left2 = rect2.Center.X - rect2.Width / 2; float right1 = rect1.Center.X + rect1.Width / 2; float right2 = rect2.Center.X + rect2.Width / 2; // If two rectangles collide if(top1 > bottom2 && top2 > bottom1 && left1 < right2 && left2 < right1) { // If two rectangle centers completely overlap, // slightly move one of the object's center so they don't completely overlap Vector2 d = rect2.Center - rect1.Center; if(d.Length() == 0) { d.X = r.Next(-200, 201); d.Y = r.Next(-200, 201); if(d != Vector2.Zero) { d.Normalize(); d *= 0.1f; } if(rect1.IsStatic) rect2.Center += d; else rect1.Center += d; HandleCollision(rect1, rect2); } Vector2 pushAmount = new Vector2(); // If rect2 is on the right of rect1 if(d.X > 0) { // If rect2 is below rect1 if(d.Y < 0) { if(right1 - left2 > top2 - bottom1) pushAmount.Y = top2 - bottom1 + OFFSET; // rect1 pushed up else pushAmount.X = left2 - right1 - OFFSET; // rect1 pushed left } // If rect2 is above rect1 else { if(right1 - left2 > top1 - bottom2) pushAmount.Y = bottom2 - top1 - OFFSET; // rect1 pushed down else pushAmount.X = left2 - right1 - OFFSET; // rect1 pushed left } } // If rect2 is on the left of rect1 else { // If rect2 is below rect1 if(d.Y < 0) { if(right2 - left1 > top2 - bottom1) pushAmount.Y = top2 - bottom1 + OFFSET; // rect1 pushed up else pushAmount.X = right2 - left1 + OFFSET; // rect1 pushed right } // If rect2 is above rect1 else { if(right2 - left1 > top1 - bottom2) pushAmount.Y = bottom2 - top1 - OFFSET; // rect1 pushed down else pushAmount.X = right2 - left1 + OFFSET; // rect1 pushed right } } // Push apart rectangles that are non-static if(rect1.IsStatic) rect2.Center -= pushAmount; else if(rect2.IsStatic) rect1.Center += pushAmount; else { rect1.Center += pushAmount / 2; rect2.Center -= pushAmount / 2; } } }
private static void HandleCollision(CollisionCircle circle, CollisionRect rect) { if(circle.IsStatic && rect.IsStatic) return; // Reference: stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersection/402010#402010 Vector2 d = circle.Center - rect.Center; d = new Vector2(Math.Abs(d.X), Math.Abs(d.Y)); Vector2 cd = new Vector2(d.X - rect.Width * 0.5f, d.Y - rect.Depth * 0.5f); float cornerDistSqr = cd.LengthSquared(); // If circle and rectangle collide if(d.X <= rect.Width / 2 + circle.Radius && d.Y <= rect.Depth / 2 + circle.Radius || cornerDistSqr <= circle.Radius * circle.Radius) { // If circle and rectangle centers completely overlap, // slightly move one of the object's center so they don't completely overlap if(d.Length() == 0) { d.X = r.Next(-200, 201); d.Y = r.Next(-200, 201); if(d != Vector2.Zero) { d.Normalize(); d *= 0.1f; } if(circle.IsStatic) rect.Center += d; else circle.Center += d; HandleCollision(circle, rect); } // Create a collision boundary around the rectangle, in which collision occurs float top = rect.Center.Y + rect.Depth / 2 + circle.Radius; float bottom = rect.Center.Y - rect.Depth / 2 - circle.Radius; float left = rect.Center.X - rect.Width / 2 - circle.Radius; float right = rect.Center.X + rect.Width / 2 + circle.Radius; float distToTop = Math.Abs(circle.Center.Y - top); float distToBottom = Math.Abs(circle.Center.Y - bottom); float distToLeft = Math.Abs(circle.Center.X - left); float distToRight = Math.Abs(circle.Center.X - right); // Choose the closest distance to the collision boundary as the pushing direction Vector2 pushAmount = new Vector2(); // How much should be pushed relative to circle float min = Math.Min(Math.Min(Math.Min(distToTop, distToBottom), distToLeft), distToRight); pushAmount.Y += min == distToTop ? distToTop + OFFSET : 0; pushAmount.Y += min == distToBottom ? -distToBottom - OFFSET : 0; pushAmount.X += min == distToLeft ? -distToLeft - OFFSET : 0; pushAmount.X += min == distToRight ? distToRight + OFFSET : 0; // Only move the non-static object if(rect.IsStatic) circle.Center += pushAmount; else if(circle.IsStatic) rect.Center -= pushAmount; else { circle.Center += pushAmount / 2; rect.Center -= pushAmount / 2; } } }
private static void HandleCollision(CollisionRect rect1, CollisionRect rect2) { if (rect1.IsStatic && rect2.IsStatic) { return; } // bottom1 means the bottom Y coordinate of rect1 // left2 means the left X coordinate of rect2 float bottom1 = rect1.Center.Y - rect1.Depth / 2; float bottom2 = rect2.Center.Y - rect2.Depth / 2; float top1 = rect1.Center.Y + rect1.Depth / 2; float top2 = rect2.Center.Y + rect2.Depth / 2; float left1 = rect1.Center.X - rect1.Width / 2; float left2 = rect2.Center.X - rect2.Width / 2; float right1 = rect1.Center.X + rect1.Width / 2; float right2 = rect2.Center.X + rect2.Width / 2; // If two rectangles collide if (top1 > bottom2 && top2 > bottom1 && left1 < right2 && left2 < right1) { // If two rectangle centers completely overlap, // slightly move one of the object's center so they don't completely overlap Vector2 d = rect2.Center - rect1.Center; if (d.Length() == 0) { d.X = r.Next(-200, 201); d.Y = r.Next(-200, 201); if (d != Vector2.Zero) { d.Normalize(); d *= 0.1f; } if (rect1.IsStatic) { rect2.Center += d; } else { rect1.Center += d; } HandleCollision(rect1, rect2); } Vector2 pushAmount = new Vector2(); // If rect2 is on the right of rect1 if (d.X > 0) { // If rect2 is below rect1 if (d.Y < 0) { if (right1 - left2 > top2 - bottom1) { pushAmount.Y = top2 - bottom1 + OFFSET; // rect1 pushed up } else { pushAmount.X = left2 - right1 - OFFSET; // rect1 pushed left } } // If rect2 is above rect1 else { if (right1 - left2 > top1 - bottom2) { pushAmount.Y = bottom2 - top1 - OFFSET; // rect1 pushed down } else { pushAmount.X = left2 - right1 - OFFSET; // rect1 pushed left } } } // If rect2 is on the left of rect1 else { // If rect2 is below rect1 if (d.Y < 0) { if (right2 - left1 > top2 - bottom1) { pushAmount.Y = top2 - bottom1 + OFFSET; // rect1 pushed up } else { pushAmount.X = right2 - left1 + OFFSET; // rect1 pushed right } } // If rect2 is above rect1 else { if (right2 - left1 > top1 - bottom2) { pushAmount.Y = bottom2 - top1 - OFFSET; // rect1 pushed down } else { pushAmount.X = right2 - left1 + OFFSET; // rect1 pushed right } } } // Push apart rectangles that are non-static if (rect1.IsStatic) { rect2.Center -= pushAmount; } else if (rect2.IsStatic) { rect1.Center += pushAmount; } else { rect1.Center += pushAmount / 2; rect2.Center -= pushAmount / 2; } } }
private static void HandleCollision(CollisionCircle circle, CollisionRect rect) { if (circle.IsStatic && rect.IsStatic) { return; } // Reference: stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersection/402010#402010 Vector2 d = circle.Center - rect.Center; d = new Vector2(Math.Abs(d.X), Math.Abs(d.Y)); Vector2 cd = new Vector2(d.X - rect.Width * 0.5f, d.Y - rect.Depth * 0.5f); float cornerDistSqr = cd.LengthSquared(); // If circle and rectangle collide if (d.X <= rect.Width / 2 + circle.Radius && d.Y <= rect.Depth / 2 + circle.Radius || cornerDistSqr <= circle.Radius * circle.Radius) { // If circle and rectangle centers completely overlap, // slightly move one of the object's center so they don't completely overlap if (d.Length() == 0) { d.X = r.Next(-200, 201); d.Y = r.Next(-200, 201); if (d != Vector2.Zero) { d.Normalize(); d *= 0.1f; } if (circle.IsStatic) { rect.Center += d; } else { circle.Center += d; } HandleCollision(circle, rect); } // Create a collision boundary around the rectangle, in which collision occurs float top = rect.Center.Y + rect.Depth / 2 + circle.Radius; float bottom = rect.Center.Y - rect.Depth / 2 - circle.Radius; float left = rect.Center.X - rect.Width / 2 - circle.Radius; float right = rect.Center.X + rect.Width / 2 + circle.Radius; float distToTop = Math.Abs(circle.Center.Y - top); float distToBottom = Math.Abs(circle.Center.Y - bottom); float distToLeft = Math.Abs(circle.Center.X - left); float distToRight = Math.Abs(circle.Center.X - right); // Choose the closest distance to the collision boundary as the pushing direction Vector2 pushAmount = new Vector2(); // How much should be pushed relative to circle float min = Math.Min(Math.Min(Math.Min(distToTop, distToBottom), distToLeft), distToRight); pushAmount.Y += min == distToTop ? distToTop + OFFSET : 0; pushAmount.Y += min == distToBottom ? -distToBottom - OFFSET : 0; pushAmount.X += min == distToLeft ? -distToLeft - OFFSET : 0; pushAmount.X += min == distToRight ? distToRight + OFFSET : 0; // Only move the non-static object if (rect.IsStatic) { circle.Center += pushAmount; } else if (circle.IsStatic) { rect.Center -= pushAmount; } else { circle.Center += pushAmount / 2; rect.Center -= pushAmount / 2; } } }
public void AddWalls(int x, int y, byte directions) { byte mi = 0x00; CollisionRect[] pWalls = new CollisionRect[4]; int c = 0; if ((directions & Direction.XN) != 0 && pWalls[0] == null) { mi |= Direction.XN | Direction.XNZN | Direction.XNZP; pWalls[0] = new CollisionRect( RTSConstants.CGRID_WALL_SIZE, RTSConstants.CGRID_SIZE, new Vector2( x * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_WALL_SIZE * 0.5f, y * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_SIZE * 0.5f ), true ); c++; } if ((directions & Direction.XP) != 0 && pWalls[1] == null) { mi |= Direction.XP | Direction.XPZN | Direction.XPZP; pWalls[1] = new CollisionRect( RTSConstants.CGRID_WALL_SIZE, RTSConstants.CGRID_SIZE, new Vector2( (x + 1) * RTSConstants.CGRID_SIZE - RTSConstants.CGRID_WALL_SIZE * 0.5f, y * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_SIZE * 0.5f ), true ); c++; } if ((directions & Direction.ZN) != 0 && pWalls[2] == null) { mi |= Direction.ZN | Direction.XNZN | Direction.XPZN; pWalls[2] = new CollisionRect( RTSConstants.CGRID_SIZE, RTSConstants.CGRID_WALL_SIZE, new Vector2( x * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_SIZE * 0.5f, y * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_WALL_SIZE * 0.5f ), true ); c++; } if ((directions & Direction.ZP) != 0 && pWalls[3] == null) { mi |= Direction.ZP | Direction.XNZP | Direction.XPZP; pWalls[3] = new CollisionRect( RTSConstants.CGRID_SIZE, RTSConstants.CGRID_WALL_SIZE, new Vector2( x * RTSConstants.CGRID_SIZE + RTSConstants.CGRID_SIZE * 0.5f, (y + 1) * RTSConstants.CGRID_SIZE - RTSConstants.CGRID_WALL_SIZE * 0.5f ), true ); c++; } CollisionRect[] walls = new CollisionRect[c]; c = 0; if (pWalls[0] != null) { walls[c++] = pWalls[0]; } if (pWalls[1] != null) { walls[c++] = pWalls[1]; } if (pWalls[2] != null) { walls[c++] = pWalls[2]; } if (pWalls[3] != null) { walls[c++] = pWalls[3]; } Add(walls, mi, x, y); }