Exemplo n.º 1
0
    void movement()
    {
        // Gathering information :
        int     contactCount = motor.getContactCount();
        Vector2 leftTangent  = Vector2.zero;
        Vector2 rightTangent = Vector2.zero;
        Vector2 leftNormal   = Vector2.zero;
        Vector2 rightNormal  = Vector2.zero;
        Vector2 oldSpeed     = speed;
        float   oldSpeedNorm = Vector2.Distance(speed, Vector2.zero);

        if (contactCount >= 1)
        {
            leftTangent  = motor.getLeftTangent().normalized;
            rightTangent = motor.getRightTangent().normalized;
            leftNormal   = motor.getLeftNormal().normalized;
            rightNormal  = motor.getRightNormal().normalized;
        }
        bool isLeftMovement = Vector2.Angle(speed, leftTangent) < Vector2.Angle(speed, rightTangent);

        bool leftGround   = Vector2.Angle(Vector2.up, leftNormal) < groundAngle;
        bool rightGround  = Vector2.Angle(Vector2.up, rightNormal) < groundAngle;
        bool leftWall     = Vector2.Angle(Vector2.up, leftNormal) < 91 && !leftGround;
        bool rightWall    = Vector2.Angle(Vector2.up, rightNormal) < 91 && !rightGround;
        bool leftCeiling  = !leftGround && !leftWall;
        bool rightCeiling = !rightGround && !rightWall;

        // Movement choices :
        bool ld    = Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.D);
        bool rd    = Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.Q);
        bool ud    = Input.GetKey(KeyCode.Z) && !Input.GetKey(KeyCode.S);
        bool bd    = Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.Z);
        bool stick = Input.GetKey(KeyCode.LeftShift);
        bool jump  = Input.GetKeyDown(KeyCode.Space);

        // walk order :
        bool goRight = (Vector2.Angle(Vector2.up, rightNormal) < 80 && rd);

        goRight |= (Vector2.Angle(-Vector2.up, rightNormal) < 80 && ld);
        goRight |= (Vector2.Angle(Vector2.right, rightNormal) < 80 && bd);
        goRight |= (Vector2.Angle(-Vector2.right, rightNormal) < 80 && ud);

        bool goLeft = (Vector2.Angle(Vector2.up, leftNormal) < 80 && ld);

        goLeft |= (Vector2.Angle(-Vector2.up, leftNormal) < 80 && rd);
        goLeft |= (Vector2.Angle(Vector2.right, leftNormal) < 80 && ud);
        goLeft |= (Vector2.Angle(-Vector2.right, leftNormal) < 80 && bd);

        // nudge order :
        bool nudgeLeft  = ld && !rd;
        bool nudgeRight = rd && !ld;

        // walk condition :
        bool acceptRightWalk = contactCount >= 1 && rightGround;

        acceptRightWalk |= contactCount == 1 && rightWall && stick &&
                           (Vector2.Dot(rightTangent, Vector2.up) < 0 || !isLeftMovement) &&
                           oldSpeedNorm > 0.1f;
        acceptRightWalk |= contactCount >= 1 && rightCeiling && stick && oldSpeedNorm > 0.1f;

        bool acceptLeftWalk = contactCount >= 1 && leftGround;

        acceptLeftWalk |= contactCount >= 1 && leftWall && stick &&
                          (Vector2.Dot(leftTangent, Vector2.up) < 0 || isLeftMovement) &&
                          oldSpeedNorm > 0.1f;
        acceptLeftWalk |= contactCount >= 1 && leftCeiling && stick && oldSpeedNorm > 0.1f;

        // nudge condition :
        bool acceptLeftNudge = contactCount == 0;

        acceptLeftNudge |= contactCount == 1 && !stick && leftWall && !leftGround && !rightGround &&
                           Vector2.Dot(leftNormal, -Vector2.right) > 0;
        acceptLeftNudge |= contactCount == 2 && !stick && leftWall && !leftGround && !rightGround &&
                           Vector2.Dot(leftNormal, -Vector2.right) > 0 &&
                           Vector2.Dot(rightNormal, -Vector2.right) > 0;

        bool acceptRightNudge = contactCount == 0;

        acceptRightNudge |= contactCount == 1 && !stick && leftWall && !leftGround && !rightGround &&
                            Vector2.Dot(leftNormal, Vector2.right) > 0;
        acceptRightNudge |= contactCount == 2 && !stick && leftWall && !leftGround && !rightGround &&
                            Vector2.Dot(leftNormal, Vector2.right) > 0 &&
                            Vector2.Dot(rightNormal, Vector2.right) > 0;

        bool acceptIdling = contactCount >= 1 && (leftGround || rightGround) && !goLeft && !goRight;

        // gravity
        bool applyGrav     = contactCount == 0;
        bool applyWallGrav = contactCount >= 1 && (leftWall || leftCeiling) && !leftGround;

        // idle
        if (acceptIdling)
        {
            //Debug.Log ("idling");
            Vector2 delta = Vector2.zero;
            if (isLeftMovement)
            {
                //Debug.Log ("idling right");
                delta = idleAcceleration * rightTangent * Time.deltaTime;
            }
            else
            {
                //Debug.Log("idling left");
                delta = idleAcceleration * leftTangent * Time.deltaTime;
            }

            if (Vector2.Dot(delta + speed, oldSpeed) <= 0)
            {
                speed = Vector2.zero;
            }
            else
            {
                speed += delta;
            }
        }

        if (applyGrav)
        {
            //Debug.Log ("gravity");
            speed += gravity * Time.deltaTime;
        }

        if (applyWallGrav)
        {
            //Debug.Log ("wall gravity");
            if (Vector2.Dot(leftTangent, -Vector2.up) > 0)
            {
                speed += Vector2.Dot(gravity * wallGravMultiplier, leftTangent) * leftTangent * Time.deltaTime;
            }
            else if (Vector2.Dot(rightTangent, -Vector2.up) > 0)
            {
                speed += Vector2.Dot(gravity * wallGravMultiplier, rightTangent) * rightTangent * Time.deltaTime;
            }
        }

        if (applyWallGrav && !(goLeft && acceptLeftWalk) && !(goRight && acceptRightWalk))
        {
            //Debug.Log ("wall drag");
            speed += -wallDrag * speed * Time.deltaTime;
        }

        // nudge
        if (nudgeLeft && acceptLeftNudge)
        {
            //Debug.Log ("nudge left");
            speed += -(nudge * Time.deltaTime) * Vector2.right;
        }
        if (nudgeRight && acceptRightNudge)
        {
            //Debug.Log ("nudge right");
            speed += (nudge * Time.deltaTime) * Vector2.right;
        }

        // walk right
        if (goRight && acceptRightWalk)
        {
            //Debug.Log ("go right");
            if (isLeftMovement)
            {
                Vector2 delta = switchAcceleration * rightTangent * Time.deltaTime;

                if (Vector2.Dot(oldSpeed + delta, speed) < 0)
                {
                    speed -= Vector2.Dot(speed, rightTangent) * rightTangent;
                }
                else
                {
                    speed += delta;
                }
            }
            else if (oldSpeedNorm < maxWalkSpeed)
            {
                speed += walkAcceleration * rightTangent * Time.deltaTime;
            }
        }

        // walk left
        if (goLeft && acceptLeftWalk)
        {
            //Debug.Log ("go left");
            if (!isLeftMovement)
            {
                Vector2 delta = switchAcceleration * leftTangent * Time.deltaTime;

                if (Vector2.Dot(oldSpeed + delta, speed) < 0)
                {
                    speed -= Vector2.Dot(speed, leftTangent) * leftTangent;
                }
                else if (oldSpeedNorm < maxWalkSpeed)
                {
                    speed += delta;
                }
            }
            else if (oldSpeedNorm < maxWalkSpeed)
            {
                speed += walkAcceleration * leftTangent.normalized * Time.deltaTime;
            }
        }

        // jump
        if (contactCount >= 1)
        {
            jumping = false;
        }
        if (jumping && Input.GetKeyUp(KeyCode.Space) && Time.time - lastJump < maxJumpStop && speed.y > jumpSpeed / 2)
        {
            speed  -= Vector2.up * jumpSpeed / 2;
            jumping = false;
        }

        if (jump)
        {
            if (contactCount >= 1)
            {
                if (leftGround || rightGround)
                {
                    lastJump = Time.time;
                    jumping  = true;
                    speed   += jumpSpeed * Vector2.up;
                }
                else if (leftWall && !(goRight && acceptRightWalk || goLeft && acceptLeftWalk))
                {
                    // Debug.Log ("wall drag jump");
                    if (Vector2.Dot(leftNormal, Vector2.right) > 0)
                    {
                        speed = jumpSpeed * (Vector2.up * 2 + Vector2.right).normalized;
                    }
                    else
                    {
                        speed = jumpSpeed * (Vector2.up * 2 - Vector2.right).normalized;
                    }
                }
                else
                {
                    speed += jumpSpeed * (Vector2.Angle(leftNormal, Vector2.up) < Vector2.Angle(rightNormal, Vector2.up) ?
                                          leftNormal : rightNormal);
                }
            }
        }

        // rocket influence
        if (Input.GetMouseButton(0) && fuel > 0)
        {
            Vector2 direction = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
            float   distance  = Vector2.Distance(Camera.main.ScreenToWorldPoint(Input.mousePosition), transform.position);
            float   strength  = minRocketForce[rocketLevel] + (maxRocketForce[rocketLevel] - minRocketForce[rocketLevel]) * distance / rocketRadius;

            float force = Mathf.Min(strength, maxRocketForce[rocketLevel]) * Time.deltaTime;
            force = Mathf.Min(fuel / fuelPerForce, force);
            float projectedSpeed = Vector2.Dot(oldSpeed, direction.normalized);
            if (projectedSpeed < terminalRocketSpeed)
            {
                speed += direction.normalized * force;
            }
            fuel -= force * fuelPerForce;
        }

        // stepping movement
        if (nudgeLeft && acceptLeftNudge && (leftWall || leftCeiling))
        {
            motor.move(-0.1f * Time.deltaTime * Vector2.right);
        }
        if (nudgeRight && acceptRightNudge && (leftWall || leftCeiling))
        {
            motor.move(0.1f * Time.deltaTime * Vector2.right);
        }
        if (leftCeiling && (!stick || (isLeftMovement && goRight) ||
                            (!isLeftMovement && goLeft) ||
                            oldSpeedNorm < ceilingDropOffSpeed))
        {
            motor.move(-0.1f * Time.deltaTime * Vector2.up);
        }

        Vector2 movement = speed * Time.deltaTime;

        movement = adaptSpeedToContact(movement);

        int a = 0;

        while (Vector2.Distance(movement, Vector2.zero) > 0.001f && a < 10)
        {
            a++;
            movement = motor.move(movement);

            movement = adaptSpeedToContact(movement);
        }
    }
    void Update()
    {
        isGrounded = (motor.getContactCount() >= 1 && Vector2.Angle(Vector2.up, motor.getLeftNormal()) < 88) ||
                     (motor.getContactCount() >= 2 && Vector2.Angle(Vector2.up, motor.getRightNormal()) < 88);

        speed += gravity * Time.deltaTime;

        if (isGrounded)
        {
            if (Input.GetKey(KeyCode.Q) && Vector2.Angle(Vector2.up, motor.getLeftNormal()) < 88)
            {
                speed = walkSpeed * motor.getLeftTangent();
            }
            else if (Input.GetKey(KeyCode.D) && Vector2.Angle(Vector2.up, motor.getRightNormal()) < 88)
            {
                speed = walkSpeed * motor.getRightTangent();
            }
            else
            {
                speed = Vector2.zero;
            }
            if (Input.GetKeyDown(KeyCode.Space))
            {
                speed.y += jumpSpeed;
            }
        }
        else
        {
            if (Input.GetKey(KeyCode.Q))
            {
                speed += -nudge * Time.deltaTime * Vector2.right;
            }
            if (Input.GetKey(KeyCode.D))
            {
                speed += nudge * Time.deltaTime * Vector2.right;
            }
        }

        if (motor.getContactCount() >= 1)
        {
            Vector2 normal = motor.getLeftNormal();
            if (Vector2.Dot(normal, speed) < 0)
            {
                speed -= Vector2.Dot(speed, normal) * normal;
            }
        }

        if (motor.getContactCount() == 2)
        {
            Vector2 normal = motor.getRightNormal();
            if (Vector2.Dot(normal, speed) < 0)
            {
                speed -= Vector2.Dot(speed, normal) * normal;
            }
        }

        Vector2 movement = speed * Time.deltaTime;

        while (Vector2.Distance(movement, Vector2.zero) > 0.001f)
        {
            movement = motor.move(movement);
            if (motor.getContactCount() >= 1)
            {
                speed -= Vector2.Dot(speed, motor.getLeftNormal()) * motor.getLeftNormal();
            }
        }

        /*if (Input.GetKeyDown (KeyCode.Q)) {
         *      motor.move(-Vector2.right/3);
         * }
         * if (Input.GetKeyDown (KeyCode.D)) {
         *      motor.move (-Vector2.left/3);
         * }
         * if (Input.GetKeyDown (KeyCode.Z)) {
         *      motor.move(Vector2.up/3);
         * }
         * if (Input.GetKeyDown (KeyCode.S)) {
         *      motor.move (-Vector2.up / 3);
         * }*/
    }
    void movement()
    {
        // Gathering information :
        int     contactCount = motor.getContactCount();
        Vector2 leftTangent  = Vector2.zero;
        Vector2 rightTangent = Vector2.zero;
        Vector2 leftNormal   = Vector2.zero;
        Vector2 rightNormal  = Vector2.zero;
        Vector2 oldSpeed     = speed;
        float   oldSpeedNorm = 0;

        switch (direction)
        {
        case Direction.free: oldSpeedNorm = Vector2.Distance(speed, Vector2.zero); break;

        case Direction.left: oldSpeedNorm = leftSpeed; break;

        case Direction.right: oldSpeedNorm = rightSpeed; break;
        }

        if (contactCount >= 1)
        {
            leftTangent  = motor.getLeftTangent().normalized;
            rightTangent = motor.getRightTangent().normalized;
            leftNormal   = motor.getLeftNormal().normalized;
            rightNormal  = motor.getRightNormal().normalized;
        }
        bool isLeftMovement = direction == Direction.left;

        bool leftGround   = Vector2.Angle(Vector2.up, leftNormal) < groundAngle;
        bool rightGround  = Vector2.Angle(Vector2.up, rightNormal) < groundAngle;
        bool leftWall     = Vector2.Angle(Vector2.up, leftNormal) < 91 && !leftGround;
        bool rightWall    = Vector2.Angle(Vector2.up, rightNormal) < 91 && !rightGround;
        bool leftCeiling  = !leftGround && !leftWall;
        bool rightCeiling = !rightGround && !rightWall;

        // Movement choices :
        bool ld    = Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.D);
        bool rd    = Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.Q);
        bool ud    = Input.GetKey(KeyCode.Z) && !Input.GetKey(KeyCode.S);
        bool bd    = Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.Z);
        bool stick = Input.GetKey(KeyCode.LeftShift);
        bool jump  = Input.GetKeyDown(KeyCode.Space);

        // walk order :
        bool goRight = (Vector2.Angle(Vector2.up, rightNormal) < 80 && rd);

        goRight |= (Vector2.Angle(-Vector2.up, rightNormal) < 80 && ld);
        goRight |= (Vector2.Angle(Vector2.right, rightNormal) < 80 && bd);
        goRight |= (Vector2.Angle(-Vector2.right, rightNormal) < 80 && ud);

        bool goLeft = (Vector2.Angle(Vector2.up, leftNormal) < 80 && ld);

        goLeft |= (Vector2.Angle(-Vector2.up, leftNormal) < 80 && rd);
        goLeft |= (Vector2.Angle(Vector2.right, leftNormal) < 80 && ud);
        goLeft |= (Vector2.Angle(-Vector2.right, leftNormal) < 80 && bd);

        // nudge order :
        bool nudgeLeft  = ld && !rd;
        bool nudgeRight = rd && !ld;

        // walk condition :
        bool acceptRightWalk = contactCount >= 1 && rightGround;

        acceptRightWalk |= contactCount == 1 && rightWall && stick &&
                           (Vector2.Dot(rightTangent, Vector2.up) < 0 || !isLeftMovement);
        acceptRightWalk |= contactCount >= 1 && rightCeiling && stick && oldSpeedNorm > 0.1f;

        bool acceptLeftWalk = contactCount >= 1 && leftGround;

        acceptLeftWalk |= contactCount >= 1 && leftWall && stick &&
                          (Vector2.Dot(leftTangent, Vector2.up) < 0 || isLeftMovement);
        acceptLeftWalk |= contactCount >= 1 && leftCeiling && stick && oldSpeedNorm > 0.1f;

        // nudge condition :
        bool acceptLeftNudge = contactCount == 0;

        acceptLeftNudge |= contactCount == 1 && !stick && (leftWall || leftCeiling) && !leftGround && !rightGround &&
                           Vector2.Dot(leftNormal, -Vector2.right) > 0;
        acceptLeftNudge |= contactCount == 2 && !stick && (leftWall || leftCeiling) && !leftGround && !rightGround &&
                           Vector2.Dot(leftNormal, -Vector2.right) > 0 &&
                           Vector2.Dot(rightNormal, -Vector2.right) > 0;

        bool acceptRightNudge = contactCount == 0;

        acceptRightNudge |= contactCount == 1 && !stick && (leftWall || leftCeiling) && !leftGround && !rightGround &&
                            Vector2.Dot(leftNormal, Vector2.right) > 0;
        acceptRightNudge |= contactCount == 2 && !stick && (leftWall || leftCeiling) && !leftGround && !rightGround &&
                            Vector2.Dot(leftNormal, Vector2.right) > 0 &&
                            Vector2.Dot(rightNormal, Vector2.right) > 0;

        bool acceptIdling = contactCount >= 1 && (leftGround || rightGround) && !goLeft && !goRight;

        // gravity
        bool applyGrav     = contactCount == 0;
        bool applyWallGrav = contactCount >= 1 && (leftWall || leftCeiling) && !leftGround && !rightGround;

        bool applyDrag = !(acceptRightWalk && goRight) && !(acceptLeftWalk && goLeft) && leftWall;

        // jump
        if (leftGround && Time.time - lastJump > maxJumpStop)
        {
            jumping = false;
        }
        if (jumping && Input.GetKeyUp(KeyCode.Space) && Time.time - lastJump < maxJumpStop)
        {
            if (direction == Direction.free && speed.y > 0)
            {
                speed.y /= (1 + speed.y / jumpSpeed);
            }
            else if (direction == Direction.left && Vector2.Dot(Vector2.up, leftTangent) > 0)
            {
                leftSpeed /= (1 + leftSpeed / jumpSpeed);
            }
            else if (direction == Direction.right && Vector2.Dot(Vector2.up, rightTangent) > 0)
            {
                rightSpeed /= (1 + rightSpeed / jumpSpeed);
            }
            jumping = false;
        }
        // leap jump
        if (leapFrame >= leapMaxFrame || contactCount >= 1)
        {
            leaped = false;
        }
        if (leaped)
        {
            if (leapFrame < leapMaxFrame && jump)
            {
                speed    += jumpSpeed * Vector2.up;
                jumping   = true;
                lastJump  = Time.time;
                direction = Direction.free;
            }
            leapFrame++;
        }

        if (contactCount == 0)
        {
            direction = Direction.free;
            speed    += gravity * Time.deltaTime;
            if (ld)
            {
                speed += -nudge * Vector2.right * Time.deltaTime;
            }
            if (rd)
            {
                speed += nudge * Vector2.right * Time.deltaTime;
            }
        }
        else
        {
            if (jump)
            {
                if (leftGround || rightGround)
                {
                    speed    = jumpSpeed * Vector2.up;
                    jumping  = true;
                    lastJump = Time.time;
                }
                else if (leftWall || leftCeiling)
                {
                    if (applyDrag)
                    {
                        if (Vector2.Dot(leftNormal, Vector2.right) > 0)
                        {
                            speed = jumpSpeed * (Vector2.right + Vector2.up * 2.5f).normalized;
                        }
                        else
                        {
                            speed = jumpSpeed * (-Vector2.right + Vector2.up * 2.5f).normalized;
                        }
                        jumping  = true;
                        lastJump = Time.time;
                    }
                    else
                    {
                        speed = jumpSpeed * leftNormal;
                    }
                }
                if (!applyDrag)
                {
                    switch (direction)
                    {
                    case Direction.free: break;

                    case Direction.left: speed += leftTangent * leftSpeed; break;

                    case Direction.right: speed += rightTangent * rightSpeed; break;
                    }
                }

                direction = Direction.free;
            }
            else if (Vector2.Angle(leftNormal, -Vector2.up) < 80 &&
                     (acceptRightWalk && goRight && isLeftMovement ||
                      acceptLeftWalk && goLeft && !isLeftMovement ||
                      oldSpeedNorm < ceilingDropOffSpeed ||
                      !stick))
            {
                speed = -Vector2.up * 0.5f;

                switch (direction)
                {
                case Direction.free: break;

                case Direction.left: speed += leftTangent * leftSpeed; break;

                case Direction.right: speed += rightTangent * rightSpeed; break;
                }

                direction = Direction.free;
            }
            else
            {
                if (acceptLeftNudge && ld)
                {
                    speed = -(nudge * Time.deltaTime + 0.5f) * Vector2.right;
                    switch (direction)
                    {
                    case Direction.free: break;

                    case Direction.left: speed += leftTangent * leftSpeed; break;

                    case Direction.right: speed += rightTangent * rightSpeed; break;
                    }
                    direction = Direction.free;
                }
                else if (acceptRightNudge && rd)
                {
                    speed = (nudge * Time.deltaTime + 0.5f) * Vector2.right;
                    switch (direction)
                    {
                    case Direction.free: break;

                    case Direction.left: speed += leftTangent * leftSpeed; break;

                    case Direction.right: speed += rightTangent * rightSpeed; break;
                    }
                    direction = Direction.free;
                }
                else
                {
                    if (acceptRightWalk && goRight)
                    {
                        if (direction == Direction.left)
                        {
                            if (leftSpeed > 0.01f)
                            {
                                float delta = switchAcceleration * Time.deltaTime;

                                if (leftSpeed - delta > 0)
                                {
                                    leftSpeed -= delta;
                                }
                                else
                                {
                                    leftSpeed  = 0;
                                    rightSpeed = 0;
                                    direction  = Direction.right;
                                }
                            }
                            else
                            {
                                direction  = Direction.right;
                                rightSpeed = walkAcceleration * Time.deltaTime;
                            }
                        }
                        else if (rightSpeed < maxWalkSpeed)
                        {
                            direction   = Direction.right;
                            rightSpeed += walkAcceleration * Time.deltaTime;
                        }
                    }
                    else if (acceptLeftWalk && goLeft)
                    {
                        if (direction == Direction.right)
                        {
                            if (rightSpeed > 0.01f)
                            {
                                float delta = switchAcceleration * Time.deltaTime;

                                if (rightSpeed - delta > 0)
                                {
                                    rightSpeed -= delta;
                                }
                                else
                                {
                                    rightSpeed = 0;
                                    leftSpeed  = 0;
                                    direction  = Direction.left;
                                }
                            }
                            else
                            {
                                direction = Direction.left;
                                leftSpeed = walkAcceleration * Time.deltaTime;
                            }
                        }
                        else if (leftSpeed < maxWalkSpeed)
                        {
                            direction  = Direction.left;
                            leftSpeed += walkAcceleration * Time.deltaTime;
                        }
                    }
                    else if (acceptIdling)
                    {
                        if (direction == Direction.right)
                        {
                            float delta = idleAcceleration * Time.deltaTime;

                            if (rightSpeed - delta > 0)
                            {
                                rightSpeed -= delta;
                            }
                            else
                            {
                                rightSpeed = 0;
                            }
                        }
                        else
                        {
                            float delta = idleAcceleration * Time.deltaTime;

                            if (leftSpeed - delta > 0)
                            {
                                leftSpeed -= delta;
                            }
                            else
                            {
                                leftSpeed = 0;
                            }
                        }
                    }

                    if (applyWallGrav)
                    {
                        if (direction == Direction.right)
                        {
                            if (Vector2.Dot(Vector2.up, rightTangent) > 0)
                            {
                                rightSpeed += Vector2.Dot(gravity, rightTangent) * wallGravMultiplier * Time.deltaTime;
                                if (rightSpeed < 0)
                                {
                                    leftSpeed = -rightSpeed;
                                    direction = Direction.left;
                                }
                            }
                            else
                            {
                                rightSpeed += Vector2.Dot(gravity, rightTangent) * wallGravMultiplier * Time.deltaTime;
                            }
                        }
                        else
                        {
                            if (Vector2.Dot(Vector2.up, leftTangent) > 0)
                            {
                                leftSpeed += Vector2.Dot(gravity, leftTangent) * wallGravMultiplier * Time.deltaTime;
                                if (leftSpeed < 0)
                                {
                                    rightSpeed = -leftSpeed;
                                    direction  = Direction.right;
                                }
                            }
                            else
                            {
                                leftSpeed += Vector2.Dot(gravity, leftTangent) * wallGravMultiplier * Time.deltaTime;
                            }
                        }
                    }
                    if (applyDrag)
                    {
                        if (direction == Direction.right)
                        {
                            if (Vector2.Dot(-Vector2.up, rightTangent) > 0)
                            {
                                rightSpeed -= wallDrag * oldSpeedNorm * Time.deltaTime;
                                if (rightSpeed < 0)
                                {
                                    rightSpeed = 0;
                                }
                            }
                        }
                        else
                        {
                            if (Vector2.Dot(-Vector2.up, leftTangent) > 0)
                            {
                                leftSpeed -= wallDrag * oldSpeedNorm * Time.deltaTime;
                                if (leftSpeed < 0)
                                {
                                    leftSpeed = 0;
                                }
                            }
                        }
                    }
                }
            }
        }

        if (Input.GetMouseButton(0) && fuel > 0)
        {
            Vector2 rocketDirection = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
            float   distance        = Vector2.Distance(Camera.main.ScreenToWorldPoint(Input.mousePosition), transform.position);
            float   strength        = minRocketForce[rocketLevel] + (maxRocketForce[rocketLevel] - minRocketForce[rocketLevel]) * distance / rocketRadius;

            float force = Mathf.Min(strength, maxRocketForce[rocketLevel]) * Time.deltaTime;
            force = Mathf.Min(fuel / fuelPerForce, force);
            float projectedSpeed = Vector2.Dot(oldSpeed, rocketDirection.normalized);
            if (projectedSpeed < terminalRocketSpeed)
            {
                switch (direction)
                {
                case Direction.free:
                    speed += rocketDirection.normalized * force;
                    break;

                case Direction.right:
                    if (Vector2.Dot(rightTangent, rocketDirection) > 0 && Vector2.Dot(rightNormal, rocketDirection) < 0.1f)
                    {
                        rightSpeed += force;
                    }
                    else if (Vector2.Dot(leftTangent, rocketDirection) > 0 && Vector2.Dot(leftNormal, rocketDirection) < 0.1f)
                    {
                        rightSpeed -= force;
                        if (rightSpeed < 0)
                        {
                            leftSpeed = -rightSpeed;
                            direction = Direction.left;
                        }
                    }
                    else
                    {
                        speed     = rightSpeed * rightTangent + rocketDirection.normalized * force;
                        direction = Direction.free;
                    }
                    break;

                case Direction.left:
                    if (Vector2.Dot(rightTangent, rocketDirection) > 0 && Vector2.Dot(rightNormal, rocketDirection) < 0.1f)
                    {
                        leftSpeed -= force;
                        if (leftSpeed < 0)
                        {
                            rightSpeed = -leftSpeed;
                            direction  = Direction.right;
                        }
                    }
                    else if (Vector2.Dot(leftTangent, rocketDirection) > 0 && Vector2.Dot(leftNormal, rocketDirection) < 0.1f)
                    {
                        leftSpeed += force;
                    }
                    else
                    {
                        speed     = leftSpeed * leftTangent + rocketDirection.normalized * force;
                        direction = Direction.free;
                    }
                    break;
                }
                speed += rocketDirection.normalized * force;
            }
            fuel -= force * fuelPerForce;
        }

        if (direction == Direction.free && contactCount >= 1)
        {
            if (Vector2.Dot(speed, leftNormal) <= 0.005f && Vector2.Dot(speed, leftTangent) > 0)
            {
                direction = Direction.left;
                leftSpeed = Vector2.Dot(speed, leftTangent);
            }
            else if (Vector2.Dot(speed, rightNormal) <= 0.005f && Vector2.Dot(speed, rightTangent) > 0)
            {
                direction  = Direction.right;
                rightSpeed = Vector2.Dot(speed, rightTangent);
            }
        }

        Vector2 freeMovement  = speed * Time.deltaTime;
        float   leftMovement  = leftSpeed * Time.deltaTime;
        float   rightMovement = rightSpeed * Time.deltaTime;
        Vector2 tmp           = Vector2.zero;

        int a = 0;

        while (((contactCount == 0 && Vector2.Distance(speed, Vector2.zero) > 0.001f) ||
                (contactCount >= 1 && ((direction == Direction.left && leftMovement > 0.001f) ||
                                       (direction == Direction.right && rightMovement > 0.001f) ||
                                       (direction == Direction.free && Vector2.Distance(speed, Vector2.zero) > 0.001f)))) && a < 10)
        {
            Vector2 oldLeftTangent  = leftTangent;
            Vector2 oldRightTangent = rightTangent;

            Vector2 oldLeftNormal  = leftNormal;
            Vector2 oldRightNormal = rightNormal;

            rightGround = contactCount >= 1 && Vector2.Angle(rightNormal, Vector2.up) < groundAngle;
            leftGround  = contactCount >= 1 && Vector2.Angle(leftNormal, Vector2.up) < groundAngle;

            if (contactCount == 0)
            {
                tmp = motor.move(freeMovement);
            }
            if (contactCount >= 1)
            {
                if (direction == Direction.left)
                {
                    if (motor.isLeftContactEdge())
                    {
                        tmp = motor.move(leftMovement * leftTangent);
                    }
                    else
                    {
                        if (contactCount < 2 || leftMovement > 0.001f)
                        {
                            // when there are 2 contact, we want to avoid moving very little from that corner
                            tmp = motor.leftLineMove(leftMovement);
                        }
                    }
                }
                else if (direction == Direction.right)
                {
                    if (motor.isRightContactEdge())
                    {
                        tmp = motor.move(rightMovement * rightTangent);
                    }
                    else
                    {
                        if (contactCount < 2 || rightMovement > 0.001f)
                        {
                            tmp = motor.rightLineMove(rightMovement);
                        }
                    }
                }
                else
                {
                    tmp = motor.move(freeMovement);
                }
            }

            contactCount = motor.getContactCount();
            if (contactCount == 0)
            {
                switch (direction)
                {
                case Direction.free: break;

                case Direction.left:
                    speed = leftSpeed * leftTangent;
                    if (Vector2.Angle(Vector2.up, leftNormal) < groundAngle)
                    {
                        leaped     = true;
                        leapFrame  = 0;
                        leapNormal = leftNormal;
                    }
                    break;

                case Direction.right:
                    speed = rightSpeed * rightTangent;
                    if (Vector2.Angle(Vector2.up, leftNormal) < groundAngle)
                    {
                        leaped     = true;
                        leapFrame  = 0;
                        leapNormal = rightNormal;
                    }
                    break;
                }
                freeMovement = Vector2.zero;
                direction    = Direction.free;
            }
            else
            {
                leftTangent  = motor.getLeftTangent();
                rightTangent = motor.getRightTangent();

                leftNormal  = motor.getLeftNormal();
                rightNormal = motor.getRightNormal();

                if (tmp != Vector2.zero)
                {
                    if (Vector2.Angle(tmp, motor.getLeftTangent()) < Vector2.Angle(tmp, motor.getRightTangent()))
                    {
                        if (contactCount < 2 ||
                            (Vector2.Angle(leftTangent, rightTangent) > 110 &&
                             (stick ||
                              Vector2.Angle(leftNormal, Vector2.up) < groundAngle ||
                              !rightGround)) ||
                            Vector2.Angle(leftNormal, Vector2.up) < groundAngle)
                        {
                            switch (direction)
                            {
                            case Direction.free: leftSpeed = Vector2.Dot(speed, leftTangent); break;

                            case Direction.left: leftSpeed = Vector2.Dot(oldLeftTangent, leftTangent) * leftSpeed; break;

                            case Direction.right: leftSpeed = Vector2.Dot(rightSpeed * oldRightTangent, leftTangent); break;
                            }
                            leftMovement = Vector2.Dot(motor.getLeftTangent(), tmp);
                            direction    = Direction.left;
                        }
                        else
                        {
                            leftSpeed    = 0;
                            leftMovement = 0;
                            direction    = Direction.left;
                        }
                    }
                    else
                    {
                        if (contactCount < 2 ||
                            (Vector2.Angle(leftTangent, rightTangent) > 110 &&
                             (stick || Vector2.Angle(rightNormal, Vector2.up) < groundAngle ||
                              !leftGround)) ||
                            Vector2.Angle(rightNormal, Vector2.up) < groundAngle)
                        {
                            switch (direction)
                            {
                            case Direction.free: rightSpeed = Vector2.Dot(speed, rightTangent); break;

                            case Direction.left: rightSpeed = Vector2.Dot(leftSpeed * oldLeftTangent, leftTangent) * rightSpeed; break;

                            case Direction.right: rightSpeed = Vector2.Dot(oldRightTangent, rightTangent) * rightSpeed; break;
                            }
                            rightMovement = Vector2.Dot(motor.getRightTangent(), tmp);
                            direction     = Direction.right;
                        }
                        else
                        {
                            rightSpeed    = 0;
                            rightMovement = 0;
                            direction     = Direction.right;
                        }
                    }
                }
                else
                {
                    switch (direction)
                    {
                    case Direction.free:
                        if (Vector2.Angle(speed, motor.getLeftTangent()) < Vector2.Angle(speed, motor.getRightTangent()))
                        {
                            direction = Direction.left;
                            leftSpeed = Vector2.Dot(speed, motor.getLeftTangent());
                        }
                        else
                        {
                            direction  = Direction.right;
                            rightSpeed = Vector2.Dot(speed, motor.getRightTangent());
                        }
                        break;

                    case Direction.left: leftMovement = 0; break;

                    case Direction.right: rightMovement = 0; break;
                    }
                }
            }
            a++;
        }
    }