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 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 List <Vector3> GetPreviousFreeFallBottomPositionsForRayCast(BoundBase characterBound, MovableEntity characterEntity) { Vector3 boundOrigin = characterBound.GetOrigin(); Vector3 boundMax = characterBound.GetMax(); Vector3 boundMin = characterBound.GetMin(); Vector3 velocityToPreviousPosition = BodyMechanics.GetFreeFallVelocity(characterEntity.Velocity); boundMax -= velocityToPreviousPosition; boundMin -= velocityToPreviousPosition; boundOrigin -= velocityToPreviousPosition; FRay[] rays = new FRay[9] { new FRay(new Vector3(boundMax.X, boundMax.Y, boundMax.Z), characterEntity.Velocity), new FRay(new Vector3(boundMax.X, boundMax.Y, boundMin.Z), characterEntity.Velocity), new FRay(new Vector3(boundMax.X, boundMin.Y, boundMax.Z), characterEntity.Velocity), new FRay(new Vector3(boundMax.X, boundMin.Y, boundMin.Z), characterEntity.Velocity), new FRay(new Vector3(boundMin.X, boundMax.Y, boundMax.Z), characterEntity.Velocity), new FRay(new Vector3(boundMin.X, boundMax.Y, boundMin.Z), characterEntity.Velocity), new FRay(new Vector3(boundMin.X, boundMin.Y, boundMax.Z), characterEntity.Velocity), new FRay(new Vector3(boundMin.X, boundMin.Y, boundMin.Z), characterEntity.Velocity), new FRay(boundOrigin, characterEntity.Velocity) }; return(GetRayCastPositionsOnCharacterBoundByVelocity(rays, characterBound, boundMax, boundMin, boundOrigin)); }
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; } } }