void UpdatePositionBetter() { var selfPos = transform.position; #region Vertical Test // Test if player is on ground var isOnGround = false; RaycastHit2D groundHit = new RaycastHit2D(); Vector2 selfGroundPos = Vector2.zero; foreach (var bo in VerticalRayOrigins(true)) { var hit = StageUtility.FindGroundSurface(bo); var groundCheck = hit.transform != null && hit.point.y >= bo.y; if (isOnGround && !groundCheck) { break; // ignore the last mid-in-air rays } isOnGround = groundCheck; if (isOnGround) { groundHit = hit; selfGroundPos = bo; } } float slopeAngle = 0f; float foot2Ground = 0f; if (isOnGround) { slopeAngle = Vector2.SignedAngle(Vector2.up, groundHit.normal); _fallTime = 0f; _xDragModifier = 0f; // adjust value to put player's feet on the ground (on the direction of surface normal) foot2Ground = Vector2.Dot(Vector2.up * (groundHit.point.y - selfGroundPos.y), groundHit.normal); if (!_controller.IsOnGround) { LandOnGround(); } } else if (_controller.IsGravityEnabled) { _fallTime += Time.deltaTime; slopeAngle = -90f; _xDragModifier += drag.x * Time.deltaTime; if (_jumpSpeed > 0) { _jumpSpeed = Mathf.Max(_jumpSpeed - drag.y * Time.deltaTime, 0); } } var gSpeed = -gravity * _fallTime + _jumpSpeed; // the grav falling speed, v = gt (t is the accumulated falling time) #endregion #region Horizontal Test bool isWallBlocked = false; RaycastHit2D wallHit = new RaycastHit2D(); foreach (var ro in HorizontalRayOrigins(_isMovingRight)) { var hit = StageUtility.FindWallSurface(ro, _isMovingRight); if (hit.transform != null) { wallHit = hit; break; } } if (wallHit.transform != null) { var wallAngle = Vector2.Angle(Vector2.up, wallHit.normal); isWallBlocked = wallAngle >= maxClimbAngle; } #endregion var xSpeed = isWallBlocked ? 0f : Speed; Vector2 moveVec = Quaternion.Euler(0, 0, slopeAngle) * new Vector2(xSpeed, foot2Ground); // move speed along groud (if is on the ground) moveVec += Vector2.up * _jumpSpeed; Vector2 fallVec = new Vector2(xSpeed, gSpeed); // falling vector in the next second float fallAngle = Vector2.SignedAngle(Vector2.right, fallVec.normalized); Vector2 finalVec = (slopeAngle >= minDropAngle || slopeAngle > fallAngle) && moveVec.sqrMagnitude > 0 && !_isJumping ? moveVec : fallVec; if (showDebugInfo) { Debug.DrawRay(selfPos, moveVec.normalized, Color.blue); Debug.DrawRay(selfPos, fallVec.normalized, Color.red); Debug.DrawRay(selfPos, finalVec.normalized, Color.green); } var newPos = selfPos + finalVec.ToVector3() * Time.deltaTime; FrameDeltaPos = newPos - selfPos; transform.position = newPos; _controller.IsOnGround = isOnGround; }