Complete Unity C# Lecture 77 - Unexpected translation

I’m not sure what is going on, but because my player object was already pointing so that left and right movement was on the Z-axis. I had already done a large portion of animation and decided to try to do the Vector3 movement using a zOffset. This created weird behaviour where object position wasn’t updating but eventually I got it to move with left and right inputs.
Now whenever I try to do y-axis movement in the same manner adding ‘+=’ transform.localPosition , the player object vanishes out of bounds immediately.

If I’m getting left and right movement using '+= ’ then up and down movement doesn’t register.
Any ideas what’s going on here? Thanks

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] float controlSpeed = 100f;
    
    Vector3 movement;
    // Update is called once per frame
    void Update()
    {
        ProcessTranslationZ();
        ProcessTranslationY();
    }

    void ProcessTranslationZ()
    {
        float xOffset = movement.x * controlSpeed * Time.deltaTime;
        transform.localPosition += new Vector3(0f, 0f, -(transform.localPosition.x + xOffset));
    }

    void ProcessTranslationY()
    {
        float yOffset = movement.y * controlSpeed * Time.deltaTime;
        transform.localPosition = new Vector3(0f, transform.localPosition.y + yOffset, 0f);
    }    

    public void OnMovement(InputValue value) 
    {
        Debug.Log(movement);
        movement = value.Get<Vector2>();

    }
}

You are not using += on the y-translation but =. This means you are completely removing any change you added on the z-axis because you are setting z to 0 on every frame.

Also, you are setting the z-axis equal to the x-axis value plus offset, but the x-axis value will always be 0 so you are always adding only offset to the z-axis. However, on the y-axis you are adding the value of the y-axis + up to 50 units per second. So, if the y-axis is 1000, then next frame it will be set to 2000 (assume offset = 0 - no movement). And the next frame would be 4000, then 8000, etc. It will quickly go out of bounds. According to ChatGPT (because I am too lazy to try and calculate it myself) at 60fps you will go from 1,000 to 1,152,921,504,606,846,976 in 1 second. You should probably only += the offset on both z- and y-axes

    void ProcessTranslationZ()
    {
        float xOffset = movement.x * controlSpeed * Time.deltaTime;
        transform.localPosition += new Vector3(0f, 0f, -xOffset);
    }

    void ProcessTranslationY()
    {
        float yOffset = movement.y * controlSpeed * Time.deltaTime;
        transform.localPosition += new Vector3(0f, yOffset, 0f);
    }    

You could also combine them into

    void ProcessTranslation()
    {
        Vector3 Offset = new Vector3(0f, movement.y, movement.x) * controlSpeed * Time.deltaTime;
        transform.localPosition += Offset;
    }

Or beter even, translate it

    void ProcessTranslation()
    {
        Vector3 Offset = new Vector3(0f, movement.y, movement.x) * controlSpeed * Time.deltaTime;
        transform.Translate(Offset);
    }

Thanks! This makes sense why the movement seemed to be constantly resetting the value because of how I assigned the new Vector3 to the transform.localPosition.

Now I’m wondering how would I go about using mathf.Clamp to limit the movement range? Would it go in the parameters of the Vector3 Offset?

Unless I misunderstood your idea, you want to define the min and max position values, not the offset. If that’s right, you want to get a value x within a range [a, b]. Mathf.Clamp returns that value. If you want to get values in that range for your position, you’d do something like that:

transform.localPosition = new Vector3(
    0f,
    Mathf.Clamp(transform.localPosition.y, a, b),
    0f
);

where a and b are your min and max values for the second argument, which then gets used as the new local y-position value.

Alternatively:

float yPos = Mathf.Clamp(transform.localPosition.y, a, b);
transform.localPosition = new Vector3(0f, yPos, 0f);

Hey Nina,

