Exemple #1
0
 public static StateMaterial Lerp(StateMaterial from, StateMaterial to, float t)
 {
     return(new StateMaterial(
                Mathf.Lerp(from.Friction, to.Friction, t),
                Mathf.Lerp(from.Bounciness, to.Bounciness, t)
                ));
 }
Exemple #2
0
 public void SetState(string animationName, StateMaterial state)
 {
     animator.Play(animationName);
     state.SetupValues(collider2D);
 }
Exemple #3
0
    void FixedUpdate()
    {
        TrackContacts();

        bool controlWasLost = false;

        if (controlLossTimer > 0)
        {
            if (IsGrounded)
            {
                controlLossTimer -= Time.fixedDeltaTime;

                if (controlLossTimer < 0)
                {
                    controlLossTimer = 0;
                }

                if (controlLossTimer == 0)
                {
                    controlRegainStartTimestamp = Time.fixedTime;
                }
            }

            controlWasLost = true;
        }

        // Allow using item only in certain few states.
        inventoryUser.CarriedItemIsActive = false;

        // Allow performing idle action only in truly idle state.
        bool canPerformIdleAction = false;

        // Some active actions must be viewed by the camera.
        bool performedMoveAction = false;

        bool regainingControl = Time.fixedTime - controlRegainStartTimestamp < ControlRegainDuration;

        /* TODO: move groups of statements inside if/else into their own methods,
         * make FixedUpdate () method less "heavy" and more readable. */
        if (!IsGrounded && footWeldJoint != null)
        {
            /* Sometimes weld joint can move character into position where
             * no ground contacts can be found by circle trace method.
             * Such state is not valid since visually character is grounded,
             * but it's not able to move or jump. */
            BreakFootWeld();
        }

        if (regainingControl)
        {
            bumpedWhileControlWasLost = false;
            charController.SetState("ControlRegain", StateMaterials.ControlRegain);
        }
        else if (controlWasLost)
        {
            BreakFootWeld();
            IsPreparingToJump = false;

            var  velocity      = rigidbody2D.velocity;
            bool changeHeading = false;

            if (IsGrounded)
            {
                if (velocity.magnitude > ControlLostChangeHeadingMinVelocity)
                {
                    changeHeading = true;
                }
            }
            else if (velocity.magnitude > 0)
            {
                changeHeading = true;
            }

            if (AnyBumpBetweenFrames)
            {
                bumpedWhileControlWasLost = true;
            }

            if (changeHeading)
            {
                Heading = System.Math.Sign(velocity.x);
            }

            if (IsGrounded || bumpedWhileControlWasLost)
            {
                charController.SetState("ControlLostOnGround", StateMaterials.ControlLostOnGround);
            }
            else
            {
                charController.SetState("ControlLostMidAir", StateMaterials.ControlLostMidAir);
            }
        }
        else
        {
            if (IsPreparingToJump)
            {
                if (Time.fixedTime - jumpPreparationStartTimestamp >= JumpPreparationDuration)
                {
                    IsPreparingToJump = false;

                    if (IsGrounded)
                    {
                        BreakFootWeld();

                        float jumpDirAngle;
                        float jumpStartVelocity;

                        if (jumpForward)
                        {
                            jumpDirAngle      = ForwardJumpDirectionAngle;
                            jumpStartVelocity = ForwardJumpStartVelocity;
                            IsJumpingForward  = true;
                        }
                        else
                        {
                            jumpDirAngle      = BackJumpDirectionAngle;
                            jumpStartVelocity = BackJumpStartVelocity;
                            IsJumpingBackward = true;
                        }

                        float jumpDirAngleRad = jumpDirAngle * Mathf.Deg2Rad;
                        jumpDir    = new Vector2(Mathf.Cos(jumpDirAngleRad), Mathf.Sin(jumpDirAngleRad));
                        jumpDir.x *= Heading;

                        var   flatestFloorContact = FloorContacts.WithMax(c => Vector2.Dot(jumpDir, c.Normal));
                        float frictionAccelFactor = CalculateFrictionAccelFactor(flatestFloorContact);

                        if (frictionAccelFactor > 1)
                        {
                            frictionAccelFactor = 1;
                        }

                        var velocityChange = jumpDir * jumpStartVelocity;
                        velocityChange.x *= frictionAccelFactor;
                        AddForceAndReaction(velocityChange, ForceMode.VelocityChange, flatestFloorContact);
                        lastJumpTimestamp = Time.fixedTime;

                        stopJumpBounciness  = false;
                        performedMoveAction = true;

                        soundPlayer.PlayVariation(JumpSounds);
                        charController.SetState(IsJumpingForward ? "JumpingForward" : "JumpingBackward", StateMaterials.JumpBouncy);
                    }
                    else
                    {
                        // TODO: transfer control to fall-move processing code.
                        EnterStandState();
                    }
                }
                else
                {
                    charController.SetState("PrepareToJump", StateMaterials.Stand);
                }
            }
            else if (IsJumping)
            {
                bool isBouncy = Time.fixedTime - lastJumpTimestamp < JumpBouncinessDuration;

                if ((BumpTheFloorBetweenFrames || IsGrounded) && !isBouncy)
                {
                    IsJumpingForward  = false;
                    IsJumpingBackward = false;
                    EnterStandState();
                }
                else
                {
                    // Stop bouncing after first hit.
                    if (BumpTheWallOrCeilingBetweenFrames)
                    {
                        stopJumpBounciness = true;
                    }

                    StateMaterial stateMaterial;

                    if (isBouncy && !stopJumpBounciness)
                    {
                        // Enable character bounciness.
                        float angle = rigidbody2D.velocity.AngleRad();
                        float t     = Mathf.Abs(Mathf.Cos(angle));
                        stateMaterial = StateMaterial.Lerp(StateMaterials.JumpNormal, StateMaterials.JumpBouncy, t);
                    }
                    else
                    {
                        // Disable bouncing.
                        stateMaterial = StateMaterials.JumpNormal;
                    }

                    if (IsJumpingBackward && Time.fixedTime - lastJumpTimestamp < BackJumpSideAccelerationDuration)
                    {
                        /* Apply little amount of side acceleration so that the character
                         * can climb to the edge of a peak rather than bounce backward and fall down. */
                        int sign  = System.Math.Sign(jumpDir.x);
                        var accel = new Vector2(sign * BackJumpSideAcceleration, 0);
                        rigidbody2D.AddForce(accel, ForceMode.Acceleration);

                        DebugHelper.DrawRay(transform.position, accel, Color.blue, 0, false);
                    }

                    charController.SetState(IsJumpingForward ? "JumpingForward" : "JumpingBackward", stateMaterial);
                }
            }
            else
            {
                bool  movingDown   = Vector2.Dot(rigidbody2D.velocity, -Vector2.up) > 0;
                float downVelocity = movingDown ? rigidbody2D.velocity.magnitude : 0;
                // TODO: apply "Fall" animation after some time of being in the air. Velocity should not be accounted.

                if (!IsGrounded && downVelocity >= FallVelocity)
                {
                    charController.SetState("Fall", StateMaterials.JumpNormal);
                }
                else
                {
                    bool  noMovementPerformed = false;
                    var   move       = new Vector2(MoveX, MoveY);
                    float moveAmount = move.magnitude;

                    if (moveAmount != 0)
                    {
                        var moveDir = move.normalized;

                        if (moveAmount > 1)
                        {
                            moveAmount = 1;
                        }

                        SurfaceContact surfaceContact      = null;
                        Vector2        moveDirAlongSurface = Vector2.zero;
                        float          surfaceAcceleration = 0;
                        float          gravityResistance   = 0;
                        float          maxVelocity         = 0;
                        bool           wantToWalk          = false;
                        bool           canTurn             = false;

                        if (IsGrounded)
                        {
                            canTurn = true;
                            var steepestFloorContact = FloorContacts.WithMin(c => Vector2.Dot(moveDir, c.Normal));
                            var tangent = Common.RightOrthogonal(steepestFloorContact.Normal);
                            moveDirAlongSurface = Vector2.Dot(moveDir, tangent) > 0 ? tangent : -tangent;

                            bool noObstaclesOnTheWay = frameContacts
                                                       .All(c =>
                                                            Vector2.Dot(c.Normal, moveDirAlongSurface) >= 0 ||
                                                            // Push dynamic body if it doesn't belong to other character.
                                                            (c.Collider.attachedRigidbody != null && !IsCharacter(c.Collider))

                                                            /* TODO: check mass of the body? Presumably evaluate to false when object can't be moved.
                                                             * UPD: well, it depends on friction force applied from the floor to an obstacle object,
                                                             * so everything is much more complicated.. */
                                                            );

                            if (noObstaclesOnTheWay)
                            {
                                wantToWalk          = true;
                                surfaceContact      = steepestFloorContact;
                                surfaceAcceleration = WalkAcceleration;
                                gravityResistance   = WalkGravityResistance;
                                maxVelocity         = MaxWalkVelocity;
                            }
                            else
                            {
                                var obstacleContact = frameContacts.First(c => Vector2.Dot(c.Normal, moveDirAlongSurface) < 0);
                                Debug.DrawRay(obstacleContact.Point, obstacleContact.Normal * 0.1f, Color.magenta);
                            }
                        }

                        if (!wantToWalk)
                        {
                            SurfaceContact staircaseContact;
                            bool           canClimb = CheckCanClimbStaircase(moveDir.x, ClimbStepHeight, ClimbStepDepth, out staircaseContact);

                            if (canClimb)
                            {
                                canTurn        = true;
                                wantToWalk     = true;
                                surfaceContact = staircaseContact;

                                float climbMoveDirAngleRad = ClimbMovementDirectionAngle * Mathf.Deg2Rad;
                                var   climbDir             = new Vector2(Mathf.Cos(climbMoveDirAngleRad), Mathf.Sin(climbMoveDirAngleRad));
                                climbDir.x         *= moveDir.x;
                                moveDirAlongSurface = climbDir;

                                surfaceAcceleration = ClimbAcceleration;
                                gravityResistance   = ClimbGravityResistance;
                                maxVelocity         = MaxClimbVelocity;
                            }
                        }

                        if (wantToWalk)
                        {
                            BreakFootWeld();
                            StateMaterial stateMaterial;

                            if (IsCharacter(surfaceContact.Collider))
                            {
                                stateMaterial = StateMaterials.StepOverCharacter;
                            }
                            else
                            {
                                stateMaterial = StateMaterials.Walk;
                            }

                            var otherRigidbody   = surfaceContact.Collider.attachedRigidbody;
                            var platformVelocity = Vector2.zero;

                            if (otherRigidbody != null)
                            {
                                platformVelocity = otherRigidbody.GetPointVelocity(surfaceContact.Point);
                            }

                            var relVelocity          = rigidbody2D.velocity - platformVelocity;
                            var velocityAlongSurface = Common.Project(relVelocity, moveDirAlongSurface);

                            float frictionAccelFactor = CalculateFrictionAccelFactor(surfaceContact);
                            surfaceAcceleration *= frictionAccelFactor;

                            var     velocityDelta           = moveDirAlongSurface * surfaceAcceleration * Time.fixedDeltaTime;
                            var     newVelocityAlongSurface = velocityAlongSurface + velocityDelta;
                            Vector2 velocityChange;

                            // DEV: new approach.
                            // TODO: slow down when walking down steep ground.
                            if (newVelocityAlongSurface.magnitude > maxVelocity)
                            {
                                if (newVelocityAlongSurface.magnitude > velocityAlongSurface.magnitude)
                                {
                                    if (velocityAlongSurface.magnitude < maxVelocity)
                                    {
                                        velocityChange = velocityAlongSurface.normalized * maxVelocity - velocityAlongSurface;
                                    }
                                    else
                                    {
                                        velocityChange = Vector2.zero;
                                    }
                                }
                                else
                                {
                                    velocityChange = newVelocityAlongSurface - velocityAlongSurface;
                                }
                            }
                            else
                            {
                                velocityChange = newVelocityAlongSurface - velocityAlongSurface;
                            }

                            // TODO: old approach.
                            //newVelocityAlongSurface = Vector2.ClampMagnitude ( newVelocityAlongSurface, maxVelocity );
                            //velocityChange = newVelocityAlongSurface - velocityAlongSurface;

                            Debug.DrawRay(transform.position, velocityChange, Color.red, 0, false);

                            AddForceAndReaction(velocityChange, ForceMode.VelocityChange, surfaceContact);
                            AddForceAndReaction(-Physics2D.gravity * gravityResistance, ForceMode.Acceleration, surfaceContact);

                            soundPlayer.PlayVariation(WalkSounds, restart: false);
                            charController.SetState("Walk", stateMaterial);
                        }
                        else
                        {
                            noMovementPerformed = true;
                        }

                        if (canTurn)
                        {
                            var headingScale = headingTransform.localScale;
                            headingScale.x = moveDir.x;
                            headingTransform.localScale = headingScale;
                        }
                    }
                    else
                    {
                        noMovementPerformed = true;
                    }

                    bool readyToJump        = Time.fixedTime - lastJumpTimestamp >= JumpCooldown;
                    bool wantsToPerformJump = PerformForwardJump || PerformBackJump;

                    if (wantsToPerformJump && IsGrounded && readyToJump)
                    {
                        jumpPreparationStartTimestamp = Time.fixedTime;
                        IsPreparingToJump             = true;

                        /* TODO: disable IsPreparingToJump when control lost.
                         * And maybe in some other cases too. */
                        jumpForward = PerformForwardJump;
                    }

                    if (noMovementPerformed)
                    {
                        canPerformIdleAction = true;
                        bool performedIdleAction = false;

                        if (IsStandingStill(FootWeldMaxVelocity))                               // TODO: use other value instead of FootWeldMaxVelocity?
                        {
                            performedIdleAction = charController.PerformIdleAction();
                        }

                        if (!performedIdleAction)
                        {
                            EnterStandState();
                        }
                    }
                    else
                    {
                        performedMoveAction = true;
                    }
                }
            }
        }

        if (!canPerformIdleAction)
        {
            charController.InterruptIdleAction();
        }

        if (performedMoveAction)
        {
            CameraEvents.Moved.Restart();
        }
    }
Exemple #4
0
 public async Task <StateMaterial> UpdateStateMaterial(StateMaterial StateMaterial)
 {
     return(await this._stateMaterialService.Update(StateMaterial));
 }
Exemple #5
0
 public async Task <StateMaterial> CreateStateMaterial([FromBody] StateMaterial StateMaterial)
 {
     return(await this._stateMaterialService.Create(StateMaterial));
 }
Exemple #6
0
 public async Task <StateMaterial> Update(StateMaterial StateMaterial)
 {
     return(await this.asyncRepository.UpdateAsync(StateMaterial));
 }