void OnDrawGizmosSelected() { if (!m_showGuides) { return; } float maxWalkSpeed = m_platformPhysics.SolveMaxSpeedWithAccAndDrag(WalkingAcc, WalkingDrag); maxWalkSpeed = Mathf.Min(maxWalkSpeed, MaxWalkingSpeed); if (m_jumpingGuideMode == eJumpingGuideMode.MovingDirection) { if (m_platformPhysics.HSpeed > 0.1f * maxWalkSpeed) { m_simulatedMovingDir = 1f; } else if (m_platformPhysics.HSpeed < -0.1f * maxWalkSpeed) { m_simulatedMovingDir = -1f; } } else if (m_jumpingGuideMode == eJumpingGuideMode.Right) { m_simulatedMovingDir = 1f; } else if (m_jumpingGuideMode == eJumpingGuideMode.Left) { m_simulatedMovingDir = -1f; } if (!Application.isPlaying || IsGrounded || IsClimbing) { m_jumpingGuideBasePos = transform.position; } if (Application.isPlaying) { if (IsGrounded || IsClimbing) { m_simulatedStartingHSpeed = m_platformPhysics.HSpeed; } } else { m_simulatedStartingHSpeed = maxWalkSpeed; } Vector3 simulationPos = m_jumpingGuideBasePos + m_jumpingGuideOffset; float maxHDist = 0f; float minHoldJumpTime = Time.fixedDeltaTime; int iters = Mathf.CeilToInt(JumpingAccTime / minHoldJumpTime) + 1; float jumpingAccTime = 0; float timeDt = Time.fixedDeltaTime; PlatformCharacterPhysics physics = new PlatformCharacterPhysics(m_platformPhysics); for (int iter = 0; iter < iters; ++iter, jumpingAccTime += minHoldJumpTime) { physics.Position = Vector3.zero; physics.HDrag = WalkingDrag; physics.MaxHSpeed = MaxWalkingSpeed; physics.Velocity = new Vector3(m_simulatedStartingHSpeed, JumpingSpeed); float time = 0f; float maxWhileIters = 1000; do { Vector3 prevPos = physics.Position; physics.AddAcceleration(m_simulatedMovingDir * Vector2.right * AirborneAcc); if (time < jumpingAccTime) { physics.Acceleration += transform.up * m_jumpingAcc; } time += timeDt; float timeToGround = physics.SolveTimeToPosY(0f); if (timeToGround >= timeDt) { physics.UpdatePhysics(timeDt); } else { physics.UpdatePhysics(timeToGround); physics.Position = new Vector3(physics.Position.x, 0f); // for float imprecisions, pos.y will me almost but not equal to 0f. This will end the loop. } Gizmos.color = Color.Lerp(new Color(0f, 1f, 0f, 0.2f), new Color(0f, 1f, 0f, 0.5f), 1f - (iter + 1f) / iters); Gizmos.DrawLine(prevPos + simulationPos, physics.Position + simulationPos); // Draw max and min high line depending on if (iter == 0 || iter == iters - 1) { Gizmos.color = new Color(0f, 0f, 0f, 0.2f); Gizmos.DrawSphere(prevPos + simulationPos, 0.03f * GizmoUtils.GetGizmoSize(prevPos + simulationPos)); } }while (physics.Position.y > 0 && --maxWhileIters > 0); //Debug.Assert(maxIters > 0, "Infinite loop detected!"); Gizmos.DrawSphere(physics.Position + simulationPos, 0.03f * GizmoUtils.GetGizmoSize(physics.Position + simulationPos)); maxHDist = Mathf.Max(maxHDist, Mathf.Abs(physics.Position.x)); } maxHDist *= m_simulatedMovingDir; float minJumpHeight = physics.SolveMaxJumpHeight(m_jumpingSpeed); float maxJumpHeight = physics.SolveMaxJumpHeight(m_jumpingSpeed, m_jumpingAcc, m_jumpingTime); Gizmos.color = new Color(1f, 1f, 0f, 1f); Gizmos.DrawLine(simulationPos + new Vector3(-maxHDist * .25f, minJumpHeight), simulationPos + new Vector3(maxHDist * .75f, minJumpHeight)); Gizmos.color = new Color(1f, 1f, 0f, 1f); Gizmos.DrawLine(simulationPos + new Vector3(-maxHDist * .25f, maxJumpHeight), simulationPos + new Vector3(maxHDist * .75f, maxJumpHeight)); Gizmos.color = Color.white; }
protected virtual void Update() { if (m_deltaLadderJumpTimeThreshold > 0f) { m_deltaLadderJumpTimeThreshold -= Time.deltaTime; } DoClimbing(); if (!m_isClimbing) { // Jumping Action if (GetActionState(eControllerActions.Jump)) { bool jumpActionDown = GetIfActionHasChanged(eControllerActions.Jump); int wallPushFactor = 0; if (jumpActionDown && !IsGrounded) { wallPushFactor = m_smartCollider.SkinRightRayContacts.Contains(true) ? -1 : m_smartCollider.SkinLeftRayContacts.Contains(true) ? 1 : 0; if (transform.localScale.x < 0) { wallPushFactor = -wallPushFactor; } } //wall jump if (jumpActionDown && !IsGrounded && (m_jumpingAdditionalParameters.wallJumps < 0 || m_jumpingAdditionalParameters.wallJumps > m_wallJumpsCounter) && m_smartCollider.SkinRightRayContacts.Contains(true) || m_smartCollider.SkinLeftRayContacts.Contains(true)) // isMovingAgainstAWall { ++m_wallJumpsCounter; ++m_airJumpsCounter; m_jumpingTimer = JumpingAccTime; m_platformPhysics.VSpeed = JumpingSpeed; m_platformPhysics.HSpeed = wallPushFactor * m_jumpingAdditionalParameters.wallPushSpeed; } //air jump else if (jumpActionDown && !IsGrounded && (m_jumpingAdditionalParameters.airJumps < 0 || m_jumpingAdditionalParameters.airJumps > m_airJumpsCounter)) { ++m_airJumpsCounter; m_jumpingTimer = JumpingAccTime; m_platformPhysics.VSpeed = JumpingSpeed; } // ground jump else if ( IsGrounded && //GetIfActionHasChanged(eControllerActions.Jumping) && //NOTE: if not commented, player needs to release and press jump to jump m_jumpingTimer == -1 //NOTE: if not commented, player jumps only once if holding jumping while in air ) { m_jumpingTimer = JumpingAccTime; m_platformPhysics.VSpeed = JumpingSpeed; m_isGrounded = false; } } else if (!GetActionState(eControllerActions.Jump)) { m_jumpingTimer = -1f; } // Moving Action if (GetActionState(eControllerActions.Right)) { m_platformPhysics.AddAcceleration(Vector2.right * HorizontalMovingAcc * m_horSpeedScale); } if (GetActionState(eControllerActions.Left)) { m_platformPhysics.AddAcceleration(-Vector2.right * HorizontalMovingAcc * m_horSpeedScale); } // Platform Drop Down Action if (m_isGrounded && m_platformDropTimer <= 0f && GetActionState(eControllerActions.PlatformDropDown)) { //NOTE: for this to work, OneWayCollisionDown should be removed from LayerCollisions m_smartCollider.LayerCollision = m_smartCollider.LayerCollision & ~m_smartCollider.OneWayCollisionDown; m_smartCollider.OneWayCollisionDown = 0; m_platformDropTimer = PlatformDropTime; } // Jumping if (m_jumpingTimer > 0f) { m_jumpingTimer -= Time.deltaTime; m_platformPhysics.Acceleration += transform.up * m_jumpingAcc; } // Platform Drop Down if (m_platformDropTimer > 0f) { m_platformDropTimer -= Time.deltaTime; if (m_platformDropTimer <= 0f) { // Restore the One Way Down collision again after the time is over m_smartCollider.OneWayCollisionDown = m_savedOneWayCollisionDown; } } m_instantVelocity = (transform.position - m_prevPos) / Time.deltaTime; m_prevPos = transform.position; m_platformPhysics.Drag = new Vector2(m_walkingDrag, 0f); m_platformPhysics.MaxHSpeed = MaxWalkingSpeed * m_horSpeedScale; m_platformPhysics.Position = transform.position; m_platformPhysics.UpdatePhysics(Time.deltaTime); m_groundDist = _CalculateGroundDist(); bool wasGrounded = m_isGrounded; m_isGrounded = m_smartCollider.enabled && m_smartCollider.IsGrounded() && m_platformPhysics.DeltaDisp.y <= 0f; // NOTE: Unity 5.4 has a bug in TransformDirection being affected by scale (x is negated to flip the sprite). // So instead of calling TransformDirection I will rotate it directly. transform.position = transform.position + transform.rotation * (m_platformPhysics.Position - transform.position); //+++ Do slopes // If over a slope, move the character in the slope direction if (m_slopeAngle != 0f) { if (Mathf.Abs(m_slopeAngle) <= Mathf.Round(m_maxSlope)) { transform.position += transform.up * m_platformPhysics.DeltaDisp.x * Mathf.Tan(m_slopeAngle * Mathf.Deg2Rad); m_isGrounded = true; } else if (Mathf.Sign(m_slopeAngle) == Mathf.Sign(m_platformPhysics.DeltaDisp.x)) { // Avoid climbing up the slope transform.position = m_platformPhysics.Position = new Vector3(m_prevPos.x, transform.position.y, transform.position.z); m_platformPhysics.HSpeed = 0f; m_isGrounded = true; } } // if not over a slope, check if there is a slope under the character to place it to the ground else if (!m_isGrounded && wasGrounded && m_platformPhysics.DeltaDisp.y <= 0f) { m_groundDist = _CalculateGroundDist(); float magneticDist = Mathf.Abs(m_platformPhysics.DeltaDisp.x * Mathf.Tan((m_maxSlope) * Mathf.Deg2Rad)); if (m_groundDist <= magneticDist) { m_isGrounded = true; m_groundDist += SmartRectCollider2D.k_SkinMinWidth; transform.position += -transform.up * m_groundDist; } } if (m_isGrounded) { m_wallJumpsCounter = m_airJumpsCounter = 0; } m_slopeAngle = 0f; //--- } //Update Actions m_actionChanged = m_prevActionFlags ^ m_actionFlags; m_prevActionFlags = m_actionFlags; }