/// <summary> /// Processes the geometry layer, creating the game representation. /// </summary> /// <param name="rawLayer">The layer.</param> /// <param name="map">The map.</param> /// <param name="tileDefinitions">A global dictionary of all tile definitions.</param> /// <returns> /// An instance of a new <see cref="GeometryTileLayer" />. /// </returns> private void ProcessGeometryLayer(TmxLayer rawLayer, GeometryTileLayer layer, Map map, IDictionary <int, TileDefinition> tileDefinitions) { if (rawLayer == null) { throw new ArgumentNullException(nameof(rawLayer)); } if (layer == null) { throw new ArgumentNullException(nameof(layer)); } if (map == null) { throw new ArgumentNullException(nameof(map)); } if (tileDefinitions == null) { throw new ArgumentNullException(nameof(tileDefinitions)); } TraceSource.TraceEvent(TraceEventType.Verbose, 0, $"Processing layer {rawLayer.Name}"); var tiles = new List <GeometryTile>(); foreach (var tile in rawLayer.Tiles) { if (tile.Gid != 0) { var geoTile = new GeometryTile(); geoTile.GridPosition = new Int32Point(tile.X, tile.Y); geoTile.WorldPosition = new Int32Point(tile.X * map.GeometryTileWidth, tile.Y * map.GeometryTileHeight); geoTile.Definition = tileDefinitions[tile.Gid]; geoTile.DefinitionId = tile.Gid; tiles.Add(geoTile); } } layer.SetTiles(tiles); }
/// <summary> /// Determines whether a /// </summary> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> /// <param name="lastTile">The last tile hit.</param> /// <param name="trace">The trace line parameters.</param> /// <param name="hitTile">The tile that was hit.</param> /// <returns> /// <c>true</c> if point is on a solid tile; otherwise, <c>false</c>. /// </returns> private bool IsPointOnSolidTile(int x, int y, GeometryTile lastTile, TraceQuery trace, out GeometryTile hitTile) { hitTile = null; bool hit = false; var map = _mapService.CurrentMap; if (map == null) { return(hit); } var tileCol = (int)Math.Floor((double)x / map.GeometryTileWidth); var tileRow = (int)Math.Floor((double)y / map.GeometryTileHeight); if ((tileCol < 0) || (tileRow < 0)) { return(hit); } for (var i = 0; i < map.CollisionLayers.Length; i++) { var layer = map.CollisionLayers[i]; // if the trace has specific a collision path, ignore layers that are not on the path if (trace.CollisionPath != null) { if ((layer.CollisionPath != null) && (layer.CollisionPath != trace.CollisionPath)) { continue; } } var tile = layer.GetTile(tileCol, tileRow); if (tile != null) { // solidity filters if ( (tile.Definition.SolidType == SolidType.None) && ((trace.Options & TraceLineOptions.SolidOnly) > TraceLineOptions.None)) { continue; } if ( (tile.Definition.SolidType == SolidType.JumpThrough) && ((trace.Options & TraceLineOptions.IgnoreJumpThrough) > TraceLineOptions.None)) { continue; } var collisionMap = tile.Definition.CollisionMap; if (collisionMap != null) { var localX = x - tile.WorldPosition.X; var localY = y - tile.WorldPosition.Y; if (!hit) { if (collisionMap[localX, localY]) { hitTile = tile; hit = true; } } } if (hit) { if (_varShowTracelines.Value) { if ((lastTile == null) || (lastTile.GridPosition.X != tile.GridPosition.X) || (lastTile.GridPosition.Y != tile.GridPosition.Y)) { _renderService.HighlightGeometryTile(tileCol, tileRow, 0, 255, 0, 0); } } } } } return(hit); }
/// <summary> /// Fires a traceline and collects collision information. /// </summary> /// <param name="trace">Object containing the trace line parameters.</param> /// <returns> /// A value containing the result of the trace. /// </returns> public TraceResult TraceLine(TraceQuery trace) { double x0, y0, x1, y1; List <GameEntity> entities = _entListPool.GetObject(); x0 = trace.Line.Start.X; y0 = trace.Line.Start.Y; x1 = trace.Line.End.X; y1 = trace.Line.End.Y; if ((trace.Options & TraceLineOptions.IgnoreEntities) == TraceLineOptions.None) { GetPossibleCollidersForTraceline(trace, entities); } var dx = Math.Abs(x1 - x0); var 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 = 0.0D; if (dx == 0) { x_inc = 0; error = double.MaxValue; } 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.MaxValue; } 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; } var hit = false; GeometryTile tile = null; GameEntity entity = null; for (; n > 0; --n) { // visit if (entities.Count > 0) { hit = IsPointInEntity(entities, x, y, trace, out entity); } if (!hit && ((trace.Options & TraceLineOptions.IgnoreTiles) == TraceLineOptions.None)) { hit = IsPointOnSolidTile(x, y, tile, trace, out tile); } if (hit) { break; } if (error > 0) { y += y_inc; error -= dx; } else { x += x_inc; error += dy; } } if (_varShowTracelines.Value) { if (hit) { _renderService.DrawLine(new Line(trace.Line.Start.X, trace.Line.Start.Y, x, y), 0); _renderService.DrawLine(new Line(x, y, trace.Line.End.X, trace.Line.End.Y), 0, 0, 255, 0); } else { _renderService.DrawLine(trace.Line, 0); } } entities.Clear(); _entListPool.PutObject(entities); var retval = new TraceResult(); retval.Hit = hit; retval.ContactPoint = new Point(x, y); retval.Entity = entity; retval.Tile = tile; return(retval); }