Beispiel #1
0
        /// <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);
        }