예제 #1
0
    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;
    }