1
\$\begingroup\$

I can't figure out why my object can't move and turn at the same time.

    public float moveSpeed;
private Vector3 rotationSpeed;
public Camera cam;

public Vector3 straightForward;

public Quaternion spreadAngleRight;
public Quaternion spreadAngleLeft;

public Vector3 localRightVector;
public Vector3 localLeftVector;

public Vector3 newVectorRight;
public Vector3 newVectorLeft;

private Rigidbody rb;

Vector3 movement;
void Start () {
    rb = gameObject.GetComponent<Rigidbody> ();
    rotationSpeed = new Vector3(0, 100, 0);

    straightForward = transform.TransformDirection (Vector3.forward);

    spreadAngleRight = Quaternion.AngleAxis (45, new Vector3 (0, 1, 0));
    spreadAngleLeft = Quaternion.AngleAxis (315, new Vector3 (0, 1, 0));

    localRightVector = spreadAngleRight * straightForward;
    localLeftVector = spreadAngleLeft * straightForward;

    newVectorRight = transform.TransformDirection (localRightVector);
    newVectorLeft = transform.TransformDirection (localLeftVector);
}

// Update is called once per frame
void Update () {

    #region Control
    if(Input.GetKey(KeyCode.W)){
        rb.MovePosition(transform.position + transform.TransformDirection(Vector3.forward * moveSpeed) * Time.deltaTime);
    }
    if (Input.GetKey (KeyCode.A)) {
        rb.MovePosition(transform.position + transform.TransformDirection(-Vector3.right * moveSpeed) * Time.deltaTime);        
    }
    if (Input.GetKey (KeyCode.S)) {
        rb.MovePosition(transform.position + transform.TransformDirection(-Vector3.forward * moveSpeed) * Time.deltaTime);      
    }
    if (Input.GetKey (KeyCode.D)) {
        rb.MovePosition(transform.position + transform.TransformDirection(Vector3.right * moveSpeed) * Time.deltaTime);     
    } 
    if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.D)){
        rb.MovePosition(transform.position + transform.TransformDirection(newVectorRight * moveSpeed) * Time.deltaTime);
    }
    if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A)){
        rb.MovePosition(transform.position + transform.TransformDirection(newVectorLeft * moveSpeed) * Time.deltaTime);
    }
    if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.D)){
        rb.MovePosition(transform.position - transform.TransformDirection(newVectorLeft * moveSpeed) * Time.deltaTime);
    }
    if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.A)){
        rb.MovePosition(transform.position - transform.TransformDirection(newVectorRight * moveSpeed) * Time.deltaTime);
    }
    Vector3 mouseInputX = Input.GetAxis ("Mouse X") * rotationSpeed;
    Vector3 mouseInputY = Input.GetAxis ("Mouse Y") * rotationSpeed;

    gameObject.transform.Rotate (mouseInputX * Time.deltaTime, Space.Self);
    cam.transform.LookAt(gameObject.transform.position + Vector3.up * 2f);

    #endregion
}
\$\endgroup\$
4
  • \$\begingroup\$ What does the Rigidbody GameObject does instead? if it is the rotation, I suggest you to debug the Mouse X's vector to see if it is changing at all, because the movement seems to be ok. \$\endgroup\$ Mar 20, 2018 at 17:46
  • \$\begingroup\$ The problem is, that if I move, for example with W and then start rotating with Mouse Y, the movement will stop until rotation is complete. \$\endgroup\$ Mar 20, 2018 at 19:58
  • \$\begingroup\$ @DavidDonovan try transform.forward and transform.right instead of TransformDirection() \$\endgroup\$ Mar 20, 2018 at 21:42
  • \$\begingroup\$ And I would suggest using Quaternions when working with rotations. See Gimbal Lock - en.wikipedia.org/wiki/Gimbal_lock \$\endgroup\$ Mar 20, 2018 at 21:46

3 Answers 3

2
\$\begingroup\$

Transform.Rotate is used for transforms (I know, excuse the redundancy). If you are already displacing with Rigidbody, then use Rigidbody.MoveRotation (it takes a quaternion as parameter). Example:

public Vector3 rotationVelocity;

