Exemplo n.º 1
0
        /// <summary>
        /// Determines the rectangular tile area that is visible to the specified <see cref="IDrawDevice"/>.
        /// </summary>
        /// <param name="device"></param>
        /// <param name="input"></param>
        public static TileOutput GetVisibleTileRect(IDrawDevice device, TileInput input)
        {
            TileOutput output;

            // Determine the view space transform of the tilemap
            float   cameraScaleAtObj   = device.GetScaleAtZ(input.TilemapPos.Z);
            Vector3 viewCenterWorldPos = device.GetWorldPos(new Vector3(device.TargetSize * 0.5f, input.TilemapPos.Z));

            // Early-out, if so small that it might break the math behind rendering a single tile.
            if (cameraScaleAtObj <= 0.000000001f)
            {
                return(EmptyOutput);
            }

            // Determine transformed X and Y axis in world space
            output.XAxisWorld = Vector2.UnitX;
            output.YAxisWorld = Vector2.UnitY;
            MathF.TransformCoord(ref output.XAxisWorld.X, ref output.XAxisWorld.Y, input.TilemapAngle, input.TilemapScale);
            MathF.TransformCoord(ref output.YAxisWorld.X, ref output.YAxisWorld.Y, input.TilemapAngle, input.TilemapScale);

            // Determine which tile is in the center of view space.
            Point2 viewCenterTile = Point2.Zero;
            {
                Vector2 localViewCenter = (viewCenterWorldPos - input.TilemapPos).Xy;
                localViewCenter = new Vector2(
                    Vector2.Dot(localViewCenter, output.XAxisWorld.Normalized),
                    Vector2.Dot(localViewCenter, output.YAxisWorld.Normalized)) / input.TilemapScale;
                viewCenterTile = new Point2(
                    (int)MathF.Floor(localViewCenter.X / input.TileSize.X),
                    (int)MathF.Floor(localViewCenter.Y / input.TileSize.Y));
            }

            // Determine the edge length of a square that is big enough to enclose the world space rect of the Camera view
            float   visualAngle  = input.TilemapAngle - device.ViewerAngle;
            Vector2 visualBounds = new Vector2(
                device.TargetSize.Y * MathF.Abs(MathF.Sin(visualAngle)) + device.TargetSize.X * MathF.Abs(MathF.Cos(visualAngle)),
                device.TargetSize.X * MathF.Abs(MathF.Sin(visualAngle)) + device.TargetSize.Y * MathF.Abs(MathF.Cos(visualAngle)));
            Vector2 localVisualBounds      = visualBounds / cameraScaleAtObj;
            Point2  targetVisibleTileCount = new Point2(
                3 + (int)MathF.Ceiling(localVisualBounds.X / (MathF.Min(input.TileSize.X, input.TileSize.Y) * input.TilemapScale)),
                3 + (int)MathF.Ceiling(localVisualBounds.Y / (MathF.Min(input.TileSize.X, input.TileSize.Y) * input.TilemapScale)));

            // Determine the tile indices (xy) that are visible within that rect
            output.VisibleTileStart = new Point2(
                MathF.Max(viewCenterTile.X - targetVisibleTileCount.X / 2, 0),
                MathF.Max(viewCenterTile.Y - targetVisibleTileCount.Y / 2, 0));
            Point2 tileGridEndPos = new Point2(
                MathF.Min(viewCenterTile.X + targetVisibleTileCount.X / 2, input.TileCount.X),
                MathF.Min(viewCenterTile.Y + targetVisibleTileCount.Y / 2, input.TileCount.Y));

            output.VisibleTileCount = new Point2(
                MathF.Clamp(tileGridEndPos.X - output.VisibleTileStart.X, 0, input.TileCount.X),
                MathF.Clamp(tileGridEndPos.Y - output.VisibleTileStart.Y, 0, input.TileCount.Y));

            // Determine start position for rendering
            output.RenderOriginWorld = input.TilemapPos + new Vector3(
                output.VisibleTileStart.X * output.XAxisWorld * input.TileSize.X +
                output.VisibleTileStart.Y * output.YAxisWorld * input.TileSize.Y);

            return(output);
        }
Exemplo n.º 2
0
 /// <summary>
 /// Transforms screen space to world space.
 /// </summary>
 /// <param name="screenPos"></param>
 /// <param name="device"></param>
 public static Vector3 GetWorldPos(this IDrawDevice device, Vector2 screenPos)
 {
     return(device.GetWorldPos(new Vector3(screenPos)));
 }