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; }
void FixedUpdate() { // Fix an issue when m_isGrounded is always false the first update if SmartRectCollider2D was not updated first if (m_skipFirstFixedUpdate) { m_skipFirstFixedUpdate = false; return; } Vector3 vLocVelocity = transform.rotation != Quaternion.identity ? Quaternion.Inverse(transform.rotation) * m_smartRectCollider.InstantVelocity : m_smartRectCollider.InstantVelocity; m_isGrounded = m_smartRectCollider.enabled && m_smartRectCollider.IsGrounded() && vLocVelocity.y <= Vector3.kEpsilon; if (m_isGrounded) { m_fallingJumpToleranceTimer = FallingJumpTolerance; } if (m_isController) { if (State != eState.Dying) { m_spriteRenderer.color = Color.white; VPad.Update(); float fHorAxis = VPad.GetAxis("Horizontal"); float fVerAxis = VPad.GetAxis("Vertical"); // Fix issue when using keys, because the time to go from 0 to 1 or 1 to 0 is too high by default Unity parameters // So if a moving key is pressed, the horizontal axis will be set to the right value directly if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D)) { fHorAxis = 1f; } else if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A)) { fHorAxis = -1f; } //--- if (m_isClimbing) { // isLadder is true when the collider width is small enough to avoid moving horizontal and center the player in the center of the collider. // By default, it is true when collider width is less than two times the smart rect collider width bool isLadder = (m_currentClimbingCollider is BoxCollider2D) && ((BoxCollider2D)m_currentClimbingCollider).size.x < 2 * m_smartRectCollider.Size.x; Vector3 vDisp = new Vector3(isLadder ? 0f : fHorAxis, fVerAxis); if (isLadder) { // Snap to ladder BoxCollider2D box2DCollider = (BoxCollider2D)m_currentClimbingCollider; Vector3 center = box2DCollider.transform.TransformPoint(box2DCollider.offset); Vector3 snapPos = Vector3.Project(transform.position - center, m_currentClimbingCollider.transform.up); // this allow rotated ladders, like in pirate ship demo snapPos += center; snapPos.z = transform.position.z; transform.position = Vector3.Lerp(transform.position, snapPos, 0.5f); } if (vDisp.magnitude > 0.2f) { transform.position += transform.rotation * vDisp * ClimbingSpeed * Time.deltaTime; SetNextState(eState.Climbing); } else { SetNextState(eState.ClimbingIdle); } } else // normal walking { bool isWalking = (Mathf.Abs(fHorAxis) > 0.7f); fHorAxis = Mathf.Sign(fHorAxis) * Mathf.Max(Mathf.Abs(fHorAxis), 0.4f); if (isWalking) { SetNextState(m_isGrounded ? eState.Walking : (m_smartRectCollider.InstantVelocity.y > 0f ? eState.Jumping : eState.Falling)); float walkAcc = fHorAxis > 0 ? WalkAcc : -WalkAcc; float fHorAxisAbs = Mathf.Abs(fHorAxis); if (Mathf.Sign(fHorAxis) != Mathf.Sign(m_walkVeloc.x) && m_walkVeloc.x != 0) { m_walkVeloc.x += walkAcc + walkAcc * WalkReactivity * fHorAxisAbs; } else { m_walkVeloc.x += walkAcc; } float walkSpeed = m_isSwimming ? WalkSpeed / 2 : WalkSpeed; m_walkVeloc.x = Mathf.Clamp(m_walkVeloc.x, -walkSpeed * fHorAxisAbs, walkSpeed * fHorAxisAbs); float movingSign = (IsSpriteFacingRight ? Mathf.Sign(m_walkVeloc.x) : -Mathf.Sign(m_walkVeloc.x)); if (movingSign != Mathf.Sign(transform.localScale.x)) { Vector3 tempScale = transform.localScale; tempScale.x = -tempScale.x; // flip player transform.localScale = tempScale; } } else { SetNextState(m_isGrounded ? eState.Idle : (m_smartRectCollider.InstantVelocity.y > 0f ? eState.Jumping : eState.Falling)); m_walkVeloc *= Mathf.Clamp01(1 - m_rigidBody2D.drag * Time.deltaTime); } // Apply walk velocity Vector3 locWalkVeloc = transform.rotation != Quaternion.identity ? transform.rotation * m_walkVeloc : m_walkVeloc; transform.position += locWalkVeloc * Time.deltaTime; // Apply jump speed if (m_jumpSpeed > 0f) { Vector3 gravity = Physics2D.gravity * (m_rigidBody2D.gravityScale == 0f ? 1f : m_rigidBody2D.gravityScale); Vector3 locJumpVeloc = m_jumpSpeed * transform.up; transform.position += locJumpVeloc * Time.deltaTime + 0.5f * gravity * Time.deltaTime * Time.deltaTime; m_jumpSpeed = Mathf.Max(0f, m_jumpSpeed - (gravity.magnitude + m_rigidBody2D.drag * JumpDragFactor) * Time.deltaTime); if (m_jumpSpeed < Vector3.kEpsilon) { m_jumpSpeed = 0f; } } } // Check if going down and there is a climbing collider below float SkinBottomWidthFactor = 1.1f; //NOTE: set a value > 1f to allow climbing down when climb collision and platform collision are close Collider2D climbingColliderBelow = GetClimbingColliderBelow(SkinBottomWidthFactor); Collider2D climbingColliderAbove = GetClimbingColliderAbove(); if (fVerAxis < -0.5f && m_currentClimbingCollider == null) { if (climbingColliderBelow != null) { if (m_currentClimbingCollider == null) { m_smartRectCollider.TeleportTo(transform.position - transform.up * m_smartRectCollider.SkinBottomWidth * SkinBottomWidthFactor); } m_currentClimbingCollider = climbingColliderBelow; StartClimbing(); } else { StopClimbing(); } } // Check if going up and it is inside a climbing collider else if (fVerAxis > 0.5f) { if (climbingColliderAbove != null) { m_currentClimbingCollider = climbingColliderAbove; StartClimbing(); } else if (m_smartRectCollider.SkinBottomRayContacts.Contains(true) || climbingColliderBelow == null) { StopClimbing(); } } // Stop climbing once the top is reached else if (m_isGrounded || (climbingColliderBelow == null && climbingColliderAbove == null)) { StopClimbing(); } /*/ Used to teleport player to mouse position and test collisions with world * if( Input.GetMouseButton(0) ) * { * Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); * pos.z = transform.position.z; * transform.position = pos; * } * //*/ } } else { } }