Ejemplo n.º 1
0
        /// <summary>
        ///     Apply horizontal movement, detecting and solving collisions with sliding
        /// </summary>
        /// <param name="scaledVelocity">The current velocity scaled by deltaTime</param>
        private void SolveHorizontalMovementSliding(Vector3 scaledVelocity)
        {
            // Has horizontal movement?
            if (Vector3.Dot(scaledVelocity, new Vector3(1f, 0f, 1f)) == 0f)
            {
                return;
            }

            // Start by moving the Cylinder horizontally
            RobotCylinder.Center += new Vector3(scaledVelocity.X, 0f, scaledVelocity.Z);

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

                // Get the intersected collider and its center
                var collider       = Colliders[index];
                var colliderCenter = BoundingVolumesExtensions.GetCenter(collider);

                // The Robot collided with this thing
                // Is it a step? Can the Robot climb it?
                bool stepClimbed = SolveStepCollision(collider, index);

                // If the Robot collided with a step and climbed it, stop here
                // Else go on
                if (stepClimbed)
                {
                    return;
                }

                // Get the cylinder center at the same Y-level as the box
                var sameLevelCenter = RobotCylinder.Center;
                sameLevelCenter.Y = colliderCenter.Y;

                // Find the closest horizontal point from the box
                var closestPoint = BoundingVolumesExtensions.ClosestPoint(collider, sameLevelCenter);

                // Calculate our normal vector from the "Same Level Center" of the cylinder to the closest point
                // This happens in a 2D fashion as we are on the same Y-Plane
                var normalVector       = sameLevelCenter - closestPoint;
                var normalVectorLength = normalVector.Length();

                // Our penetration is the difference between the radius of the Cylinder and the Normal Vector
                // For precission problems, we push the cylinder with a small increment to prevent re-colliding into the geometry
                var penetration = RobotCylinder.Radius - normalVector.Length() + EPSILON;

                // Push the center out of the box
                // Normalize our Normal Vector using its length first
                RobotCylinder.Center += (normalVector / normalVectorLength * penetration);
            }
        }
Ejemplo n.º 2
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.º 3
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;
                }
            }
        }
Ejemplo n.º 4
0
        /// <inheritdoc />
        public override void Update(GameTime gameTime)
        {
            // Initialize values indicating if the Robot moved, if it rotated, and how much movement should be applied
            var advanceAmount = 0f;
            var rotated       = false;
            var moved         = false;

            // Check for key presses and rotate accordingly
            // We can stack rotations in a given axis by multiplying our past matrix
            // By a new matrix containing a new rotation to apply
            if (Game.CurrentKeyboardState.IsKeyDown(Keys.Right))
            {
                RobotRotation *= Matrix.CreateRotationY(-RobotRotatingVelocity);
                rotated        = true;
            }
            else if (Game.CurrentKeyboardState.IsKeyDown(Keys.Left))
            {
                RobotRotation *= Matrix.CreateRotationY(RobotRotatingVelocity);
                rotated        = true;
            }


            // Check for key presses and set our advance variable accordingly
            if (Game.CurrentKeyboardState.IsKeyDown(Keys.Up))
            {
                advanceAmount = RobotVelocity;
                moved         = true;
            }
            else if (Game.CurrentKeyboardState.IsKeyDown(Keys.Down))
            {
                advanceAmount = -RobotVelocity;
                moved         = true;
            }

            // If there was any movement
            if (moved)
            {
                // Calculate the Robot new Position using the last Position,
                // And adding an increment in the Robot Direction (calculated by rotating a vector by its rotation)
                var newPosition = RobotPosition + Vector3.Transform(Vector3.Backward, RobotRotation) * advanceAmount;

                // Set the Center of the Cylinder as our calculated position
                RobotCylinder.Center = newPosition;

                // Test against every wall. If there was a collision, move our Cylinder back to its original position
                for (int index = 0; index < WallBoxes.Length; index++)
                {
                    if (!RobotCylinder.Intersects(WallBoxes[index]).Equals(BoxCylinderIntersection.None))
                    {
                        moved = false;
                        RobotCylinder.Center = RobotPosition;
                        break;
                    }
                }

                // If there was no collision, update our Robot Position value
                if (moved)
                {
                    RobotPosition = newPosition;
                }
            }

            // If we effectively moved (with no collision) or rotated
            if (moved || rotated)
            {
                // Calculate our World Matrix again
                RobotWorld = RobotScale * RobotRotation * Matrix.CreateTranslation(RobotPosition);

                // Update the Camera accordingly, as it follows the Robot
                UpdateCamera();
            }


            // Update Gizmos with the View Projection matrices
            Game.Gizmos.UpdateViewProjection(Camera.View, Camera.Projection);


            base.Update(gameTime);
        }