// Self-explanatory public void SetMapValue(Coords number, float newValue) { // Perhaps should throw exception if (!(_currentMap.MyCollider.CheckInBounds(number))) return; this._influenceMap[number.X, number.Y] = newValue; }
// Self-explanatory public float GetMapValue(Coords number) { // Perhaps should throw exception if (!(_currentMap.MyCollider.CheckInBounds(number))) return 0; return this._influenceMap[number.X, number.Y]; }
private LinkedList<Creature>[,] _residents;// = new LinkedList<Creature>(); public LinkedList<Creature> VisibilityResidents(Coords c) { if (c.Type == CoordsType.Tile) { return _residents[c.X, c.Y]; } return _residents[c.X / _pixelsPerBoxX, c.Y / _pixelsPerBoxY]; }
// returns the item's position (in Coords) public Nullable<Coords> Position() { Nullable<Coords> returnValue = null; if (this._ownerTile != null) { returnValue = _ownerTile.Position; } else if (this._ownerCreature != null) { returnValue = new Coords(CoordsType.Tile, _ownerCreature.PositionPixel); } return returnValue; }
/// <summary> /// Returns the Direction in which a vector is pointing. /// </summary> public static Nullable<Direction> DirectionVectorToDirection(Coords dirvector) { if (dirvector.X == 0 & dirvector.Y == 0) { return null; } // The angle is clockwise from the negative X, Y=0 axis. Note the positive Y-axis points down. double angle; angle = Math.Atan2(dirvector.Y, dirvector.X) + Math.PI; Direction moveDir = (Direction) (byte)((((angle + 0.125 * Math.PI) / (0.25 * Math.PI)) + 5) % 8); return moveDir; }
// Generates a rectangular room private void GenerateRectangularRoom(Map homeMap, Coords topLeft, Coords bottomRight) { Coords difference = bottomRight - topLeft; if (!(difference.X > 1 && difference.Y > 1)) { return; } // Walls FillRectangleWithTiles(homeMap, topLeft, new Coords(CoordsType.Tile, topLeft.X, bottomRight.Y), Constants.TileGeneratorWallStone); FillRectangleWithTiles(homeMap, topLeft, new Coords(CoordsType.Tile, bottomRight.X, topLeft.Y), Constants.TileGeneratorWallStone); FillRectangleWithTiles(homeMap, new Coords(CoordsType.Tile, topLeft.X, bottomRight.Y), bottomRight, Constants.TileGeneratorWallStone); FillRectangleWithTiles(homeMap, new Coords(CoordsType.Tile, bottomRight.X, topLeft.Y), bottomRight, Constants.TileGeneratorWallStone); // Floor this.FillRectangleWithTiles(homeMap, new Coords(CoordsType.Tile, topLeft.X + 1, topLeft.Y + 1), new Coords(CoordsType.Tile, bottomRight.X - 1, bottomRight.Y - 1), Constants.TileGeneratorFloorDirt); // Open door. For now by default door is in the top-left corner. Coords doorSpot = new Coords(CoordsType.Tile, topLeft.X + 1, topLeft.Y); homeMap.SetTile(doorSpot, new TilePassable(homeMap, doorSpot, Constants.TileGeneratorFloorDirt)); }
/// <summary> /// Returns the Coords that neighbour 'here' in 'direction'. /// Note C# forms coordinate system has origin at the top-left /// </summary> public static Coords CoordsNeighboringInDirection(Coords here, Direction direction) { switch (direction) { case (Direction.Northeast): return new Coords(here.Type, here.X + 1, here.Y - 1); case (Direction.East): return new Coords(here.Type, here.X + 1, here.Y); case (Direction.Southeast): return new Coords(here.Type, here.X + 1, here.Y + 1); case (Direction.South): return new Coords(here.Type, here.X, here.Y + 1); case (Direction.Southwest): return new Coords(here.Type, here.X - 1, here.Y + 1); case (Direction.West): return new Coords(here.Type, here.X - 1, here.Y); case (Direction.Northwest): return new Coords(here.Type, here.X - 1, here.Y - 1); case (Direction.North): return new Coords(here.Type, here.X, here.Y - 1); } // This code should be unreachable. Added because compiler wants it. return here; }
// Furnishes a rectangular room with appropriate furniture private void FurnishRectangularWorkshop(Map homeMap, Coords topLeft, Coords bottomRight) { // put a bed in the middle of it Coords toolTableLocation = new Coords(CoordsType.Tile, (Int32)((bottomRight.X + topLeft.X) * 0.5), (Int32)((bottomRight.Y + topLeft.Y) * 0.5)); homeMap.CreateItem(toolTableLocation, Constants.ItemGeneratorToolTable); }
/// <summary> /// Returns the eucledean distance between two Coords /// </summary> public static float DistanceBetweenTwoCoordsEucledean(Coords c1, Coords c2) { return (float)Math.Sqrt(Math.Pow((c1.X - c2.X), 2) + Math.Pow((c1.Y - c2.Y), 2)); }
public static Int32 DistanceBetweenTwoCoordsEucledeanSquared(Coords c1, Coords c2) { Int32 dx = c1.X - c2.X; Int32 dy = c1.Y - c2.Y; return (dx * dx + dy * dy); }
public Vector(Coords c) { if (c.Type == CoordsType.Tile) { c = new Coords(CoordsType.Pixel, c); } _X = c.X; _Y = c.Y; }
public static Coords CoordsAverage(Coords c1, Coords c2) { return new Coords(c1.Type, (Int32)0.5 * (c1.X + c2.X), (Int32)0.5 * (c1.Y + c2.Y)); }
public float DistanceTo(Coords c) { return((float)Math.Sqrt(Math.Pow((this.X - c.X), 2) + Math.Pow((this.Y - c.Y), 2))); }
/// <summary> /// Spawns the player on the 'ground' at 'startPoint' /// returns a reference to the Player so one can more easily take care of references. /// </summary> public Creature SpawnPlayer(Coords startPoint) { //Player player = new Player(this, startPoint, this.IssueCreatureID()); //this.PlayerReference = player; return null; }
/// <summary> /// Tile-level (coarse) A* pathfinding. /// </summary> /// <param name="start"> Start Coords </param> /// <param name="end"> Target tile Coords </param> /// <param name="h"> Heuristic function </param> /// <returns> Route to goal, as a list of Directions </returns> public List <Direction> PathfinderAStarCoarse(Coords start, Coords end, HeuristicFunction h) { return(this.PathfinderAStarCoarse(start, end, end, h)); }
/// <summary> /// Tile-level (coarse) A* pathfinding. /// </summary> /// <param name="start"> Start Coords </param> /// <param name="endTopLeft"> Goal-box TopLeft Coords </param> /// <param name="endBottomRight"> Goal-box BottomRight Coords </param> /// <param name="h"> Heuristic function </param> /// <returns> Route to goal, as a list of Directions </returns> public List <Direction> PathfinderAStarCoarse(Coords start, Coords endTopLeft, Coords endBottomRight, HeuristicFunction h) { return(this._PathfinderAStar(new Coords(CoordsType.General, start), new Coords(CoordsType.General, endTopLeft), new Coords(CoordsType.General, endBottomRight), this._passabilityMap, delegate(Coords c) { return h(c, StaticMathFunctions.CoordsAverage(endTopLeft, endBottomRight)); })); }
/// <summary> /// returns the distance between two Coords /// </summary> public static float DistanceBetweenTwoCoordss(Coords c1, Coords c2) { return(Math.Max(Math.Abs(c1.X - c2.X), Math.Abs(c1.Y - c2.Y))); }
/// <summary> /// Returns the eucledean distance between two Coords /// </summary> public static float DistanceBetweenTwoCoordsEucledean(Coords c1, Coords c2) { return((float)Math.Sqrt(Math.Pow((c1.X - c2.X), 2) + Math.Pow((c1.Y - c2.Y), 2))); }
public static bool CoordinateIsInBox(Coords c, Coords boxTopLeft, Coords boxBottomRight) { return(((c.X >= boxTopLeft.X) && (c.X <= boxBottomRight.X)) && ((c.Y >= boxTopLeft.Y) && (c.Y <= boxBottomRight.Y))); }
public static Coords CoordsAverage(Coords c1, Coords c2) { return(new Coords(c1.Type, (Int32)0.5 * (c1.X + c2.X), (Int32)0.5 * (c1.Y + c2.Y))); }
public PlayerInputMoveTo(UInt64 timeStamp, UInt32 unitID, Coords point) : base(timeStamp) { this._unitID = unitID; this._point = point; }
/// <summary> /// Checks if tile is see-through or not. /// </summary> public bool CheckSightValidity(Coords point) { if (!(_myCollider.CheckInBounds(point))) return false; return _visibilityMap[point.X, point.Y] > 0; }
private Tile(Map home, Coords position) { this.InhabitedMap = home; this.Position = position; }
public void CreateItem(Coords startPoint, ItemGenerator item) { Item newItem = new Item(this.IssueItemID(), item); this.CatalogueAddItemTo(newItem.ID, newItem); //Coords bedLocation = new Coords((Int32)((bottomRight.X + topLeft.X) * 0.5), (Int32)((bottomRight.Y + topLeft.Y) * 0.5)); TilePassable itemTile = this.GetTile(startPoint) as TilePassable; itemTile.InventoryAddItem(newItem); }
public TileImpassable(Map home, Coords position, TileGenerator generator) : base(home, position, generator) { }
public void OrderMove(Coords targetPixel) { this._myNavigator = new Navigator(this.MyCreature, targetPixel, true); }
public TileImpassable(Map home, Coords position, String name, float visibilityCoefficient, SpriteTile myBitmap) : base(home, position, name, visibilityCoefficient, myBitmap) { }
public static bool CoordinateIsInBox(Coords c, Coords boxTopLeft, Coords boxBottomRight) { return (((c.X >= boxTopLeft.X) && (c.X <= boxBottomRight.X)) && ((c.Y >= boxTopLeft.Y) && (c.Y <= boxBottomRight.Y))); }
// Fills a space with tiles of "tileType" private void FillRectangleWithTiles(Map homeMap, Coords topLeft, Coords bottomRight, TileGenerator tileType) { Coords difference = bottomRight - topLeft; if (!(difference.X > -1 && difference.Y > -1)) { return; } // There should be a more elegant way of dealing with the "Is it passable or impassable?" problem. if (tileType.passable) { for (int i = 0; i < difference.X + 1; ++i) { for (int j = 0; j < difference.Y + 1; ++j) { Coords currentCoords = new Coords(CoordsType.Tile, topLeft.X + i, topLeft.Y + j); homeMap.SetTile(currentCoords, new TilePassable(homeMap, currentCoords, tileType)); } } } else { for (int i = 0; i < difference.X + 1; ++i) { for (int j = 0; j < difference.Y + 1; ++j) { Coords currentCoords = new Coords(CoordsType.Tile, topLeft.X + i, topLeft.Y + j); homeMap.SetTile(currentCoords, new TileImpassable(homeMap, currentCoords, tileType)); } } } }
/// <summary> /// returns the distance between two Coords /// </summary> public static float DistanceBetweenTwoCoordss(Coords c1, Coords c2) { return Math.Max(Math.Abs(c1.X - c2.X), Math.Abs(c1.Y - c2.Y)); }
public void SetTile(Coords coords, Tile newValue) { _tiles[coords.X, coords.Y] = newValue; }
public void MoveOrder(Coords targetPixel) { MyNavigator = new Navigator(this.MyCreature, targetPixel, true); }
public bool RayTracerVisibilityCheckPixel(Vector c1, Vector c2) { double x0 = c1.X; double y0 = c1.Y; double x1 = c2.X; double y1 = c2.Y; double dx = Math.Abs(x1 - x0); double dy = Math.Abs(y1 - y0); int x = (int)(Math.Floor(x0)); int y = (int)(Math.Floor(y0)); int n = 1; int x_inc, y_inc; double error; if (dx == 0) { x_inc = 0; error = Double.PositiveInfinity; } else if (x1 > x0) { x_inc = 1; n += (int)(Math.Floor(x1)) - x; error = (Math.Floor(x0) + 1 - x0) * dy; } else { x_inc = -1; n += x - (int)(Math.Floor(x1)); error = (x0 - Math.Floor(x0)) * dy; } if (dy == 0) { y_inc = 0; error -= Double.PositiveInfinity; } else if (y1 > y0) { y_inc = 1; n += (int)(Math.Floor(y1)) - y; error -= (Math.Floor(y0) + 1 - y0) * dx; } else { y_inc = -1; n += y - (int)(Math.Floor(y1)); error -= (y0 - Math.Floor(y0)) * dx; } Coords c2Tile = new Coords(CoordsType.Tile, c2); for (; n > 0; --n) { Coords currentCoords = new Coords(CoordsType.Tile, x, y); // We ignore accrued visibility for now. Can add it later. if ((this._visibilityMap[currentCoords.X, currentCoords.Y] == 0) && (currentCoords != c2Tile)) { return false; } if (error > 0) { y += y_inc; error -= dx; } else { x += x_inc; error += dy; } } return true; }
// Furnishes a rectangular room with appropriate furniture private void FurnishRectangularLivingRoom(Map homeMap, Coords topLeft, Coords bottomRight) { // put a bed in the middle of it Coords bedLocation = new Coords(CoordsType.Tile, (Int32)((bottomRight.X + topLeft.X) * 0.5), (Int32)((bottomRight.Y + topLeft.Y) * 0.5)); homeMap.CreateItem(bedLocation, Constants.ItemGeneratorBed); }
/// <summary> /// Returns the Bresenham line between p0 and p1; Borrowed the code /// from some dude whose name I don't have, who in turn borrowed from Wikipedia. /// </summary> private List<Coords> BresenhamLine(Coords p0, Coords p1) { List<Coords> returnList = new List<Coords>(); Boolean steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X); if (steep == true) { Coords tmpPoint = new Coords(CoordsType.Tile, p0.X, p0.Y); p0 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); tmpPoint = p1; p1 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); } Int32 deltaX = Math.Abs(p1.X - p0.X); Int32 deltaY = Math.Abs(p1.Y - p0.Y); Int32 error = 0; Int32 deltaError = deltaY; Int32 yStep = 0; Int32 xStep = 0; Int32 y = p0.Y; Int32 x = p0.X; if (p0.Y < p1.Y) { yStep = 1; } else { yStep = -1; } if (p0.X < p1.X) { xStep = 1; } else { xStep = -1; } Int32 tmpX = 0; Int32 tmpY = 0; while (x != p1.X) { x += xStep; error += deltaError; //if the error exceeds the X delta then //move one along on the Y axis if ((2 * error) > deltaX) { y += yStep; error -= deltaX; } //flip the coords if they're steep if (steep) { tmpX = y; tmpY = x; } else { tmpX = x; tmpY = y; } //check the point generated is legal //and if it is add it to the list if (_myCollider.CheckInBounds(new Coords(CoordsType.Tile, tmpX, tmpY)) == true) { returnList.Add(new Coords(CoordsType.Tile, tmpX, tmpY)); } else { //a bad point has been found, so return the list thus far return returnList; } } return returnList; }
public TilePassable(Map home, Coords position, TileGenerator generator) : base(home, position, generator) { this._myInventory = new Inventory(this); }
private List <Direction> _PathfinderAStar(Coords start, Coords endTopLeft, Coords endBottomRight, BitArray[] _passabilityMap, hFunction h) { // NOTE: Should later implemented a collision predictor mechanic to work in tandem // with the path-finder to provide better agent behavior. // NOTE: Consider returning the number of tiles scanned in case no path is found. // This will alert a boxed-in creature of its predicament. // NOTE: Introduce a flag for a straight-line initial check(for outdoors environmens and // for when the goal is near). Int32 rangeX = _passabilityMap.Length; Int32 rangeY = _passabilityMap[0].Count; NodeAStar?[,] nodeArray = new NodeAStar?[rangeX, rangeY]; NodeAStar startNode = new NodeAStar(); startNode.costSoFar = 0; startNode.estimatedTotalCost = h(start); nodeArray[start.X, start.Y] = startNode; List <Coords> ListOpen = new List <Coords>(); ListOpen.Add(start); while (ListOpen.Count > 0) { // I have to use this bool the way I've implemented the algo. Consider rewriting. bool resortList = false; Coords currentCoords = ListOpen.First(); // Check to see if goal is reached. //if (currentCoords.Equals(endTopLeft)) if (StaticMathFunctions.CoordinateIsInBox(currentCoords, endTopLeft, endBottomRight)) { break; } NodeAStar currentNode = nodeArray[currentCoords.X, currentCoords.Y].Value; for (byte i = 0; i <= 3; ++i) { Direction currentDir = (Direction)(2 * i + 1); Coords dirCoords = StaticMathFunctions.DirectionToCoords(currentDir); Coords potential = currentCoords + dirCoords; // check if move in dir is allowed if (potential.X >= 0 && potential.X < rangeX && potential.Y >= 0 && potential.Y < rangeY && // bounds check _passabilityMap[potential.X][potential.Y]) // passability check { // Using the simplest cost function possible. Can be easily updated // once tile walkability coefficients are added. Coords newNodePosition = new Coords(CoordsType.General, currentCoords.X + dirCoords.X, currentCoords.Y + dirCoords.Y); float accruedCost = currentNode.costSoFar + Constants.MovementCost[(byte)currentDir]; // Straight line correction if (currentDir == nodeArray[currentCoords.X, currentCoords.Y].Value.connection) { accruedCost -= Constants.PathfinderStraightPathCorrection; } // Check to see if the node under examination is in the closed list. //NodeAStar? oldNode = nodeArray[newNodePosition.X, newNodePosition.Y]; if (nodeArray[newNodePosition.X, newNodePosition.Y] != null) { // If node is in closed list, see if it needs updating. if (nodeArray[newNodePosition.X, newNodePosition.Y].Value.costSoFar > accruedCost) { float expectedAdditionalCost = nodeArray[newNodePosition.X, newNodePosition.Y].Value.estimatedTotalCost - nodeArray[newNodePosition.X, newNodePosition.Y].Value.costSoFar; NodeAStar nodeToAdd = new NodeAStar(currentDir, accruedCost, accruedCost + expectedAdditionalCost); nodeArray[newNodePosition.X, newNodePosition.Y] = nodeToAdd; ListOpen.Add(newNodePosition); resortList = true; } } // Node is in open list. Process it. else { float expectedAdditionalCost = h(newNodePosition); NodeAStar nodeToAdd = new NodeAStar(currentDir, accruedCost, accruedCost + expectedAdditionalCost); nodeArray[newNodePosition.X, newNodePosition.Y] = nodeToAdd; ListOpen.Add(newNodePosition); resortList = true; } } } ListOpen.RemoveAt(0); if (resortList) { ListOpen.Sort( delegate(Coords c1, Coords c2) { float difference = nodeArray[c1.X, c1.Y].Value.estimatedTotalCost - nodeArray[c2.X, c2.Y].Value.estimatedTotalCost; Int32 returnValue = 0; if (difference > 0) { returnValue = 1; } else if (difference < 0) { returnValue = -1; } return(returnValue); } ); } } List <Direction> ListRoute = new List <Direction>(); // Return empty route if the open list is empty, i.e. there is no path to the target // Ideally, the game logic should be fixed so that the search isn't even attempted // if there is no path between the two points. if (ListOpen.Count == 0) { return(ListRoute); } Coords trackbackCoords = endTopLeft; while (trackbackCoords != start) { Direction newDirection = nodeArray[trackbackCoords.X, trackbackCoords.Y].Value.connection; ListRoute.Add(newDirection); trackbackCoords = StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, trackbackCoords), StaticMathFunctions.OppositeDirection(newDirection)); } // Might be faster without reversing //ListRoute.Reverse(); // We skip the reversal, so pick directions from the END of the list. return(ListRoute); }
public Tile GetTile(Coords coords) { if (coords.Type == CoordsType.Pixel) { coords = new Coords(CoordsType.Tile, coords); } return _tiles[coords.X, coords.Y]; }
public TilePassable(Map home, Coords position, String name, float visibilityCoefficient, SpriteTile myBitmap) : base(home, position, name, visibilityCoefficient, myBitmap) { this._myInventory = new Inventory(this); }
/// <summary> /// Returns the tiles under the given line. /// Borrowed from: http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html (James McNeill) /// </summary> public List<Coords> RayTracer(Coords c1, Coords c2) { List<Coords> returnVal = new List<Coords>(); Int32 x0 = c1.X; Int32 y0 = c1.Y; Int32 x1 = c2.X; Int32 y1 = c2.Y; int dx = Math.Abs(x1 - x0); int dy = Math.Abs(y1 - y0); int x = x0; int y = y0; int n = 1 + dx + dy; int x_inc = (x1 > x0) ? 1 : -1; int y_inc = (y1 > y0) ? 1 : -1; int error = dx - dy; dx *= 2; dy *= 2; for (; n > 0; --n) { //visit(x, y); returnVal.Add(new Coords(c1.Type, x, y)); if (error > 0) { x += x_inc; error -= dy; } else { y += y_inc; error += dx; } } return returnVal; }
/// <summary> /// Performs a terrain passability check betwee two points by doing pixel validity checks at interval delta. /// </summary> public List<Creature> RayTracerPassabilityCheckRough(Creature client, Vector v1, Vector v2, double delta) { Vector difference = v2 - v1; Vector deltaV = difference; deltaV.ScaleToLength(delta); Vector currentPosition = v1; for (int i = 0; i < difference.Length() / deltaV.Length(); ++i) { Coords pixel = new Coords(CoordsType.Pixel, currentPosition); List<Creature> collision = _myCollider.CreatureClippingCheck(client, pixel, false); if (collision == null || collision.Count > 0) { return collision; } currentPosition += deltaV; } return new List<Creature>(); }
public bool RayTracerVisibilityCheckPixel(Vector c1, Vector c2) { double x0 = c1.X; double y0 = c1.Y; double x1 = c2.X; double y1 = c2.Y; double dx = Math.Abs(x1 - x0); double dy = Math.Abs(y1 - y0); int x = (int)(Math.Floor(x0)); int y = (int)(Math.Floor(y0)); int n = 1; int x_inc, y_inc; double error; if (dx == 0) { x_inc = 0; error = Double.PositiveInfinity; } else if (x1 > x0) { x_inc = 1; n += (int)(Math.Floor(x1)) - x; error = (Math.Floor(x0) + 1 - x0) * dy; } else { x_inc = -1; n += x - (int)(Math.Floor(x1)); error = (x0 - Math.Floor(x0)) * dy; } if (dy == 0) { y_inc = 0; error -= Double.PositiveInfinity; } else if (y1 > y0) { y_inc = 1; n += (int)(Math.Floor(y1)) - y; error -= (Math.Floor(y0) + 1 - y0) * dx; } else { y_inc = -1; n += y - (int)(Math.Floor(y1)); error -= (y0 - Math.Floor(y0)) * dx; } Coords c2Tile = new Coords(CoordsType.Tile, c2); for (; n > 0; --n) { Coords currentCoords = new Coords(CoordsType.Tile, x, y); // We ignore accrued visibility for now. Can add it later. if ((this._visibilityMap[currentCoords.X, currentCoords.Y] == 0) && (currentCoords != c2Tile)) { return(false); } if (error > 0) { y += y_inc; error -= dx; } else { x += x_inc; error += dy; } } return(true); }
/// <summary> /// Checks if the Bresenham line between p0 and p1 goes only through visible tiles /// !!! Code repetition, should redo. /// </summary> public bool BresenhamLineCheckVisible(Coords p0, Coords p1) { if (p0.Equals(p1)) { return true; } Boolean steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X); // fix this stupidity Coords p0original = new Coords(CoordsType.Tile, p0.X, p0.Y); Coords p1original = new Coords(CoordsType.Tile, p1.X, p1.Y); if (steep == true) { Coords tmpPoint = new Coords(CoordsType.Tile, p0.X, p0.Y); p0 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); tmpPoint = p1; p1 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); } Int32 deltaX = Math.Abs(p1.X - p0.X); Int32 deltaY = Math.Abs(p1.Y - p0.Y); Int32 error = 0; Int32 deltaError = deltaY; Int32 yStep = 0; Int32 xStep = 0; Int32 y = p0.Y; Int32 x = p0.X; if (p0.Y < p1.Y) { yStep = 1; } else { yStep = -1; } if (p0.X < p1.X) { xStep = 1; } else { xStep = -1; } Int32 tmpX = 0; Int32 tmpY = 0; float visibilityTotal = 1f; while (x != p1.X) { x += xStep; error += deltaError; //if the error exceeds the X delta then //move one along on the Y axis if ((2 * error) > deltaX) { y += yStep; error -= deltaX; } //flip the coords if they're steep if (steep) { tmpX = y; tmpY = x; } else { tmpX = x; tmpY = y; } // check the point generated is legal // using passability check. creatures will leave shadows. should write a visibility // check later Coords currentCoords = new Coords(CoordsType.Tile, tmpX, tmpY); // for this to look good you must make sure it takes account of the eucledean distances over which the coeffcients hold // otherwise you get square FOVs. visibilityTotal *= this._visibilityMap[currentCoords.X, currentCoords.Y]; if ( (visibilityTotal < Constants.VisibilityTreshold) & (!(currentCoords.Equals(p0original) | currentCoords.Equals(p1original))) ) { return false; } } return true; }
/// <summary> /// Returns the Bresenham line between p0 and p1; Borrowed the code /// from some dude whose name I don't have, who in turn borrowed from Wikipedia. /// </summary> private List <Coords> BresenhamLine(Coords p0, Coords p1) { List <Coords> returnList = new List <Coords>(); Boolean steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X); if (steep == true) { Coords tmpPoint = new Coords(CoordsType.Tile, p0.X, p0.Y); p0 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); tmpPoint = p1; p1 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); } Int32 deltaX = Math.Abs(p1.X - p0.X); Int32 deltaY = Math.Abs(p1.Y - p0.Y); Int32 error = 0; Int32 deltaError = deltaY; Int32 yStep = 0; Int32 xStep = 0; Int32 y = p0.Y; Int32 x = p0.X; if (p0.Y < p1.Y) { yStep = 1; } else { yStep = -1; } if (p0.X < p1.X) { xStep = 1; } else { xStep = -1; } Int32 tmpX = 0; Int32 tmpY = 0; while (x != p1.X) { x += xStep; error += deltaError; //if the error exceeds the X delta then //move one along on the Y axis if ((2 * error) > deltaX) { y += yStep; error -= deltaX; } //flip the coords if they're steep if (steep) { tmpX = y; tmpY = x; } else { tmpX = x; tmpY = y; } //check the point generated is legal //and if it is add it to the list if (_myCollider.CheckInBounds(new Coords(CoordsType.Tile, tmpX, tmpY)) == true) { returnList.Add(new Coords(CoordsType.Tile, tmpX, tmpY)); } else { //a bad point has been found, so return the list thus far return(returnList); } } return(returnList); }
/// <summary> /// Checks if tile allows passage /// Some of this is redundant now that I have Tile.SeeAllowedMove. Should rethink. /// </summary> public bool CheckTilePassageValidity(Coords point) { if (!this.CheckSightValidity(point)) { return false; } return _passabilityMap[point.X][point.Y]; }
/// <summary> /// Checks if the Bresenham line between p0 and p1 goes only through visible tiles /// !!! Code repetition, should redo. /// </summary> public bool BresenhamLineCheckVisible(Coords p0, Coords p1) { if (p0.Equals(p1)) { return(true); } Boolean steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X); // fix this stupidity Coords p0original = new Coords(CoordsType.Tile, p0.X, p0.Y); Coords p1original = new Coords(CoordsType.Tile, p1.X, p1.Y); if (steep == true) { Coords tmpPoint = new Coords(CoordsType.Tile, p0.X, p0.Y); p0 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); tmpPoint = p1; p1 = new Coords(CoordsType.Tile, tmpPoint.Y, tmpPoint.X); } Int32 deltaX = Math.Abs(p1.X - p0.X); Int32 deltaY = Math.Abs(p1.Y - p0.Y); Int32 error = 0; Int32 deltaError = deltaY; Int32 yStep = 0; Int32 xStep = 0; Int32 y = p0.Y; Int32 x = p0.X; if (p0.Y < p1.Y) { yStep = 1; } else { yStep = -1; } if (p0.X < p1.X) { xStep = 1; } else { xStep = -1; } Int32 tmpX = 0; Int32 tmpY = 0; float visibilityTotal = 1f; while (x != p1.X) { x += xStep; error += deltaError; //if the error exceeds the X delta then //move one along on the Y axis if ((2 * error) > deltaX) { y += yStep; error -= deltaX; } //flip the coords if they're steep if (steep) { tmpX = y; tmpY = x; } else { tmpX = x; tmpY = y; } // check the point generated is legal // using passability check. creatures will leave shadows. should write a visibility // check later Coords currentCoords = new Coords(CoordsType.Tile, tmpX, tmpY); // for this to look good you must make sure it takes account of the eucledean distances over which the coeffcients hold // otherwise you get square FOVs. visibilityTotal *= this._visibilityMap[currentCoords.X, currentCoords.Y]; if ( (visibilityTotal < Constants.VisibilityTreshold) & (!(currentCoords.Equals(p0original) | currentCoords.Equals(p1original))) ) { return(false); } } return(true); }
public void SpawnCreature(Coords startPoint, Team team, CreatureGenerator generator) { Creature newguy = new Creature(this, startPoint, (UInt16)this.IssueCreatureID(), team, generator); team.MemberRegister(newguy); }
/// <summary> /// Spawns the player on the 'ground' at 'startPoint' /// returns a reference to the Player so one can more easily take care of references. /// </summary> public Creature SpawnPlayer(Coords startPoint) { //Player player = new Player(this, startPoint, this.IssueCreatureID()); //this.PlayerReference = player; return(null); }
public Coords(CoordsType newType, Coords c) { this._type = newType; if (newType == CoordsType.Tile && c._type == CoordsType.Pixel) { _X = c.X / Constants.TileSize; _Y = c.Y / Constants.TileSize; return; } else if (newType == CoordsType.Pixel && c._type == CoordsType.Tile) { _X = c.X + (Int32)(0.5 * Constants.TileSize); _Y = c.Y + (Int32)(0.5 * Constants.TileSize); return; } _X = c.X; _Y = c.Y; }
public float DistanceTo(Coords c) { return (float)Math.Sqrt(Math.Pow((this.X - c.X), 2) + Math.Pow((this.Y - c.Y), 2)); }
/// Generates the influence map. /// Uses a silly recursive algorithm. /// Stopping conditions: Let's use two, to avoid stupid infinite loops. /// One is a distance threshold check. // Second is a min influence threshold check. /// <summary> /// Generates the influence map. /// Uses a silly recursive algorithm. /// Stopping conditions: Let's use two, to avoid stupid infinite loops. /// One is a distance threshold check. /// Second is a min influence threshold check. /// </summary> public void GenerateInfluenceMap() { // boolean array to keep note of which tiles have been processed //BitArray[,] takenCareOf = new BitArray[_currentMap.BoundX, _currentMap.BoundY]; BitArray[] takenCareOf = new BitArray[_currentMap.BoundX]; for (int i = 0; i < _currentMap.BoundX; ++i) { takenCareOf[i] = new BitArray(_currentMap.BoundY); } takenCareOf[Source.X][Source.Y] = true; // sets up two queues - one for the current pass, one for the next one // distance increments by one at each pass // if too slow, the process should be broken up so it does a number of passes each tick Queue <Coords> currentQueue = new Queue <Coords>(); Queue <Coords> nextQueue = new Queue <Coords>(); currentQueue.Enqueue(_source); UInt32 currentDistance = 0; // main loop // Stopping conditions: the two queues are exhausted, OR InfluenceMapMaxDistance is reached while ( ((currentQueue.Count > 0) & (nextQueue.Count > 0)) | (currentDistance < Constants.InfluenceMapMaxDistance) ) { // Checks if it's time to start the next pass if (currentQueue.Count == 0) { currentQueue = nextQueue; nextQueue = new Queue <Coords>(); currentDistance++; continue; } Coords currentCoords = currentQueue.Peek(); TilePassable currentTile = (TilePassable)CurrentMap.GetTile(currentCoords); // Analyzes the neighbors of the current Tile for possible additions to nextQueue for (byte i = 1; i <= 8; i++) { Direction currentDir = (Direction)i; if (currentTile.AllowedMovesCheckInDirection(currentDir)) { Coords toCheck = StaticMathFunctions.CoordsNeighboringInDirection(currentCoords, currentDir); if (!takenCareOf[toCheck.X][toCheck.Y]) { nextQueue.Enqueue(toCheck); takenCareOf[toCheck.X][toCheck.Y] = true; } } } float newVal = _f(currentDistance); // Check to avert infnite / excessively deep loop if (newVal > Constants.InfluenceMapMinThreshold) { this.SetMapValue(currentCoords, newVal); } currentQueue.Dequeue(); } }