private void ProcessNoCollisionAtState_Move(MovableEntity character) { Vector3 boundMin = character.GetCharacterCollisionBound().GetMin(); Vector3 origin = character.GetCharacterCollisionBound().GetOrigin(); // Ray cast from middle height position to avoid miss ray casting Vector3 rayCastStartPosition = new Vector3(origin); FRay rayDown = new FRay(rayCastStartPosition, -GameWorld.GetWorldInstance().GetLevel().Camera.GetLocalSpaceUpVector()); float intersectionDistance = LandscapeRayIntersection.Intersection_TerrainRay(GameWorld.GetWorldInstance().GetLevel().Terrain.GetData(), rayDown); // Subtract length of bound extent from middle height position float boundExtent = origin.Y - boundMin.Y; float actualIntersectionDistance = intersectionDistance - boundExtent; // Character is in free fall, next position will be calculated in next tick if (intersectionDistance < 0.0f || RAYCAST_INTERSECTION_FAR(BodyMechanics.GetFreeFallDistanceInVelocity(character.Velocity), actualIntersectionDistance)) { character.ActorState = BehaviorState.FREE_FALLING; } // Check if character can reach that height else { // Character could be elevated on terrain Vector3 CharacterNewPosition = rayDown.GetPositionInTime(intersectionDistance); CharacterNewPosition.Y += character.GetCharacterCollisionBound().GetExtent().Y; character.SetPosition(CharacterNewPosition); character.ActorState = BehaviorState.IDLE; } // Push current position to stack character.pushPosition(); }
private void ProcessNoCollisionAtState_FreeFalling(MovableEntity character) { if (character.Velocity.LengthSquared > 0) { Vector3 boundMin = character.GetCharacterCollisionBound().GetMin(); // Raycast from bottom height point Vector3 rayCastStartPosition = new Vector3(character.GetCharacterCollisionBound().GetOrigin()); rayCastStartPosition.Y = boundMin.Y; FRay ray = new FRay(rayCastStartPosition, character.Velocity); float intersectionDistance = LandscapeRayIntersection.Intersection_TerrainRay(GameWorld.GetWorldInstance().GetLevel().Terrain.GetData(), ray); // Character is still in free fall, just update position if (intersectionDistance < 0.0f || RAYCAST_INTERSECTION_FAR(BodyMechanics.GetFreeFallDistanceInVelocity(character.Velocity), intersectionDistance)) { character.SetPosition(BodyMechanics.UpdateFreeFallPosition(character.ComponentTranslation, character.Velocity)); } // Character could be elevated on terrain else { Vector3 CharacterNewPosition = ray.GetPositionInTime(intersectionDistance); CharacterNewPosition.Y += character.GetCharacterCollisionBound().GetExtent().Y; character.SetPosition(CharacterNewPosition); character.ActorState = BehaviorState.IDLE; } } character.pushPosition(); }
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; } } }