private RayCastOutputData GetClosestAndHighestRay(List <RayCastOutputData> rayCastResults, BoundBase characterBound)
        {
            float             boundMaxY         = characterBound.GetMax().Y;
            RayCastOutputData rayCastOutputData = null;

            List <RayCastOutputData> mostHighRayCastPositionResults = new List <RayCastOutputData>();

            // find rays with the most high start position
            foreach (var result in rayCastResults)
            {
                if (result.shortestDistance > -1 && GeometryMath.CMP(result.parentRay.StartPosition.Y, boundMaxY) > 0)
                {
                    mostHighRayCastPositionResults.Add(result);
                }
            }

            if (mostHighRayCastPositionResults.Count > 1)
            {
                // find ray with the most close intersection position
                float intersectionDistance = mostHighRayCastPositionResults.First().shortestDistance;
                rayCastOutputData = mostHighRayCastPositionResults.First();

                for (Int32 i = 1; i < mostHighRayCastPositionResults.Count; i++)
                {
                    if (mostHighRayCastPositionResults[i].shortestDistance <= intersectionDistance)
                    {
                        rayCastOutputData    = mostHighRayCastPositionResults[i];
                        intersectionDistance = rayCastOutputData.shortestDistance;
                    }
                }
            }

            return(rayCastOutputData);
        }
        private RayCastOutputData GetClosestRayCastResultFromMultipleRayCastExt(List <FRay> Rays, List <BoundBase> collidedBounds, MovableEntity characterEntity)
        {
            // Get closest ray cast result with existing priority - (high > middle > bottom)

            RayCastOutputData result = null;

            var boundOriginRayCastResult = GetClosestRayCastResult(Rays.Last(), collidedBounds);

            // Highest position has higher priority than origin
            var closestHighest = GetClosestAndHighestRay(GetRayCastResultsFromMultipleRayCast(Rays, collidedBounds, characterEntity), characterEntity.GetCharacterCollisionBound());

            if (closestHighest != null && closestHighest.shortestDistance > -1.0f && closestHighest.shortestDistance <= boundOriginRayCastResult.shortestDistance)
            {
                result = closestHighest;
            }

            else if (boundOriginRayCastResult.shortestDistance > -1)
            {
                result = boundOriginRayCastResult;
            }

            else
            {
                result = GetClosestRayCastResultFromMultipleRayCast(Rays, collidedBounds, characterEntity);
            }

            return(result);
        }
        private void InterProcessDownRayCastCollision(MovableEntity character, BoundBase characterBound, List <BoundBase> collidedBounds)
        {
            List <Vector3> currentPositionsForRayCast = GetCurrentMiddlePositionsForRayCast(characterBound, character);
            List <FRay>    listOfRays = new List <FRay>();

            for (Int32 i = 0; i < currentPositionsForRayCast.Count; i++)
            {
                listOfRays.Add(new FRay(currentPositionsForRayCast[i], -GameWorld.GetWorldInstance().GetLevel().Camera.GetLocalSpaceUpVector()));
            }

            RayCastOutputData closestRayCastDown = GetClosestRayCastResultFromMultipleRayCast(listOfRays, collidedBounds, character);

            if (RAYCAST_COLLIDED(closestRayCastDown.shortestDistance))
            {
                // Character could be elevated on collided mesh

                if (closestRayCastDown.shortestDistance <= (characterBound.GetExtent().Y * 2))
                {
                    float   distanceToStep    = (characterBound.GetExtent().Y - closestRayCastDown.shortestDistance);
                    Vector3 elevationPosition = characterBound.GetOrigin();
                    elevationPosition.Y += distanceToStep;
                    character.SetPosition(elevationPosition);
                    character.ActorState = BehaviorState.IDLE;
                }
                // Character now goes to free fall
                else
                {
                    character.ActorState = BehaviorState.FREE_FALLING;
                }

                character.pushPosition();
            }
            else
            {
                character.popPosition();
                character.ActorState = BehaviorState.IDLE;
            }
        }
        private RayCastOutputData GetClosestRayCastResultFromMultipleRayCast(List <FRay> Rays, List <BoundBase> collidedBounds, MovableEntity characterEntity)
        {
            RayCastOutputData resultOutput           = null;
            float             resultShortestDistance = -1.0f;

            foreach (FRay ray in Rays)
            {
                var localRayCastResult = GetClosestRayCastResult(ray, collidedBounds);

                if (resultShortestDistance <= -1)
                {
                    resultShortestDistance = localRayCastResult.shortestDistance;
                    resultOutput           = localRayCastResult;
                }

                if (localRayCastResult.shortestDistance > -1 && resultShortestDistance >= localRayCastResult.shortestDistance)
                {
                    resultShortestDistance = localRayCastResult.shortestDistance;
                    resultOutput           = localRayCastResult;
                }
            }

            return(resultOutput);
        }
        private void ProcessCollisionAtState_FreeFalling(MovableEntity character, Entity collidedEntity, List <BoundBase> collidedBounds)
        {
            switch (GetEntityType(collidedEntity))
            {
            // If character collided another character during free fall because of forward velocity
            case EntityType.MOVABLE_ENTITY:
            {
                // Restore previous position and set velocity to fall
                character.popPosition();
                character.Velocity = -GameWorld.GetWorldInstance().GetLevel().Camera.GetLocalSpaceUpVector();
                break;
            }

            // If character is in free falling but has encountered some collisions with bounds
            case EntityType.STATIC_ENTITY:
            {
                List <Vector3> previousRayCastPositions = GetPreviousFreeFallBottomPositionsForRayCast(character.GetCharacterCollisionBound(), character);
                List <FRay>    listOfRays = new List <FRay>();
                for (Int32 i = 0; i < previousRayCastPositions.Count; i++)
                {
                    listOfRays.Add(new FRay(previousRayCastPositions[i], character.Velocity));
                }

                FRay rayFromMiddleBottom = listOfRays.First();

                // Necessary data for subsequent calculations
                RayCastOutputData rayCastOutputData           = null;
                float             terrainIntersectionDistance = LandscapeRayIntersection.Intersection_TerrainRay(GameWorld.GetWorldInstance().GetLevel().Terrain.GetData(), rayFromMiddleBottom);

                bool bTerrainIntersection = !(terrainIntersectionDistance < 0.0f ||
                                              RAYCAST_INTERSECTION_FAR(BodyMechanics.GetFreeFallDistanceInVelocity(character.Velocity), terrainIntersectionDistance));

                // No terrain intersection - check intersection with bounds
                if (!bTerrainIntersection)
                {
                    rayCastOutputData = GetClosestRayCastResultFromMultipleRayCast(listOfRays, collidedBounds, character);

                    // Ray collided with one of the bounds, check angle of that plane, if can elevate on it - do it
                    if (RAYCAST_COLLIDED(rayCastOutputData.shortestDistance))
                    {
                        Vector3 normalToCollidedPlane = rayCastOutputData.collidedBound.GetNormalToIntersectedPosition(rayCastOutputData.intersectionPosition);
                        // Character can step on this surface
                        if (REACHABLE_INCLINE(normalToCollidedPlane))
                        {
                            Vector3 BoundOrigin          = character.GetCharacterCollisionBound().GetOrigin();
                            Vector3 NewCharacterPosition = new Vector3(BoundOrigin.X, rayCastOutputData.intersectionPosition.Y + character.GetCharacterCollisionBound().GetExtent().Y,
                                                                       BoundOrigin.Z);
                            character.SetPosition(NewCharacterPosition);
                            character.pushPosition();
                            character.ActorState = BehaviorState.IDLE;
                        }
                        // If normal is down directed or too up directed - character can't step on this surface - return to previous position and set velocity to down
                        else
                        {
                            // This is quick fix
                            character.ActorState = BehaviorState.MOVE;
                            character.popPosition();
                            character.Velocity = -GameWorld.GetWorldInstance().GetLevel().Camera.GetLocalSpaceUpVector();
                        }
                    }
                    // No ray collision, but bound collision exists, bound position is unknown - return to previous position and set velocity to down
                    else
                    {
                        character.popPosition();
                        character.Velocity = -GameWorld.GetWorldInstance().GetLevel().Camera.GetLocalSpaceUpVector();
                    }
                }
                // Character could be elevated on terrain
                else
                {
                    Vector3 CharacterNewPosition = rayFromMiddleBottom.GetPositionInTime(terrainIntersectionDistance);
                    CharacterNewPosition.Y += character.GetCharacterCollisionBound().GetExtent().Y;
                    character.SetPosition(CharacterNewPosition);
                    character.ActorState = BehaviorState.IDLE;
                    character.pushPosition();
                }

                break;
            }
            }
        }
        private void ProcessCollisionAtState_Move(MovableEntity characterEntity, Entity collidedEntity, List <BoundBase> collidedBounds)
        {
            switch (GetEntityType(collidedEntity))
            {
            // If character collided character during move
            case EntityType.MOVABLE_ENTITY:
            {
                characterEntity.popPosition();
                characterEntity.ActorState = BehaviorState.IDLE;
                break;
            }

            case EntityType.STATIC_ENTITY:
            {
                BoundBase characterBound = characterEntity.GetCharacterCollisionBound();

                // 1) First of all character has to do ray cast in move direction
                List <Vector3> previousPositionsForRayCast = GetPreviousClosestPositionsForRayCast(characterBound, characterEntity.Speed, characterEntity);
                List <FRay>    listOfRays = new List <FRay>();
                for (Int32 i = 0; i < previousPositionsForRayCast.Count; i++)
                {
                    listOfRays.Add(new FRay(previousPositionsForRayCast[i], characterEntity.Velocity));
                }
                RayCastOutputData outputData = GetClosestRayCastResultFromMultipleRayCastExt(listOfRays, collidedBounds, characterEntity);

                // Ray intersected with one of collided bounds
                if (RAYCAST_COLLIDED(outputData.shortestDistance))
                {
                    // Distance to collided bound is too large and character can't step so far
                    // In this case do ray cast down from current character position
                    if (RAYCAST_INTERSECTION_FAR((characterEntity.Velocity * characterEntity.Speed).Length, outputData.shortestDistance))
                    {
                        InterProcessDownRayCastCollision(characterEntity, characterBound, collidedBounds);
                    }
                    // Distance to collided bound is small enough to step there
                    // In this case acquire normal to that plane to find out can character step on that surface, if no - pop previous position and set to idle
                    else
                    {
                        var rayCastResults = GetRayCastResultsFromMultipleRayCast(listOfRays, collidedBounds, characterEntity);
                        var upperRayResult = GetClosestAndHighestRay(rayCastResults, characterBound);

                        bool bCanElevateOnMesh = true;

                        if (upperRayResult != null)
                        {
                            // check normal of collided plane
                            BoundBase bound = outputData.collidedBound;
                            Vector3   normalToCollidedPlane = bound.GetNormalToIntersectedPosition(outputData.intersectionPosition);
                            if (!REACHABLE_INCLINE(normalToCollidedPlane))
                            {
                                bCanElevateOnMesh = false;
                            }
                        }

                        if (bCanElevateOnMesh)
                        {
                            Vector3 NewCharacterPosition = characterBound.GetOrigin();
                            NewCharacterPosition.Y = outputData.intersectionPosition.Y + characterBound.GetExtent().Y;
                            characterEntity.SetPosition(NewCharacterPosition);
                            characterEntity.pushPosition();
                        }
                        else
                        {
                            characterEntity.popPosition();
                        }

                        characterEntity.ActorState = BehaviorState.IDLE;
                    }
                }

                /*  There was no intersection with ray, this could be one of these reasons :
                 *   Probably case :
                 *   1) Character is on terrain;
                 *   2) Character is in free falling.
                 */
                else
                {
                    InterProcessDownRayCastCollision(characterEntity, characterBound, collidedBounds);
                }
                break;
            }
            }
        }