private void LaunchCharacter(Vector3 m_JumpDirectionVector, Vector3 GrabPosition, float LinecastStart, Collider ignoreCollider = null) { Vector3 offset = Vector3.zero; // Start without offset JumpParameters parameter = new JumpParameters(); // Choose jump parameters based on Jump Type switch (m_JumpType) { case ClimbJumpType.Up: parameter = HopUpParameters; break; case ClimbJumpType.Right: parameter = HopRightParameters; offset = transform.right * m_System.m_Capsule.radius; // Add a small offset to the right to avoid grab on corners break; case ClimbJumpType.Left: parameter = HopLeftParameters; offset = -transform.right * m_System.m_Capsule.radius; // Add a small offset to the left to avoid grab on corners break; case ClimbJumpType.Back: parameter = JumpBackParameters; break; } // Set initial velocity and rotation considering that no data will be found m_CharacterDesiredRotation = GetRotationFromDirection(m_JumpDirectionVector); m_CharacterDesiredVelocity = m_JumpDirectionVector * parameter.HorizontalSpeed + Vector3.up * parameter.VerticalSpeed; // Try find a possible launch LaunchData launch = GetLaunchData(GrabPosition, LinecastStart, parameter, m_JumpDirectionVector, m_MaxAngle, offset, m_ClimbablesLayers, ignoreCollider); if (IsLaunchDataOnlyWay(launch, m_JumpDirectionVector)) { // Found a launch solution SetLaunchParameters(launch, m_JumpType); // Check if character is jumping right or left // After, cast a ray to the target point, if find a ledge and // its normal is not perpendicular to character forward, don't change character rotation if (m_JumpType == ClimbJumpType.Right || m_JumpType == ClimbJumpType.Left) { Vector3 startRay = launch.target - transform.forward; Vector3 direction = (launch.target - startRay).normalized; RaycastHit hit; if (Physics.SphereCast(startRay, 0.1f, direction, out hit, 3f, m_ClimbablesLayers, QueryTriggerInteraction.Collide)) { if (Vector3.Dot(transform.forward, -hit.normal) > 0.5f) { m_CharacterDesiredRotation = transform.rotation; } } } } }
/// <summary> /// Star a climb jump /// </summary> /// <param name="jumpType">Desired jump type</param> /// <param name="directionVector">Direction to jump</param> /// <param name="GrabPosition">Grab position on character</param> /// <param name="LinecastStartHeight">Point that starts cast</param> /// <returns>Time to reach the target point</returns> public float StartClimbJump(ClimbJumpType jumpType, Vector3 directionVector, Vector3 GrabPosition, float LinecastStartHeight, bool abilityUseMath, Collider ignoreCollider = null) { m_JumpType = jumpType; if (m_UseLaunchMath && abilityUseMath) { LaunchCharacter(directionVector, GrabPosition, LinecastStartHeight, ignoreCollider); } else { JumpParameters parameter = new JumpParameters(); // Choose jump parameters based on Jump Type switch (m_JumpType) { case ClimbJumpType.Right: parameter = HopRightParameters; break; case ClimbJumpType.Left: parameter = HopLeftParameters; break; case ClimbJumpType.Back: parameter = JumpBackParameters; break; } SetLaunchParameters(GetLaunchFromParameters(parameter, directionVector), m_JumpType); if (m_JumpType != ClimbJumpType.Back) { m_CharacterDesiredRotation = transform.rotation; } } m_ForceEnterAbility = true; m_DotResult = Quaternion.Dot(transform.rotation, m_CharacterDesiredRotation); return(m_JumpTimeToTarget); }
/// <summary> /// Calculate velocity to reach desired point /// </summary> /// <returns>Data for the launch</returns> public LaunchData CalculateLaunchData(Vector3 startPoint, Vector3 targetPoint, JumpParameters parameter) { LaunchData nullData = new LaunchData(Vector3.zero, targetPoint, -1, false); // Full displacement Vector3 Displacement = targetPoint - startPoint; // Organize by vertical and horizontal displacements float displacementY = Displacement.y; Vector3 displacementXZ = new Vector3(Displacement.x, 0, Displacement.z); // Check if target point is too high // When target point is higher than character maximum jump height, it means that point is not reachable if (displacementY - parameter.m_MaxJumpHeight > 0) { return(nullData); } // Get a jump height if target point is between min height and maximum height float m_JumpHeight = Mathf.Clamp(displacementY, parameter.m_MinJumpHeight, parameter.m_MaxJumpHeight); // Time to reach point // time: Time using the maximum height jump float time = Mathf.Sqrt(-2 * parameter.m_MaxJumpHeight / m_Gravity) + Mathf.Sqrt(2 * (displacementY - parameter.m_MaxJumpHeight) / m_Gravity); // timeLower: Time using height of the ledge float timeLower = Mathf.Sqrt(-2 * m_JumpHeight / m_Gravity) + Mathf.Sqrt(2 * (displacementY - m_JumpHeight) / m_Gravity); // Velocities for each time calculated Vector3 velocity = displacementXZ / time; Vector3 velocityLower = displacementXZ / timeLower; // If velocity is greater than maximum horizontal speed, means that this launch is not possible if (velocity.magnitude > parameter.HorizontalSpeed) { return(nullData); } // Check which launch to use bool useLower = timeLower < time && velocityLower.magnitude <= parameter.HorizontalSpeed; // Set vertical speed float vy = Mathf.Sqrt(-2 * m_Gravity * (useLower ? m_JumpHeight : parameter.m_MaxJumpHeight)); // Get final velocity Vector3 finalVelocity = (useLower) ? velocityLower : velocity; finalVelocity.y = vy * -Mathf.Sign(m_Gravity); return(new LaunchData(finalVelocity, targetPoint, (useLower) ? timeLower : time, true)); }
/// <summary> /// Search ledges around, calculate possible trajectories and choose the best one /// </summary> /// <returns>Best possible launch data</returns> public LaunchData GetLaunchData(Vector3 launchOriginPoint, float LinecastStartPoint, JumpParameters parameter, Vector3 moveDirection, float maxAngle, Vector3 offset, LayerMask climbableMask, Collider ignoreCollider = null) { List <Collider> m_LedgesFound; // Check ledges around if (FoundLedgeToGrab(out m_LedgesFound, moveDirection, LinecastStartPoint, climbableMask, ignoreCollider)) { // Start a list of launches List <LaunchData> launches = new List <LaunchData>(); // Get all possible target points List <Vector3> points = GetTargetPoints(m_LedgesFound, launchOriginPoint, moveDirection, offset); // Loop trough all points foreach (Vector3 point in points) { // Angle between desired direction and target point float angle = Vector3.Angle(moveDirection, Vector3.Scale(point - launchOriginPoint, new Vector3(1, 0, 1)).normalized); // Check angle between character and target point if (angle < maxAngle) { LaunchData data = CalculateLaunchData(launchOriginPoint, point, parameter); if (data.foundSolution) // Is this launch possible? { launches.Add(data); // Add this launch to the list } } } // Found at least one launch if (launches.Count > 0) { LaunchData bestLaunch = ChooseBestLaunchData(launchOriginPoint, launches, moveDirection); // Choose best launch in all possible launches if (debugTrajectory) { DrawPath(bestLaunch, launchOriginPoint); } return(bestLaunch); } } return(new LaunchData()); // Return a new empty launch data that means the character did not find any launch }
// Launch Data for no launch calculation LaunchData GetLaunchFromParameters(JumpParameters jumpParameters, Vector3 horizontalDir) { Vector3 targetVelocity = jumpParameters.HorizontalSpeed * horizontalDir + jumpParameters.VerticalSpeed * Vector3.up; return(new LaunchData(targetVelocity, Vector3.zero, 0, false)); }