Ejemplo n.º 1
0
        /**
         * Sends out a ray that starts at the given position and moves out in the given direction.
         *
         * @param position the starting position
         * @param direction the direction to proceed in
         * @param visitTile the action to perform on each visited tile
         */
        private void castLightRay(Vector2 position, Vector2 direction, VisitTile visitTile)
        {
            RectangleF viewRect = engine.graphicsComponent.camera.viewRect;

            if (!((position.x > viewRect.right && direction.x > 0) || (position.x < viewRect.left && direction.x < 0) ||
                  (position.y < viewRect.bottom && direction.y > 0) || (position.y > viewRect.top && direction.y < 0)))
            {
                return;
            }

            castRay(position, direction, (tile) => (tile.opacity), visitTile);
        }
Ejemplo n.º 2
0
        /**
         * Shoot an imaginary ray from a point in a direction, ending on some condition
         *
         * @param position  The starting position
         * @param direction The direction of the ray
         * @param visitTile The operation (if any) to perform on each tile
         * @param endCond   Condition when the ray should end
         *
         * @return Length of the ray
         */
        private float castRay(Vector2 position, Vector2 direction, Predicate <Tile> endCondition, VisitTile visitTile = null)
        {
            //Note: taken from http://www.cse.yorku.ca/~amana/research/grid.pdf
            if (endCondition == null)
            {
                throw new Exception("Error: An ending condition for the ray must be specified.");
            }

            //Bounds checking
            Tile curTile = getTileAt(position);

            if (curTile == null || direction == Vector2.Zero)
            {
                return(0);
            }

            int X    = curTile.xIndex;              //X index of current tile
            int Y    = curTile.yIndex;              //Y index of current tile
            int xDir = (direction.x >= 0) ? 1 : -1; //Direction of scanning along X
            int yDir = (direction.y >= 0) ? 1 : -1; //Direction of scanning along Y

            //Handle hor. and ver. cases separately
            if (direction.x == 0)
            {
                while (!endCondition(curTile))
                {
                    if (visitTile != null)
                    {
                        visitTile(curTile);
                    }
                    Y += yDir;
                    if (Y < 0 || Y >= height)
                    {
                        return(getDistToTile(position, xDir, yDir, X, Y));
                    }
                    curTile = tileArray[X, Y];
                }

                //Apply to the last tile
                if (visitTile != null)
                {
                    visitTile(curTile);
                }

                return(getDistToTile(position, xDir, yDir, X, Y));
            }
            else if (direction.y == 0)
            {
                while (!endCondition(curTile))
                {
                    if (visitTile != null)
                    {
                        visitTile(curTile);
                    }
                    X += xDir;
                    if (X < 0 || X >= width)
                    {
                        return(getDistToTile(position, xDir, yDir, X, Y));
                    }
                    curTile = tileArray[X, Y];
                }

                //Apply to the last tile
                if (visitTile != null)
                {
                    visitTile(curTile);
                }

                return(getDistToTile(position, xDir, yDir, X, Y));
            }

            float tMaxX   = (Tile.size * (X + (xDir + 1) / 2) - position.x) / direction.x; // t at vert tile boundary
            float tMaxY   = (Tile.size * (Y + (yDir + 1) / 2) - position.y) / direction.y; // t at horiz tile boundary
            float tDeltaX = Math.Abs(Tile.size / direction.x);                             // T required to move Tile.size in X
            float tDeltaY = Math.Abs(Tile.size / direction.y);                             // T required to move Tile.size in Y

            while (!endCondition(curTile))
            {
                if (visitTile != null)
                {
                    visitTile(curTile);
                }

                //Find next tile in ray
                if (tMaxX < tMaxY)
                {
                    tMaxX += tDeltaX;
                    X     += xDir;
                }
                else
                {
                    tMaxY += tDeltaY;
                    Y     += yDir;
                }

                if (X < 0 || X >= width || Y < 0 || Y >= height)
                {
                    return(getDistToTile(position, xDir, yDir, X, Y));
                }
                curTile = tileArray[X, Y];
            }

            //Apply to the last tile
            if (visitTile != null)
            {
                visitTile(curTile);
            }

            return(getDistToTile(position, xDir, yDir, X, Y));
        }
Ejemplo n.º 3
0
        /**
         * Sends out a cone of light that starts at position and moves out in direction.
         *
         * @param position  Vertex of the cone
         * @param direction Direction of the axis of the cone
         * @param coneWidth Angle of the cone, in degrees
         * @param numRays   Number of rays to shoot within the cone
         * @param mod       The action to perform on each visited tile
         */
        public void castLightCone(Vector2 position, Vector2 direction, float coneWidth, int numRays, VisitTile mod)
        {
            if (coneWidth < 0)
            {
                throw new Exception("World.castCone(): coneWidth < 0");
            }
            if (numRays < 0)
            {
                throw new Exception("World.castCone(): numRays < 0");
            }

            //Calculate cos and sine for angle of cone
            float c = (float)Math.Cos(coneWidth / 180 * Math.PI / 2);
            float s = (float)Math.Sin(coneWidth / 180 * Math.PI / 2);

            //Beginning vector for the cone
            Vector2 v = new Vector2(c * direction.x + s * direction.y, -s * direction.x + c * direction.y);

            //Recalculate c and s for angle between rays
            c = (float)Math.Cos(coneWidth / 180 * Math.PI / numRays);
            s = (float)Math.Sin(coneWidth / 180 * Math.PI / numRays);

            for (int i = 0; i < numRays; i++)
            {
                castLightRay(position, v, mod);
                v = new Vector2(c * v.x - s * v.y, s * v.x + c * v.y);
            }
        }