1
\$\begingroup\$

I'm trying to limit my movement in the y-axis by checking if the position will be within the boundaries after the Translate. If it is, only then do I translate the Player.

public class Player : MonoBehaviour {

    private float speed = 5.0f;
    private float bottomY = -4.37f;

    void Start () {
        transform.position = new Vector3(0, -4, 0);
    }

    void Update () {
        Movement();
    }

    void Movement () {
        // vertical movement
        Vector3 yTranslateVector = Vector3.up * Input.GetAxis("Vertical") * speed * Time.deltaTime;
        float newYPos = (transform.position + yTranslateVector).y;
        if (newYPos > bottomY && newYPos < 0) {
            transform.Translate(yTranslateVector);
        }

        // horizontal movement
        Vector3 xTranslateVector = Vector3.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime;
        transform.Translate(xTranslateVector);
    }
}

However, when I do this, the Player kind of pauses when approaching the boundary and then stutters forward towards the absolute limit upon releasing the key. I tried putting the Movement function in the Update and FixedUpdate method, but neither made any difference. Can anyone give me any insight into this?

\$\endgroup\$
3
\$\begingroup\$

Instead of cancelling the movement outright when we near the boundary, we can instead shorten our movement to reach the boundary without overshooting.

Vector2 input = new Vector2(
       Input.GetAxis("Horizontal"), 
       Input.GetAxis("Vertical"));

// Optionally, clamp input to a disc so you don't move faster diagonally.
if(input.sqrMagnitude > 1f)
    Vector2.Normalize(input);

// Compute where we want to be after we take or full movement.
Vector3 step = input * speed * Time.deltaTime;    
Vector3 destination = transform.position + step;

// Clamp the y so we don't go lower than min or higher than max.
destination.y = Mathf.Clamp(destination.y, minY, maxY);

// Move to the clamped position.
transform.position = destination;

Note that in this form, if we approach the boundary diagonally, our y movement will get cut short but we'll still take our full x movement - like we hit the wall and then slid along it. Sometimes this can feel less abrupt than hitting the wall and stopping, but it does change the net direction of movement to a shallower angle than the player had input. If you prefer to stop at the first intersection with the boundary, we can do it like this:

// Compute how far we've exceeded our bounds vertically.
float outOfBounds = Mathf.Max(destination.y - maxY, minY - destination.Y);

if(outOfBounds > 0f) {
    // Calculate the fraction of our move that was in-bounds.
    float absY = Mathf.Abs(step.y);
    float inBoundsFraction = (absY - outOfBounds)/absY;

    // Shorten our step to just that in-bounds fraction,
    // scaling evenly on both axes.
    destination = transform.position + step * inBoundsFraction;
}
\$\endgroup\$
  • \$\begingroup\$ Awesome - this seems to be everything I need and more. Just wanted to clarify what clamping input to a disc means though. \$\endgroup\$ – Kevin Apr 4 '18 at 14:03
  • 1
    \$\begingroup\$ @Kevin if x and y inputs can each vary between -1 and 1, then the set of (x, y) points you can get as input forms a square. The corners of a square are further from the center than the edges are. If your input device lets you push both x & y to the limit at once (eg. keyboard keys rather than an analog stick) say (1, 1), your input vector is ~41% longer than if you pushed right (1, 0). If we do nothing, that means diagonal movement is faster than moving along cardinal directions. To fix it, we can limit the vector to a circle around the origin, so the max length is the same in every direction. \$\endgroup\$ – DMGregory Apr 5 '18 at 1:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.