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 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 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; } } }