So I just tried this code and then lost all movement and input.
I’ve been stuck on section 4 ( Galaxy Strike) and haven’t been able to progress because I started with my player gameobject facing in the Z-axis.
So where, x-axis movement should be normally on the x-axis, to do left and right movement with the ship, I had to put the add movement.x to the z-axis parameter in the Vector3 offset.

And in order to get movement working for both up and down(y-axis) and left and right(z-axis) I had to use bixarrio’s solution. Now this means that using Mathf.Clamp as shown in lecture 78. Doesn’t work as expected.

Here is my code:

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] float controlSpeed = 10f;
    [SerializeField] float xClampRange = 5f;
 
    Vector2 movement;
    // Update is called once per frame
    void Update()
    {
        ProcessTranslation();
    }

    public void OnMovement(InputValue value) 
    {
        Debug.Log(movement);
        movement = value.Get<Vector2>();

    }

    void ProcessTranslation()
    {
        Vector3 Offset = new Vector3(0f, movement.y, 
        Mathf.Clamp(movement.x, -xClampRange, xClampRange)) * 
        controlSpeed * Time.deltaTime;
        transform.Translate(Offset);
    }
}

My option to use transform.Translate is what’s causing your confusion. Just move one option back

    void ProcessTranslation()
    {
        Vector3 Offset = new Vector3(0f, movement.y, movement.x) * controlSpeed * Time.deltaTime;
        transform.localPosition += Offset;
    }

This code is more closely resembles the course’s code and you can work from there. It’s here that you now want to clamp the offset values. At the end of this lecture your code should look like this

    void ProcessTranslation()
    {
        float xOffset = movement.x * controlSpeed * Time.deltaTime; // this is for the z-offset
        float rawXPos = transform.localPosition.z + xOffset; // notice the z position here
        float clampedXPos = Mathf.Clamp(rawXPos, -xClampRange, xClampRange);

        float yOffset = movement.y * controlSpeed * Time.deltaTime;
        float rawYPos = transform.localPosition.y + yOffset;
        float clampedYPos = Mathf.Clamp(rawYPos, -yClampRange, yClampRange);

        transform.localPosition = new Vector3(0f, clampedYPos, clampedXPos); // set the y and z local position
    }

All you are really doing is moving everything that should go to x, to z.

You should really change all the variables to use z instead of x (except for movement.x). I didn’t do it here because it may confuse you through the rest of the course, but it may also confuse you later if it says x, but it’s really z. This is the code with all the variables set to indicate z

    // at the top
    [SerializeField] float zClampRange = 5f;
    [SerializeField] float yClampRange = 5f;

    void ProcessTranslation()
    {
        float zOffset = movement.x * controlSpeed * Time.deltaTime;
        float rawZPos = transform.localPosition.z + zOffset;
        float clampedZPos = Mathf.Clamp(rawZPos, -zClampRange, zClampRange);

        float yOffset = movement.y * controlSpeed * Time.deltaTime;
        float rawYPos = transform.localPosition.y + yOffset;
        float clampedYPos = Mathf.Clamp(rawYPos, -yClampRange, yClampRange);

        transform.localPosition = new Vector3(0f, clampedYPos, clampedZPos);
    }

Don’t change this if it’s going to confuse you. It’s just not good for something to say it’s doing something for x when it’s really doing it for z.

1 Like

Since bixarrio shared a detailled solution, I just want to mention: The Translate method adds a value to the transform.position. The value is defined by the argument, in your case, the value of Offset. However, Offset does not depend on the position, and there is nothing that restricts the position.

In bixarrio’s solution, you can see that the localPosition gets set with specific values. And those specific values are calculated and clamped.

When using other people’s methods (here: Translate), we have to be very careful because those methods do not always give us the expected result. For this reason, it is often a good idea to use the basics of programming to keep the control as long as possible. In the case of bixarrio’s solution, the basics are: We define an object with “our” values, we assign the object. The next step is to use, for example, Mathf.Clamp. This allows us to debug each line to identify problems fast.

Don’t hesitate to use more variables. Our modern devices have plenty of memory. :slight_smile:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms