/// <summary>
    ///     Creates an <see cref="OrientedBoundingBox">OrientedBoundingBox</see> from a <see cref="BoundingBox">BoundingBox</see>.
    /// </summary>
    /// <param name="box">A <see cref="BoundingBox">BoundingBox</see> to create the <see cref="OrientedBoundingBox">OrientedBoundingBox</see> from</param>
    /// <returns>The generated <see cref="OrientedBoundingBox">OrientedBoundingBox</see></returns>
    public static OrientedBoundingBox FromAABB(BoundingBox box)
    {
        var center  = BoundingVolumesExtensions.GetCenter(box);
        var extents = BoundingVolumesExtensions.GetExtents(box);

        return(new OrientedBoundingBox(center, extents));
    }
Ejemplo n.º 2
0
        /// <inheritdoc />
        public override void Draw(GameTime gameTime)
        {
            // Set the DiffuseColor to white to draw this Robot
            RobotEffect.DiffuseColor = Color.White.ToVector3();
            Robot.Draw(RobotWorld, Camera.View, Camera.Projection);

            // Set the DiffuseColor to red to draw this Robot
            RobotEffect.DiffuseColor = Color.Red.ToVector3();
            Robot.Draw(RobotTwoWorld, Camera.View, Camera.Projection);

            // Draw the Chair
            Chair.Draw(ChairWorld, Camera.View, Camera.Projection);

            // Draw the Tank
            Tank.Draw(TankWorld, Camera.View, Camera.Projection);



            // Draw bounding volumes

            Game.Gizmos.DrawCube(BoundingVolumesExtensions.GetCenter(RobotBox), BoundingVolumesExtensions.GetExtents(RobotBox) * 2f, Color.Yellow);

            Game.Gizmos.DrawCube(ChairOBBWorld, TouchingChair ? Color.Orange : Color.Green);

            Game.Gizmos.DrawSphere(_tankSphere.Center, _tankSphere.Radius * Vector3.One, TouchingTank ? Color.Orange : Color.Purple);

            Game.Gizmos.DrawCylinder(RobotTwoCylinder.Transform, TouchingOtherRobot ? Color.Orange : Color.White);


            base.Draw(gameTime);
        }
Ejemplo n.º 3
0
        /// <inheritdoc />
        public override void Draw(GameTime gameTime)
        {
            // Calculate the ViewProjection matrix
            var viewProjection = Camera.View * Camera.Projection;

            // Draw the Robot
            Robot.Draw(RobotWorld, Camera.View, Camera.Projection);

            // Set the WorldViewProjection and Texture for the Floor and draw it
            TilingEffect.Parameters["WorldViewProjection"].SetValue(FloorWorld * viewProjection);
            TilingEffect.Parameters["Texture"].SetValue(FloorTexture);
            Quad.Draw(TilingEffect);

            // Draw each Wall
            // First, set the Wall Texture
            TilingEffect.Parameters["Texture"].SetValue(WallTexture);
            for (int index = 0; index < WallWorldMatrices.Length - 1; index++)
            {
                // Set the WorldViewProjection matrix for each Wall
                TilingEffect.Parameters["WorldViewProjection"].SetValue(WallWorldMatrices[index] * viewProjection);
                // Draw the Wall
                Quad.Draw(TilingEffect);
            }

            // Draw the traversing Wall
            // For this, disable Back-Face Culling as we want to draw both sides of the Quad
            // Save the past RasterizerState
            var rasterizerState = GraphicsDevice.RasterizerState;

            // Use a RasterizerState which has Back-Face Culling disabled
            GraphicsDevice.RasterizerState = RasterizerState.CullNone;

            // Set the WorldViewProjection matrix and draw the Wall
            TilingEffect.Parameters["WorldViewProjection"].SetValue(WallWorldMatrices[WallWorldMatrices.Length - 1] * viewProjection);
            Quad.Draw(TilingEffect);

            // Restore the old RasterizerState
            GraphicsDevice.RasterizerState = rasterizerState;


            // Draw Gizmos for Bounding Boxes and Robot Cylinder

            for (int index = 0; index < WallBoxes.Length; index++)
            {
                var box     = WallBoxes[index];
                var center  = BoundingVolumesExtensions.GetCenter(box);
                var extents = BoundingVolumesExtensions.GetExtents(box);
                Game.Gizmos.DrawCube(center, extents * 2f, Color.Red);
            }

            Game.Gizmos.DrawCylinder(RobotCylinder.Transform, Color.Yellow);

            base.Draw(gameTime);
        }
Ejemplo n.º 4
0
        /// <summary>
        ///     Solves the intersection between the Robot and a collider.
        /// </summary>
        /// <param name="collider">The collider the Robot intersected with</param>
        /// <param name="colliderIndex">The index of the collider in the collider array the Robot intersected with</param>
        /// <returns>True if the collider was a step and it was climbed, False otherwise</returns>
        private bool SolveStepCollision(BoundingBox collider, int colliderIndex)
        {
            // Get the collider properties to check if it's a step
            // Also, to calculate penetration
            var extents        = BoundingVolumesExtensions.GetExtents(collider);
            var colliderCenter = BoundingVolumesExtensions.GetCenter(collider);

            // Is this collider a step?
            // If not, exit
            if (extents.Y >= 6f)
            {
                return(false);
            }

            // Is the base of the cylinder close to the step top?
            // If not, exit
            var distanceToTop = MathF.Abs((RobotCylinder.Center.Y - RobotCylinder.HalfHeight) - (colliderCenter.Y + extents.Y));

            if (distanceToTop >= 12f)
            {
                return(false);
            }

            // We want to climb the step
            // It is climbable if we can reposition our cylinder in a way that
            // it doesn't collide with anything else
            var pastPosition = RobotCylinder.Center;

            RobotCylinder.Center += Vector3.Up * distanceToTop;
            for (int index = 0; index < Colliders.Length; index++)
            {
                if (index != colliderIndex && RobotCylinder.Intersects(Colliders[index]).Equals(BoxCylinderIntersection.Intersecting))
                {
                    // We found a case in which the cylinder
                    // intersects with other colliders, so the climb is not possible
                    RobotCylinder.Center = pastPosition;
                    return(false);
                }
            }

            // If we got here the climb was possible
            // (And the Robot position was already updated)
            return(true);
        }
Ejemplo n.º 5
0
        /// <inheritdoc />
        public override void Draw(GameTime gameTime)
        {
            // Calculate the ViewProjection matrix
            var viewProjection = Camera.View * Camera.Projection;

            // Robot drawing
            Robot.Draw(RobotWorld, Camera.View, Camera.Projection);

            // Floor drawing

            // Set the Technique inside the TilingEffect to "BaseTiling", we want to control the tiling on the floor
            // Using its original Texture Coordinates
            TilingEffect.CurrentTechnique = TilingEffect.Techniques["BaseTiling"];
            // Set the Tiling value
            TilingEffect.Parameters["Tiling"].SetValue(new Vector2(10f, 10f));
            // Set the WorldViewProjection matrix
            TilingEffect.Parameters["WorldViewProjection"].SetValue(FloorWorld * viewProjection);
            // Set the Texture that the Floor will use
            TilingEffect.Parameters["Texture"].SetValue(StonesTexture);
            Quad.Draw(TilingEffect);


            // Steps drawing

            // Set the Technique inside the TilingEffect to "WorldTiling"
            // We want to use the world position of the steps to define how to sample the Texture
            TilingEffect.CurrentTechnique = TilingEffect.Techniques["WorldTiling"];
            // Set the Texture that the Steps will use
            TilingEffect.Parameters["Texture"].SetValue(CobbleTexture);
            // Set the Tiling value
            TilingEffect.Parameters["Tiling"].SetValue(Vector2.One * 0.05f);

            // Draw every Step
            for (int index = 0; index < StairsWorld.Length; index++)
            {
                // Get the World Matrix
                var matrix = StairsWorld[index];
                // Set the World Matrix
                TilingEffect.Parameters["World"].SetValue(matrix);
                // Set the WorldViewProjection Matrix
                TilingEffect.Parameters["WorldViewProjection"].SetValue(matrix * viewProjection);
                BoxPrimitive.Draw(TilingEffect);
            }


            // Draw the Box, setting every matrix and its Texture
            BoxesEffect.World      = BoxWorld;
            BoxesEffect.View       = Camera.View;
            BoxesEffect.Projection = Camera.Projection;

            BoxesEffect.Texture = WoodenTexture;
            BoxPrimitive.Draw(BoxesEffect);


            // Gizmos Drawing
            for (int index = 0; index < Colliders.Length; index++)
            {
                var box     = Colliders[index];
                var center  = BoundingVolumesExtensions.GetCenter(box);
                var extents = BoundingVolumesExtensions.GetExtents(box);
                Game.Gizmos.DrawCube(center, extents * 2f, Color.Red);
            }

            Game.Gizmos.DrawCylinder(RobotCylinder.Transform, Color.Yellow);

            base.Draw(gameTime);
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     Apply horizontal movement, detecting and solving collisions
        /// </summary>
        /// <param name="scaledVelocity">The current velocity scaled by deltaTime</param>
        private void SolveVerticalMovement(Vector3 scaledVelocity)
        {
            // If the Robot has vertical velocity
            if (scaledVelocity.Y == 0f)
            {
                return;
            }

            // Start by moving the Cylinder
            RobotCylinder.Center += Vector3.Up * scaledVelocity.Y;
            // Set the OnGround flag on false, update it later if we find a collision
            OnGround = false;


            // Collision detection
            var collided   = false;
            var foundIndex = -1;

            for (var index = 0; index < Colliders.Length; index++)
            {
                if (!RobotCylinder.Intersects(Colliders[index]).Equals(BoxCylinderIntersection.Intersecting))
                {
                    continue;
                }

                // If we collided with something, set our velocity in Y to zero to reset acceleration
                RobotVelocity = new Vector3(RobotVelocity.X, 0f, RobotVelocity.Z);

                // Set our index and collision flag to true
                // The index is to tell which collider the Robot intersects with
                collided   = true;
                foundIndex = index;
                break;
            }


            // We correct based on differences in Y until we don't collide anymore
            // Not usual to iterate here more than once, but could happen
            while (collided)
            {
                var collider  = Colliders[foundIndex];
                var colliderY = BoundingVolumesExtensions.GetCenter(collider).Y;
                var cylinderY = RobotCylinder.Center.Y;
                var extents   = BoundingVolumesExtensions.GetExtents(collider);

                float penetration;
                // If we are on top of the collider, push up
                // Also, set the OnGround flag to true
                if (cylinderY > colliderY)
                {
                    penetration = colliderY + extents.Y - cylinderY + RobotCylinder.HalfHeight;
                    OnGround    = true;
                }

                // If we are on bottom of the collider, push down
                else
                {
                    penetration = -cylinderY - RobotCylinder.HalfHeight + colliderY - extents.Y;
                }

                // Move our Cylinder so we are not colliding anymore
                RobotCylinder.Center += Vector3.Up * penetration;
                collided              = false;

                // Check for collisions again
                for (var index = 0; index < Colliders.Length; index++)
                {
                    if (!RobotCylinder.Intersects(Colliders[index]).Equals(BoxCylinderIntersection.Intersecting))
                    {
                        continue;
                    }

                    // Iterate until we don't collide with anything anymore
                    collided   = true;
                    foundIndex = index;
                    break;
                }
            }
        }
    /// <summary>
    ///     Calculates an OBB with a given set of points.
    ///     Tests every orientations between initValues and endValues, stepping through angle intervals with a given step size.
    ///     Goes on until it reaches a step less than 0.01
    /// </summary>
    /// <returns>A generated Oriented Bounding Box that contains the set of points</returns>
    private static OrientedBoundingBox ComputeFromPointsRecursive(Vector3[] points, Vector3 initValues, Vector3 endValues,
                                                                  float step)
    {
        var   minObb = new OrientedBoundingBox();
        var   minimumVolume = float.MaxValue;
        var   minInitValues = Vector3.Zero;
        var   minEndValues = Vector3.Zero;
        var   transformedPoints = new Vector3[points.Length];
        float y, z;

        var x = initValues.X;

        while (x <= endValues.X)
        {
            y = initValues.Y;
            var rotationX = MathHelper.ToRadians(x);
            while (y <= endValues.Y)
            {
                z = initValues.Z;
                var rotationY = MathHelper.ToRadians(y);
                while (z <= endValues.Z)
                {
                    // Rotation matrix
                    var rotationZ      = MathHelper.ToRadians(z);
                    var rotationMatrix = Matrix.CreateFromYawPitchRoll(rotationY, rotationX, rotationZ);

                    // Transform every point to OBB-Space
                    for (var index = 0; index < transformedPoints.Length; index++)
                    {
                        transformedPoints[index] = Vector3.Transform(points[index], rotationMatrix);
                    }

                    // Obtain an AABB enclosing every transformed point
                    var aabb = BoundingBox.CreateFromPoints(transformedPoints);

                    // Calculate the volume of the AABB
                    var volume = BoundingVolumesExtensions.GetVolume(aabb);

                    // Find lesser volume
                    if (volume < minimumVolume)
                    {
                        minimumVolume = volume;
                        minInitValues = new Vector3(x, y, z);
                        minEndValues  = new Vector3(x + step, y + step, z + step);

                        // Restore the AABB center in World-Space
                        var center = BoundingVolumesExtensions.GetCenter(aabb);
                        center = Vector3.Transform(center, rotationMatrix);

                        // Create OBB
                        minObb             = new OrientedBoundingBox(center, BoundingVolumesExtensions.GetExtents(aabb));
                        minObb.Orientation = rotationMatrix;
                    }

                    z += step;
                }
                y += step;
            }
            x += step;
        }

        // Loop again if the step is higher than a given acceptance threshold
        if (step > 0.01f)
        {
            minObb = ComputeFromPointsRecursive(points, minInitValues, minEndValues, step / 10f);
        }

        return(minObb);
    }