internal void ExamineNeighbourhood(GameObject obj) { // Debug.WriteLine("Examining neighhourhood of " + obj); // Debug.Assert(!_hist.Contains(obj), "examining neighbourhood for an object that's already in the draw list"); var objBB = obj.GetBounds(); var tileTL = _map.GetTileScreen(objBB.Location, true, false); var tileBR = _map.GetTileScreen(objBB.Location + objBB.Size); for (int y = tileTL.Dy - 3; y <= tileBR.Dy + 3; y++) { for (int x = tileTL.Dx - 3; x <= tileBR.Dx + 3; x += 2) { if ((x + (y + obj.TopTile.Dy)) < 0 || y < 0) { continue; } var tile2 = _map[x + (y + obj.TopTile.Dy) % 2, y / 2]; if (tile2 == null) { continue; } // Debug.WriteLine("neighhourhood tile " + tile2 + " of obj " + obj + " at " + obj.Tile); ExamineObjects(obj, tile2); foreach (var obj2 in tile2.AllObjects) { ExamineObjects(obj, obj2); } } } }
internal void ExamineNeighbourhood(GameObject obj) { // Debug.WriteLine("Examining neighhourhood of " + obj); // Debug.Assert(!_hist.Contains(obj), "examining neighbourhood for an object that's already in the draw list"); var objBB = obj.GetBounds(); var tileTL = _map.GetTileScreen(objBB.Location, true, false); var tileBR = _map.GetTileScreen(objBB.Location + objBB.Size); for (int y = tileTL.Dy - 3; y <= tileBR.Dy + 3; y++) { for (int x = tileTL.Dx - 3; x <= tileBR.Dx + 3; x += 2) { if ((x + (y + obj.TopTile.Dy)) < 0 || y < 0) continue; var tile2 = _map[x + (y + obj.TopTile.Dy)%2, y/2]; if (tile2 == null) continue; // Debug.WriteLine("neighhourhood tile " + tile2 + " of obj " + obj + " at " + obj.Tile); ExamineObjects(obj, tile2); foreach (var obj2 in tile2.AllObjects) ExamineObjects(obj, obj2); } } }
private object GetFrontBlock(GameObject objA, GameObject objB) { // magic, don't touch. // any kind of randomness or antisymmetry in this function // will lead to cyclic dependencies in the drawing order graph, // resulting in neither object every being drawn. // tiles never overlap if (objA is MapTile && objB is MapTile) return null; var boxA = objA.GetBounds(); var boxB = objB.GetBounds(); if (!boxA.IntersectsWith(boxB)) return null; var hexA = GetIsoBoundingBox(objA); var hexB = GetIsoBoundingBox(objB); var sepAxis = Hexagon.GetSeparationAxis(hexA, hexB); // tiles can only be in front based on z-axis separation if ((objA is MapTile) ^ (objB is MapTile) && sepAxis != Axis.Z) return (objA is MapTile) ? objB : objA; // flat stuff always loses if (objA.Drawable.Flat ^ objB.Drawable.Flat) { if (sepAxis != Axis.Z) return (objA.Drawable.Flat) ? objB : objA; } switch (sepAxis) { case Axis.X: if (hexA.xMin > hexB.xMax) return objA; else if (hexB.xMin > hexA.xMax) return objB; break; case Axis.Y: if (hexA.yMin > hexB.yMax) return objA; else if (hexB.yMin > hexA.yMax) return objB; break; case Axis.Z: if (hexA.zMin > hexB.zMax) return objA; else if (hexB.zMin > hexA.zMax) return objB; break; } // units on bridges can only be drawn after the bridge if (objA is OverlayObject && SpecialOverlays.IsHighBridge(objA as OverlayObject) && objB is OwnableObject && (objB as OwnableObject).OnBridge) return objB; else if (objB is OverlayObject && SpecialOverlays.IsHighBridge(objB as OverlayObject) && objA is OwnableObject && (objA as OwnableObject).OnBridge) return objA; // no proper separation is possible, if one of both // objects is flat then mark the other one as in front, // otherwise use the one with lowest y if (objA.Drawable.Flat && !objB.Drawable.Flat) return objB; else if (objB.Drawable.Flat && !objA.Drawable.Flat) return objA; // try to make distinction based on object type // tile, smudge, overlay, terrain, unit/building, aircraft var priorities = new Dictionary<Type, int> { {typeof(MapTile), 0}, {typeof(SmudgeObject), 1}, {typeof(OverlayObject), 2}, {typeof(TerrainObject), 3}, {typeof(StructureObject), 3}, {typeof(AnimationObject), 3}, {typeof(UnitObject), 3}, {typeof(InfantryObject), 3}, {typeof(AircraftObject), 4}, }; int prioA = priorities[objA.GetType()]; int prioB = priorities[objB.GetType()]; if (prioA > prioB) return objA; else if (prioA < prioB) return objB; // finally try the minimal y coordinate if (boxA.Bottom > boxB.Bottom) return objA; else if (boxA.Bottom < boxB.Bottom) return objB; // finally if nothing worked up to here, which is very unlikely, // we'll use a tie-breaker that is at least guaranteed to yield // the same result regardless of argument order return objA.Id < objB.Id ? objA : objB; }
public virtual void DrawBoundingBox(GameObject obj, Graphics gfx) { if (IsVoxel) gfx.DrawRectangle(BoundsRectPenVoxel, obj.GetBounds()); else gfx.DrawRectangle(BoundsRectPenSHP, obj.GetBounds()); var top = obj.TopTile; var left = obj.Tile.Layer.GetTileR(obj.TopTile.Rx, obj.TopTile.Ry + obj.Drawable.Foundation.Height); var bottom = obj.Tile.Layer.GetTileR(obj.TopTile.Rx + obj.Drawable.Foundation.Width, obj.TopTile.Ry + obj.Drawable.Foundation.Height); var right = obj.Tile.Layer.GetTileR(obj.TopTile.Rx + obj.Drawable.Foundation.Width, obj.TopTile.Ry); List<Point> verts = new List<Point>(); verts.Add(new Point(top.Dx * TileWidth / 2, top.Dy * TileHeight / 2)); verts.Add(new Point(left.Dx * TileWidth / 2 - TileWidth / 4, left.Dy * TileHeight / 2 + TileHeight / 4)); verts.Add(new Point(bottom.Dx * TileWidth / 2, bottom.Dy * TileHeight / 2 + TileHeight / 2)); verts.Add(new Point(right.Dx * TileWidth / 2 + TileHeight / 2, right.Dy * TileHeight / 2 + TileHeight / 4)); verts.Add(new Point(top.Dx * TileWidth / 2, top.Dy * TileHeight / 2)); List<Point> verts2 = new List<Point>(); foreach (var p in verts) { p.Offset(30, -15); verts2.Add(p); } gfx.DrawLines(BoundsRectPenISO, verts2.ToArray()); }
private object GetFrontBlock(GameObject objA, GameObject objB) { // magic, don't touch. // any kind of randomness or antisymmetry in this function // will lead to cyclic dependencies in the drawing order graph, // resulting in neither object every being drawn. // tiles never overlap if (objA is MapTile && objB is MapTile) { return(null); } var boxA = objA.GetBounds(); var boxB = objB.GetBounds(); if (!boxA.IntersectsWith(boxB)) { return(null); } var hexA = GetIsoBoundingBox(objA); var hexB = GetIsoBoundingBox(objB); var sepAxis = Hexagon.GetSeparationAxis(hexA, hexB); // tiles can only be in front based on z-axis separation if ((objA is MapTile) ^ (objB is MapTile) && sepAxis != Axis.Z) { return((objA is MapTile) ? objB : objA); } // flat stuff always loses if (objA.Drawable.Flat ^ objB.Drawable.Flat) { if (sepAxis != Axis.Z) { return((objA.Drawable.Flat) ? objB : objA); } } switch (sepAxis) { case Axis.X: if (hexA.xMin > hexB.xMax) { return(objA); } else if (hexB.xMin > hexA.xMax) { return(objB); } break; case Axis.Y: if (hexA.yMin > hexB.yMax) { return(objA); } else if (hexB.yMin > hexA.yMax) { return(objB); } break; case Axis.Z: if (hexA.zMin > hexB.zMax) { return(objA); } else if (hexB.zMin > hexA.zMax) { return(objB); } break; } // units on bridges can only be drawn after the bridge if (objA is OverlayObject && SpecialOverlays.IsHighBridge(objA as OverlayObject) && objB is OwnableObject && (objB as OwnableObject).OnBridge) { return(objB); } else if (objB is OverlayObject && SpecialOverlays.IsHighBridge(objB as OverlayObject) && objA is OwnableObject && (objA as OwnableObject).OnBridge) { return(objA); } // no proper separation is possible, if one of both // objects is flat then mark the other one as in front, // otherwise use the one with lowest y if (objA.Drawable.Flat && !objB.Drawable.Flat) { return(objB); } else if (objB.Drawable.Flat && !objA.Drawable.Flat) { return(objA); } // try to make distinction based on object type // tile, smudge, overlay, terrain, unit/building, aircraft var priorities = new Dictionary <Type, int> { { typeof(MapTile), 0 }, { typeof(SmudgeObject), 1 }, { typeof(OverlayObject), 2 }, { typeof(TerrainObject), 3 }, { typeof(StructureObject), 3 }, { typeof(AnimationObject), 3 }, { typeof(UnitObject), 3 }, { typeof(InfantryObject), 3 }, { typeof(AircraftObject), 4 }, }; int prioA = priorities[objA.GetType()]; int prioB = priorities[objB.GetType()]; if (prioA > prioB) { return(objA); } else if (prioA < prioB) { return(objB); } // finally try the minimal y coordinate if (boxA.Bottom > boxB.Bottom) { return(objA); } else if (boxA.Bottom < boxB.Bottom) { return(objB); } // finally if nothing worked up to here, which is very unlikely, // we'll use a tie-breaker that is at least guaranteed to yield // the same result regardless of argument order return(objA.Id < objB.Id ? objA : objB); }