Example #1
0
        public IEnumerable<Tile<TileInfo>> CastRay(Ray ray)
        {
            // check http://playtechs.blogspot.nl/2007/03/raytracing-on-grid.html
            // for possible optimisations
            var start = ray.Start.NumericValue;
            var diff = ray.Direction.NumericValue;
            float startX, startY;
            this.positionToTileSpace(start.X, start.Y, out startX, out startY);
            int x1, y1;
            this.positionToTile(start.X + diff.X, start.Y + diff.Y, out x1, out y1);
            var x0 = (int)startX;
            var y0 = (int)startY;

            var tileDistanceX = x1 - x0;
            var tileDistanceY = y1 - y0;

            var count = 1 + Math.Abs(tileDistanceX) + Math.Abs(tileDistanceY);

            yield return new Tile<TileInfo>(this.tilemap, x0, y0);

            if (count <= 2)
            {
                if (count == 2)
                {
                    yield return new Tile<TileInfo>(this.tilemap, x1, y1);
                }
                yield break;
            }

            var tileX = x0;
            var tileY = y0;

            var tileStepX = Math.Sign(tileDistanceX);
            var tileStepY = Math.Sign(tileDistanceY);

            float intersectXStep, intersectYStep;
            float nextIntersectX, nextIntersectY;

            getRayIntersectParameters(startX, diff.X, out nextIntersectX, out intersectXStep);
            getRayIntersectParameters(startY, diff.Y, out nextIntersectY, out intersectYStep);

            for (int i = 2; i < count; i++)
            {
                if (nextIntersectX < nextIntersectY)
                {
                    tileX += tileStepX;
                    nextIntersectX += intersectXStep;
                }
                else
                {
                    tileY += tileStepY;
                    nextIntersectY += intersectYStep;
                }
                yield return new Tile<TileInfo>(this.tilemap, tileX, tileY);
            }

            yield return new Tile<TileInfo>(this.tilemap, x1, y1);
        }
Example #2
0
        public static HitResult? TryHit(this IProjectileCollider collider, Ray ray)
        {
            var start = ray.Start.NumericValue;
            var dir = ray.Direction.NumericValue;
            var center = collider.Position.NumericValue;
            var radius = collider.Radius.NumericValue;

            var a = start.X - center.X;
            var b = start.Y - center.Y;
            var r2 = radius * radius;

            var c2 = dir.X * dir.X;
            var d2 = dir.Y * dir.Y;
            var cd = dir.X * dir.Y;

            var s = (r2 - a * a) * d2
                    + (r2 - b * b) * c2
                    + 2 * a * b * cd;

            // if s is less than 0, the solutions for f are imaginary
            // and the ray's line does not intersect the circle
            if (s >= 0)
            {
                var f = (Mathf.Sqrt(s) + a * dir.X + b * dir.Y) / -(c2 + d2);

                if (f <= 1)
                {
                    var isInside = a * a + b * b < r2;
                    if (f >= 0 || (isInside && !float.IsNegativeInfinity(f)))
                    {
                        // TODO: currently returns negative f if ray starts inside
                        // consider treating this case differently?
                        // do we ever care about 'exit hits'?
                        // probably want to split entry/exit hits
                        // how to handle moving targets?
                        return new HitResult(
                            new Position2(start + dir * f),
                            Direction2.Of(new Vector2(a, b)),
                            f,
                            isInside
                            );
                    }
                }
            }

            return null;
        }
Example #3
0
            public HitResult? Update(GameState game, TimeSpan time)
            {
                var vDelta = this.velocity * time;

                var hitResult = new Ray(this.position, vDelta)
                    .Shoot(game, true, this.collideWithProjectileColliders);

                var f = hitResult.HasValue ? hitResult.Value.RayFactor : 1;

                var zDelta = this.vz * time;

                var z = this.z + zDelta;
                if (z < 0.U())
                {
                    f = this.z / zDelta;
                    z = 0.U();
                    hitResult = new HitResult(this.position + vDelta * f, Direction2.Zero, f, false);
                }

                this.position += vDelta * f;
                this.z = z;

                this.vz += game.Gravity * time;

                return hitResult;
            }
Example #4
0
        public HitResult? TryHit(Ray ray)
        {
            var start = ray.Start.NumericValue;
            var direction = ray.Direction.NumericValue;

            var topLeft = this.TopLeft.NumericValue;
            var bottomRight = (this.TopLeft + this.Size).NumericValue;

            HitResult? result = null;

            var bestF = 1f;

            if (direction.X != 0)
            {
                { // left
                    var f = (topLeft.X - start.X) / direction.X;

                    if (f >= 0 && f < bestF)
                    {
                        var y = start.Y + direction.Y * f;

                        if (y >= topLeft.Y && y <= bottomRight.Y)
                        {
                            bestF = f;
                            result = new HitResult(new Position2(topLeft.X, y), Direction2.FromDegrees(180), f,
                                start.X > topLeft.X);
                        }
                    }
                }
                { // right
                    var f = (bottomRight.X - start.X) / direction.X;

                    if (f >= 0 && f < bestF)
                    {
                        var y = start.Y + direction.Y * f;

                        if (y >= topLeft.Y && y <= bottomRight.Y)
                        {
                            bestF = f;
                            result = new HitResult(new Position2(bottomRight.X, y), Direction2.FromDegrees(0), f,
                                start.X < bottomRight.X);
                        }
                    }
                }
            }

            if (direction.Y != 0)
            {
                { // top
                    var f = (topLeft.Y - start.Y) / direction.Y;

                    if (f >= 0 && f < bestF)
                    {
                        var x = start.X + direction.X * f;

                        if (x >= topLeft.X && x <= bottomRight.X)
                        {
                            bestF = f;
                            result = new HitResult(new Position2(x, topLeft.Y), Direction2.FromDegrees(270), f,
                                start.Y > topLeft.Y);
                        }
                    }
                }
                { // bottom
                    var f = (bottomRight.Y - start.Y) / direction.Y;

                    if (f >= 0 && f < bestF)
                    {
                        var x = start.X + direction.X * f;

                        if (x >= topLeft.X && x <= bottomRight.X)
                        {
                            bestF = f;
                            result = new HitResult(new Position2(x, bottomRight.Y), Direction2.FromDegrees(90), f,
                                start.Y < bottomRight.Y);
                        }
                    }
                }
            }

            return result;
        }