void Update()
{
    Quaternion deltaRotation = Quaternion.Euler(rotationVelocity * Time.deltaTime);
    rb.MoveRotation(rb.rotation * deltaRotation)
}
\$\endgroup\$
2
  • \$\begingroup\$ Won't change anything, it will just rotate considering collisions and at fixed update. \$\endgroup\$ Mar 20, 2018 at 21:44
  • \$\begingroup\$ @CandidMoon keeping the motion under the rigidbody's control also ensures the rotation won't disable interpolation, which is useful. :) \$\endgroup\$
    – DMGregory
    Mar 20, 2018 at 23:46
0
\$\begingroup\$

If you're using rigidbody for movement you should also use rigidbody for rotation. Note that transform.Rotate acts on the Transform component, which is present in every Unity's GameObject.

To rotate a Rigidbody, i.e. a GameObject with a Rigidbody component attached, you should probably use rb.MoveRotation, which will use the interpolation setting of your component.

However, if you do want to rotate using Transform and want your character to move always forwards, in the direction it is looking at, there's a simpler solution that should work just fine:

if(Input.GetKey(KeyCode.D)){
    //Rotate to the right (D), for example 
    transform.rotation = Quaternion.LookRotation(transform.right);
    //Move always to the forward vector
    rb.MovePosition(transform.position + transform.forward * speed);
}

Now just use transform.right - 1 to rotate to left (A), transform.forward (W) to rotate to forward and transform.forward - 1 to rotate to back (S).

This will ensure you can rotate to any position and keep moving forward relative to this rotation.

You may asking how you would rotate between W and D for example, and this is simple, just sum up the vectors:

//If pressing W and D:    
transform.rotation = Quaternion.LookRotation(transform.right + transform.forward)

And so on with W + A (transform.forward + (-transform.right)), S + D (transform.forward + transform.right), S + A (-transform.forward + (-transform.right)).

(I don't tested this code but it should work just fine)


I may have misunderstood what you're trying to achieve. You're trying to make your player rotate with mouse and move always forward relative to that rotation? In this case, try:

//Get rotation from mouse and set to object's rotation:
transform.Rotate (mouseInputX * Time.deltaTime, Space.Self);
//if pressing forward
if(Input.GetKey(KeyCode.W)){
    rb.MovePosition(transform.position + (transform.forward * speed));
}
//if pressing right, for example
else if (Input.GetKey(KeyCode.D)){
    rb.MovePosition(transform.position + (transform.right * speed));
}

And do this for all key presses and sum the vectors as I explained before for when you press two buttons at the same time:

//If pressing W and D:    
rb.MovePosition(transform.position (transform.right + transform.forward * speed));

This should do the trick, although I'm not sure you're using the best method to rotate acording to mouse position. Maybe take the mouse position and use LookAt, for example.

\$\endgroup\$
0
\$\begingroup\$

Not sure if you found the answer, but I had the same problem and found out that the rotating item must be Dynamic for this to work, and of course with Gravity and mass all set to nothing. You also need to manually move its position each update to pin it back onto the player.

In my scenario, I had a a Dynamic player (Parent) using Velocity to move, which had a Childed object (Aimer) programmed to track the position of the mouse cursor. In LateUpdate, right before the physics engine did its calcs, it was told to moveposition to stick onto the Player. Now here's the problem.

If it was set to Dynamic it would rotate fine but either stay fixed in its original XY position on the screen(basicaly, it didnt follow anybodys Physics but its own) or even be affected by gravity and fall out of the map!

If the object was set to Static it would just lock its position and stay on the map at its starting location with an error message saying it couldn't be given these type of orders.

If it was set to Kinematic it would stick to the Parent with no problems, but NOT continue to be Childed while physics calculations were going on, so it would "freeze" during player movement and "teleport" into its correct position after movement had halted. Enabling the Aimer to be dynamic meant it could be pushed around with the same physics (velocity / addforce).

In the end I had to use Dynamic aimer with Physics enabled in order to get the free rotation in realtime while the Parent was also experiencing physics, and then I added script to manually pin the Aimer to the same coordinates as the player, every LateUpdate.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .