示例#1
0
        public override void UpdateBehaviour(float dt)
        {
            // bool isTag = CharacterStateController.Animator.GetCurrentAnimatorStateInfo(0).tagHash == StateNameHash;

            switch (state)
            {
            case LedgeHangingState.Idle:

                if (CharacterActions.movement.Up || autoClimbUp || forceAutoClimbUp)
                {
                    state = LedgeHangingState.TopUp;
                    CharacterStateController.UseRootMotion = true;
                    CharacterStateController.Animator.SetTrigger(topUpParameter);
                }
                else if (CharacterActions.movement.Down)
                {
                    forceExit = true;
                }

                break;

            case LedgeHangingState.TopUp:

                if (CharacterStateController.Animator.GetCurrentAnimatorStateInfo(0).IsName("Exit"))
                {
                    forceExit = true;
                    CharacterActor.ForceGrounded();
                }


                break;
            }
        }
示例#2
0
        public override void EnterBehaviour(float dt, CharacterState fromState)
        {
            CharacterActor.AlwaysNotGrounded = true;
            CharacterActor.IsKinematic       = true;

            forceExit = false;

            for (int i = 0; i < forceAutoClimbUpStates.Length; i++)
            {
                CharacterState state = forceAutoClimbUpStates[i];
                if (fromState == state)
                {
                    forceAutoClimbUp = true;
                    break;
                }
            }

            CharacterActor.SetBodySize(CharacterActor.DefaultBodySize);

            CharacterActor.Forward = Vector3.ProjectOnPlane(-CharacterActor.WallContactNormal, CharacterActor.Up);


            CharacterActor.Velocity = Vector3.zero;


            Vector3 referencePosition = 0.5f * (leftHitInfo.point + rightHitInfo.point);

            Vector3 headToReference = referencePosition - CharacterActor.Top;

            Vector3 correction = Vector3.Project(headToReference, CharacterActor.Up) +
                                 verticalOffset * CharacterActor.Up +
                                 forwardOffset * CharacterActor.Forward;

            targetPosition = CharacterActor.Position + correction;

            CharacterActor.Position = targetPosition;
            CharacterStateController.UseRootMotion = true;
            state = LedgeHangingState.Idle;
        }
    protected void MoveInXDirection(bool grounded)
    {
        // Create a copy of character input which we can modify;
        float characterInputX = characterInput.x;

        // Ignore input if stunned
        if (stunTimer > 0.0f)
            characterInputX = 0.0f;

        // Ignore input if crouching
        if (isCrouching)
            characterInputX = 0.0f;

        // Calculate Velocity
        float actualDrag = 1 - (currentDrag * frameTime);

        // Jump Drag
        if (jumpCount > 0 || !grounded) {
            actualDrag = 1 - (jump.drag * frameTime);
        }

        // Crouch slide drag
        if (isCrouchSliding) {
            actualDrag = 1 - (crouchSlideDrag * frameTime);
        }
        if (actualDrag < 0)
            actualDrag = 0;

        // Timer which ignores character input while jumping away from a wall
        if (wall.canWallJump && oppositeDirectionTimer > 0.0f) {
            oppositeDirectionTimer -= frameTime;
            if (wallJumpDirection == RC_Direction.RIGHT)
                characterInputX = -0.5f;
            else if (wallJumpDirection == RC_Direction.LEFT)
                characterInputX = 0.5f;
        }

        if (characterInputX != 0 && (myParent == null || !myParent.overrideX) && (!grounded || !IsSwimming || swimming.canRun)) {
            bool walking = false;
            if (jumpCount > 0 || !grounded || (characterInputX > 0 && characterInputX < 1.0f) || (characterInputX < 0 && characterInputX > -1.0f))
                walking = true;
            if (movement.movementStyle != MovementStyle.PHYSICS_LIKE && movement.jumpAtRunSpeed && (jumpCount > 0 || !grounded))
                walking = false;
            // TODO Move these behaviours to different functions (can wait till 2.0 upgrade?)
            switch (movement.movementStyle) {
            case MovementStyle.PHYSICS_LIKE:
                float newVelocity = velocity.x + (frameTime * movement.acceleration * characterInputX) * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                // Climbing sideways
                if (climbing.allowClimbing && startedClimbing) {
                    velocity.x = newVelocity;
                    if (velocity.x > climbing.horizontalSpeed)
                        velocity.x = climbing.horizontalSpeed;
                    if (velocity.x < -1 * climbing.horizontalSpeed)
                        velocity.x = -1 * climbing.horizontalSpeed;
                } else if (walking) {
                    // If going too fast just apply drag (don't just limit to walk speed else you may get odd jerks)
                    if ((velocity.x > movement.walkSpeed && characterInputX >= 0.0f) || (velocity.x < movement.walkSpeed * -1 && characterInputX <= 0.0f)) {
                        velocity.x = velocity.x * actualDrag;
                        // If we went too far go back to walk speed
                        if (velocity.x < movement.walkSpeed && characterInputX >= 0.0f) {
                            velocity.x = movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                        } else if (velocity.x > movement.walkSpeed * -1 && characterInputX <= 0.0f) {
                            velocity.x = movement.walkSpeed * -1 * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                        }
                    } else {
                        velocity.x = newVelocity;
                        // Limit to walk speed;
                        if (velocity.x > movement.walkSpeed)
                            velocity.x = movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                        if (velocity.x < -1 * movement.walkSpeed)
                            velocity.x = -1 * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                    }
                } else {
                    velocity.x = newVelocity;
                    // Limit to run speed;
                    if (velocity.x > movement.runSpeed)
                        velocity.x = movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                    if (velocity.x < -1 * movement.runSpeed)
                        velocity.x = -1 * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                }
                break;
            case MovementStyle.DIGITAL:
                if (climbing.allowClimbing && startedClimbing) {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * climbing.horizontalSpeed;
                } else if (walking) {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                } else {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                }
                break;
            case MovementStyle.DIGITAL_WITH_SLIDE:
                if (climbing.allowClimbing && startedClimbing) {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * climbing.horizontalSpeed;
                } else if (walking) {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                } else {
                    velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1);
                }
                break;
            }
        } else {
            switch (movement.movementStyle) {
            case MovementStyle.PHYSICS_LIKE:
                velocity.x = velocity.x * actualDrag;
                break;
            case MovementStyle.DIGITAL:
                velocity.x = 0;
                break;
            case MovementStyle.DIGITAL_WITH_SLIDE:
                velocity.x = velocity.x * actualDrag;
                break;
            }
        }

        // Apply velocity
        if ((myParent == null || !myParent.overrideX) && velocity.x > movement.skinSize || velocity.x * -1 > movement.skinSize) {
            if (targetSlope != 0.0f) myTransform.Translate (Quaternion.Euler(0,0,targetSlope) * new Vector3(velocity.x * frameTime, 0.0f, 0.0f));
            else myTransform.Translate (velocity.x * frameTime, 0.0f, 0.0f);
        }

        float forceSide = 0.0f;

        // Ledge Hang variables
        int ledgeHangHitCount = 0;
        Collider ledgeHangCollider = null;
        RaycastCollider actualLedgeCollider = null;

        // Wall slide variables
        int wallSlideCount = 0;
        RaycastCollider actualWallCollider = null;

        isWallSliding = false;
        isWallHolding = false;

        for (int i = 0; i < sides.Length; i++) {
            RaycastHit hitSides;
            float additionalDistance = 0.0f;
            // If crouching and using autoHeightReduction skip any sides higher than provided value
            if (!isCrouching || !crouch.useHeightReduction || sides[i].offset.y <= crouch.ignoredSideCollidersHigherThan) {
                if (ledgeHanging.autoGrab && velocity.y <= 0.0f) additionalDistance = ledgeHanging.autoGrabDistance;
                else if (wall.canWallSlide) additionalDistance = wall.wallSlideAdditionalDistance;

                hitSides = sides [i].GetCollision (1 << backgroundLayer, additionalDistance);

                // Hit something ...
                if (hitSides.collider != null) {

                    // Update ledge hang
                    if (ledgeHanging.canLedgeHang && !grounded && velocity.y <= 0.0f) {
                        if (sides [i].direction == RC_Direction.RIGHT && (sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) {
                            ledgeHangHitCount++;
                            ledgeHangDirection = RC_Direction.RIGHT;
                            ledgeHangCollider = hitSides.collider;
                            if (sides [i] == highestSideColliders [1]) {
                                actualLedgeCollider = highestSideColliders [1];
                            } else {
                                actualLedgeCollider = highestSideColliders [0];
                            }
                        } else if (sides [i].direction == RC_Direction.LEFT && (sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) {
                            ledgeHangHitCount++;
                            ledgeHangDirection = RC_Direction.LEFT;
                            ledgeHangCollider = hitSides.collider;
                            if (sides [i] == highestSideColliders [1]) {
                                actualLedgeCollider = highestSideColliders [1];
                            } else {
                                actualLedgeCollider = highestSideColliders [0];
                            }
                        }
                    }

                    /// Update wall slide
                    if ((wall.canWallSlide || wall.canWallJump) && !grounded) {
                        if ((sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) {
                            if (hitSides.distance <= sides [i].distance + wall.wallSlideAdditionalDistance) {
                                wallSlideCount++;
                                wallSlideDirection = sides[i].direction;
                                if (sides [i] == highestSideColliders [1]) {
                                    actualWallCollider = highestSideColliders [1];
                                } else {
                                    actualWallCollider = highestSideColliders [0];
                                }
                            }
                        }
                    }

                    // Check for platforms, but only if we are within collider distance + skinSize
                    if (hitSides.distance <= sides [i].distance + movement.skinSize) {
                        Platform platform = hitSides.collider.gameObject.GetComponent<Platform> ();
                        if (platform != null) {
                            platform.DoAction (sides [i], this);
                        }
                    }
                }

                // Stop movement, but only if we are within collider distance
                if (hitSides.distance <= sides [i].distance) {
                    float tmpForceSide = (hitSides.normal * (sides [i].distance - hitSides.distance)).x;
                    if (tmpForceSide > Mathf.Abs (forceSide) || tmpForceSide * -1 > Mathf.Abs (forceSide)) {
                        forceSide = tmpForceSide;
                        //	TODO Remove this after adequate testing break;
                    }
                }
            }
        }

        // Check for ledge hang
        if (ledgeHanging.canLedgeHang && ledgeHangHitCount == 1 && !IsSwimming) {
            bool stopLedgeHang = false;
            if (ledgeHangDirection == RC_Direction.LEFT) {
                if (ledgeHanging.grabOnlyInFacingDirection && CurrentDirection >= 0) {
                    stopLedgeHang = true;
                }
                if (actualLedgeCollider.IsColliding (1 << backgroundLayer, ledgeHanging.edgeDetectionOffset.x + ledgeHanging.autoGrabDistance, ledgeHanging.edgeDetectionOffset.y)) {
                    stopLedgeHang = true;
                }
                if (!stopLedgeHang &&
                    ledgeHangCollider.bounds.max.y < myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint + ledgeHanging.graspLeeway &&
                    ledgeHangCollider.bounds.max.y > myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint - ledgeHanging.graspLeeway) {
                    isLedgeHanging = true;
                    jumpCount = 2;
                    ledgeHangState = LedgeHangingState.TRANSITION;
                    ledgeHangTimer = 0.0f;
                    ledgeHangOriginalPosition = myTransform.position;
                    ledgeHangGoalPosition = ledgeHanging.hangOffset + new Vector3 (ledgeHangCollider.bounds.max.x, ledgeHangCollider.bounds.max.y, myTransform.position.z);
                    // Check for parent
                    Platform platform = ledgeHangCollider.gameObject.GetComponent<Platform> ();
                    if (platform != null) {
                        Transform parentPlatform = platform.ParentOnStand (this);
                        if (parentPlatform != null) {
                            myParent = platform;
                            if (myTransform.parent != parentPlatform) {
                                myTransform.parent = parentPlatform;
                            }
                            ledgeHangGoalPosition += platform.velocity * ledgeHanging.transitionTime;
                        } else {
                            // Force ladder to unparent if we have a "bobble"
                            if (myParent is Ladder) {
                                Unparent();
                            }
                        }
                    }
                }
            } else if (ledgeHangDirection == RC_Direction.RIGHT) {
                if (ledgeHanging.grabOnlyInFacingDirection && CurrentDirection <= 0) {
                    stopLedgeHang = true;
                }
                if (actualLedgeCollider.IsColliding (1 << backgroundLayer, ledgeHanging.edgeDetectionOffset.x + ledgeHanging.autoGrabDistance, ledgeHanging.edgeDetectionOffset.y)) {
                    stopLedgeHang = true;
                }
                if (!stopLedgeHang &&
                    ledgeHangCollider.bounds.max.y < myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint + ledgeHanging.graspLeeway &&
                    ledgeHangCollider.bounds.max.y > myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint - ledgeHanging.graspLeeway) {
                    isLedgeHanging = true;
                    jumpCount = 2;
                    ledgeHangState = LedgeHangingState.TRANSITION;
                    ledgeHangTimer = 0.0f;
                    ledgeHangOriginalPosition = myTransform.position;
                    ledgeHangGoalPosition = ledgeHanging.hangOffset + new Vector3 (ledgeHangCollider.bounds.min.x, ledgeHangCollider.bounds.max.y, myTransform.position.z);
                    // Check for parent
                    Platform platform = ledgeHangCollider.gameObject.GetComponent<Platform> ();
                    if (platform != null) {
                        Transform parentPlatform = platform.ParentOnStand (this);
                        if (parentPlatform != null) {
                            myParent = platform;
                            if (myTransform.parent != parentPlatform) {
                                myTransform.parent = parentPlatform;
                            }
                            ledgeHangGoalPosition += platform.velocity * ledgeHanging.transitionTime;
                        }
                    }
                }
            }
        }

        // Check for wall slide
        if (wallSlideCount > 0 && velocity.y <= 0.0f) {
            isWallHolding = true;
            bool stopWallSlide = true;
            RaycastHit hit = actualWallCollider.GetCollision(1<<backgroundLayer, wall.edgeDetectionOffset.x);
            if (hit.collider != null) {
                currentWallTag = hit.collider.gameObject.tag;
            } else {
                currentWallTag = null;
            }
            if (actualWallCollider.IsColliding (1 << backgroundLayer, wall.edgeDetectionOffset.x, wall.edgeDetectionOffset.y)) {
                stopWallSlide = false;
            }
            if (wall.wallJumpTag != null && wall.wallJumpTag != "" && currentWallTag != wall.wallJumpTag) stopWallSlide = true;
            if (!stopWallSlide && wall.canWallSlide && ((wallSlideDirection == RC_Direction.RIGHT && characterInput.x > 0) || (wallSlideDirection == RC_Direction.LEFT && characterInput.x < 0))) {
                // Support sliding on moving platforms
                // RaycastHit hit = actualWallCollider.GetCollision(1<< backgroundLayer, 0.1f);
                isWallSliding = true;
                State = CharacterState.WALL_SLIDING;
                // Handle moving platforms

                if (hit.collider != null) {
                    Platform platform = hit.collider.gameObject.GetComponent<Platform>();
                    if (platform != null && platform.ParentOnStand(this) != null) {
                        myParent = platform;
                        myTransform.parent = platform.ParentOnStand(this);
                    }
                }
                // End cope with moving platforms
            }
        }

        // Move
        if (forceSide > movement.skinSize) {
            myTransform.Translate(Mathf.Max(velocity.x * frameTime * -1, forceSide), 0.0f, 0.0f);
            wallJumpDirection = RC_Direction.LEFT;
            wallJumpTimer = wall.wallJumpTime;
            hasPressedJumpForWallJump = false;
            hasPressedDirectionForWallJump = false;
            StopCrouch();
        } else if (-1 * forceSide > movement.skinSize) {
            myTransform.Translate(Mathf.Min(velocity.x * frameTime * -1, forceSide), 0.0f, 0.0f);
            wallJumpDirection = RC_Direction.RIGHT;
            wallJumpTimer = wall.wallJumpTime;
            hasPressedJumpForWallJump = false;
            hasPressedDirectionForWallJump = false;
            StopCrouch();
        }
        if ((forceSide > 0 && velocity.x < 0) || (forceSide < 0 && velocity.x > 0)) {
            velocity.x = 0.0f;
        }

        // Animation
        if (grounded) {
            if  (		(velocity.x > movement.walkSpeed && characterInput.x > 0.1f) ||
                 (velocity.x < movement.walkSpeed * -1 && characterInput.x < -0.1f)) {
                State = CharacterState.RUNNING;
            } else if (	(velocity.x > maxSpeedForIdle && characterInput.x > 0.1f) ||
                       (velocity.x < -1 * maxSpeedForIdle  && characterInput.x < -0.1f)){
                State = CharacterState.WALKING;
            } else if (	velocity.x > maxSpeedForIdle || velocity.x < -1 * maxSpeedForIdle ){
                State = CharacterState.SLIDING;
            } else {
                State = CharacterState.IDLE;
            }
        }

        // Reset Drag
        currentDrag = movement.drag;
    }
    /// <summary>
    /// Controls movement while hanging from a ledge.
    /// </summary>
    private void DoLedgeHang()
    {
        switch (ledgeHangState) {
        case LedgeHangingState.TRANSITION:
            velocity.y = 0.0f;
            ledgeHangTimer += frameTime;
            State = CharacterState.LEDGE_HANGING;
            myTransform.position = Vector3.Slerp (ledgeHangOriginalPosition, ledgeHangGoalPosition, ledgeHangTimer / ledgeHanging.transitionTime);

            if (ledgeHangTimer > ledgeHanging.transitionTime) {
                ledgeHangTimer = 0.0f;
                ledgeHangState = LedgeHangingState.HANG;
                myTransform.position = ledgeHangGoalPosition;
            }
            break;
        case LedgeHangingState.HANG:
            // Fall Off
            if (characterInput.x > 0.0f && ledgeHangDirection == RC_Direction.LEFT) {
                isLedgeHanging = false;
                ledgeDropTimer = ledgeHanging.ledgeDropTime;
                State = CharacterState.FALLING;
            } else if (characterInput.x < 0.0f && ledgeHangDirection == RC_Direction.RIGHT) {
                isLedgeHanging = false;
                ledgeDropTimer = ledgeHanging.ledgeDropTime;
                State = CharacterState.FALLING;
            }// Drop Off
            else if (characterInput.y < 0.0f) {
                isLedgeHanging = false;
                ledgeDropTimer = ledgeHanging.ledgeDropTime;
                State = CharacterState.FALLING;
            }
            // Jump Off
            else if (characterInput.jumpButtonDown) {
                if (ledgeHanging.jumpOnlyInOppositeDirection) {
                    oppositeDirectionTimer = ledgeHanging.oppositeDirectionTime;
                    if (ledgeHangDirection == RC_Direction.LEFT)
                        velocity.x = movement.walkSpeed;
                    else if (ledgeHangDirection == RC_Direction.RIGHT)
                        velocity.x = -1 * movement.walkSpeed;
                }
                isLedgeHanging = false;
                velocity.y = ledgeHanging.jumpVelocity;
                jumpCount = 2;
                Unparent();
                startedClimbing = false;
                jumpButtonTimer = jump.jumpTimer;
                jumpHeldTimer = 0.0f;
                ledgeDropTimer = ledgeHanging.ledgeDropTime;
                if (ledgeHanging.jumpVelocity > 0.0f) {
                    State = CharacterState.JUMPING;
                } else {
                    State = CharacterState.FALLING;
                }
            }
            // Climb
            else if (characterInput.y > 0.0f) {
                ledgeHangState = LedgeHangingState.CLIMBING;
                ledgeHangTimer = 0.0f;
            }
            break;
        case LedgeHangingState.CLIMBING:
            ledgeHangTimer += frameTime;
            if (ledgeHangTimer > ledgeHanging.climbTime) {
                ledgeHangTimer = 0.0f;
                State = CharacterState.LEDGE_CLIMB_FINISHED;
                ledgeHangState = LedgeHangingState.FINISHED;
            } else {
                State = CharacterState.LEDGE_CLIMBING;
            }
            break;
        case LedgeHangingState.FINISHED:
            isLedgeHanging = false;
            if (ledgeHangDirection == RC_Direction.RIGHT) {
                myTransform.Translate (ledgeHanging.climbOffset);
            } else if (ledgeHangDirection == RC_Direction.LEFT) {
                myTransform.Translate (new Vector3(-1 * ledgeHanging.climbOffset.x, ledgeHanging.climbOffset.y, ledgeHanging.climbOffset.z));
            }
            State = CharacterState.IDLE;
            break;
        }
    }
示例#5
0
        public override void UpdateBehaviour(float dt)
        {
            bool isTag = CharacterStateController.Animator.GetCurrentAnimatorStateInfo(0).tagHash == StateNameHash;


            switch (state)
            {
            // case LedgeHangingState.Entering:


            //     CharacterActor.Position = targetPosition;
            //     CharacterStateController.UseRootMotion = true;
            //     state = LedgeHangingState.Idle;

            //     break;

            // // case LedgeHangingState.WaitingForAnimator:


            // //     // The transition has ended.
            // //     if( isTag )
            // //     {


            // //     }

            // //     break;

            case LedgeHangingState.Idle:

                if (CharacterActions.movement.Up || autoClimbUp || forceAutoClimbUp)
                {
                    state = LedgeHangingState.TopUp;
                    CharacterStateController.UseRootMotion = true;
                    CharacterStateController.Animator.SetTrigger(topUpParameter);
                }
                else if (CharacterActions.movement.Down)
                {
                    forceExit = true;
                }

                break;

            case LedgeHangingState.TopUp:

                // CharacterStateController.Animator.MatchTarget( ( leftHitInfo.point + rightHitInfo.point ) / 2f , AvatarTarget.Root , 0.7f , 0.95f );

                if (CharacterStateController.Animator.GetCurrentAnimatorStateInfo(0).IsName("Exit"))
                {
                    forceExit = true;
                    CharacterActor.ForceGrounded();
                }

                // if( !isTag )
                // {
                //     forceExit = true;
                //     CharacterActor.ForceGrounded();
                // }


                break;
            }
        }