protected override void GeneratePath() { CEdgeCastInfo info = m_ControlledCollider.GetEdgeCastInfo(); m_Path.Clear(); CapsuleTransform copy = m_ControlledCollider.GetCapsuleTransformCopy(); //First node is in edgehang alignment, moving away from the edge mildly CapsuleMovementPathNode newNode = m_Path.CreateFirstNode(copy); Vector3 upCenter = info.GetProposedHeadPoint(); upCenter += m_ControlledCollider.GetEdgeCastInfo().GetWallNormal() * 0.03f; copy.SetUpCenter(upCenter); copy.Rotate(info.GetUpDirection(), RotateMethod.FromTop); newNode = m_Path.DuplicateAndAddLastNode(); newNode.CopyFromTransform(copy); //Second node moves up along local up, until the bottom can slide over the edge newNode = m_Path.DuplicateAndAddLastNode(); newNode.m_Duration = m_MoveUpTime; float contactDot = Vector3.Dot(info.GetEdgeNormal(), info.GetEdgePoint()); float bottomDot = Vector3.Dot(info.GetEdgeNormal(), copy.GetDownCenter()) - m_ControlledCollider.GetRadius() - m_MoveUpMargin; float normalDot = Vector3.Dot(info.GetEdgeNormal(), copy.GetUpDirection()); float rawDistance = contactDot - bottomDot; float distance = rawDistance / normalDot; newNode.m_Position += copy.GetUpDirection() * distance; newNode.ApplyEntireMovement(copy); //Third node snaps the capsule to the "upright" position for the ground it's going to stand on newNode = m_Path.DuplicateAndAddLastNode(); newNode.m_Duration = 0.0f; newNode.m_UpDirection = (m_CharacterController.GetAlignsToGround()) ? info.GetEdgeNormal() : Vector3.up; newNode.m_RotateMethod = RotateMethod.FromBottom; newNode.ApplyEntireMovement(copy); newNode.m_Position = copy.GetPosition(); //Final node moves the capsule over the ground newNode = m_Path.DuplicateAndAddLastNode(); newNode.m_Duration = m_MoveSideTime; Vector3 direction = CState.GetDirectionAlongNormal(-info.GetWallNormal(), info.GetEdgeNormal()); newNode.m_Position += direction * m_MoveSideDistance; newNode.ApplyEntireMovement(copy); }
//Query whether this module can be active, given the current state of the character controller (velocity, isGrounded etc.) //Called every frame when inactive (to see if it could be) and when active (to see if it should not be) public override bool IsApplicable() { if (m_ControlledCollider.IsGrounded() || (DoesInputExist("Crouch") && GetButtonInput("Crouch").m_IsPressed) || GetDirInput("Move").m_Direction == DirectionInput.Direction.Down || m_CharacterController.DidJustJump()) { return(false); } //Prevent overriding walljumps if (GetDirInput("Move").IsInThisDirection(m_ControlledCollider.GetEdgeCastInfo().GetWallNormal())) { return(false); } if ((m_CharacterController.GetJumpIsCached()) && m_ControlledCollider.IsTouchingEdge()) { //Move up to avoid transitioning into a wallrun. //Also used to prevent small distance jumps. CEdgeCastInfo edgeInfo = m_ControlledCollider.GetEdgeCastInfo(); CapsuleTransform copy = m_ControlledCollider.GetCapsuleTransformCopy(); Vector3 headStartDisplacement = edgeInfo.GetEdgeNormal() * (m_ControlledCollider.GetRadius() + 0.1f) + edgeInfo.GetWallNormal() * 0.015f; if (!copy.CanMove(headStartDisplacement, true)) { return(false); } copy.Move(headStartDisplacement); m_ProposedNewPosition = copy.GetPosition(); return(true); } return(false); }
//Query whether this module can be active, given the current state of the character controller (velocity, isGrounded etc.) //Called every frame when inactive (to see if it could be) and when active (to see if it should not be) public override bool IsApplicable() { if (!m_IsActive) { //Character can't touch ground, has to touch edge and might be disabled if it is moving upwards if (m_ControlledCollider.IsGrounded()) { return(false); } if (!m_ControlledCollider.IsTouchingEdge()) { return(false); } CEdgeCastInfo info = m_ControlledCollider.GetEdgeCastInfo(); if (GetDirInput("Move").m_Direction == DirectionInput.Direction.Up || GetDirInput("Move").IsInThisDirection(-info.GetWallNormal())) { float angle = Vector3.Angle(info.GetEdgeNormal(), Vector3.up); if (angle >= m_ControlledCollider.GetMaxGroundedAngle()) { return(false); } GeneratePath(); if (m_Path.IsPossible(m_ControlledCollider.GetCapsuleTransform())) { return(true); } } } else { //If the referencepoint slope is too steep to cling on to (during motion), interrupt movement float angle = Vector3.Angle(m_ReferencePoint.m_Transform.up, Vector3.up); if (angle >= m_ControlledCollider.GetMaxGroundedAngle()) { return(false); } if (m_WasInterrupted) { return(false); } if (Time.time - m_StartTime >= m_Path.GetTotalTime() || m_Path.IsDone()) { return(false); } return(true); } return(false); }