Jhon Piper
Jhon Piper

Reputation: 613

Rotate object in the direction it's moving in Unity

I have a 2D object that simply moves straight forward until it hit's another object, in which the physics material causes the object to bounce off the other object.

I'm not the best at drawing but here's an illustration of what I want it to do: (The arrow in the sphere represents what direction the sphere is currently facing)

enter image description here

enter image description here

I have the physics part of this down just fine, however the physics material does not rotate the gameobject so instead the actual result looks more like this:

enter image description here

I know you can set the rotation of the object pretty easily with transform, but how do you get the movement direction of the gameobject and then set the rotation to that direction?

Upvotes: 3

Views: 12745

Answers (4)

James Bond
James Bond

Reputation: 379

Manually rotating while physics are active may give you some wacky results, but here goes

public class FaceVelocity : MonoBehaviour
{
    private Rigidbody rigidBody;
    void Awake()
    {
        rigidBody = getComponent<RigidBody2D>();
    }
    //Apply rotation in late update to make sure it's not undone by physics
    void LateUpdate()
    {
        transform.right = rigidBody.velocity.normalized
    }
}

If your objects rotates while in contact with something (aka where it's most likely to) it may disort physics. It may be better to to use a parent object for physics and a child object for visuals.

public class FaceVelocity : MonoBehaviour
{
    private Rigidbody rigidBody;
    void Awake()
    {
        rigidBody = transform.parent.getComponent<RigidBody2D>();
    }
    //Apply rotation in late update to make sure it's not undone
    void LateUpdate()
    {
        transform.right = rigidBody.velocity.normalized
    }
}

Although to me it sounds like you don't even need rigidbodies and particle physics would be enough. If you do not use rigidbodies, calculate velocity direction yourself:

public class FaceVelocity : MonoBehaviour
    {
        private Vector3 prevPos;
        void Awake()
        {
            prevPos = transform.position;
        }
        //Apply rotation in late update to make sure it's not undone 
        void LateUpdate()
        {
            transform.right = (transform.position - prevpos).normalized
        }
    }

Upvotes: 1

VirendraV
VirendraV

Reputation: 81

I hope this script will help you

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Reflect : MonoBehaviour
{
//3d Project
    public int reflections;
    public float maxLenght;

    private Ray ray;
    private RaycastHit hit;
    private Vector3 direction;
    Vector3 pos;

    private void Awake()
    {

        reflections = 5;
        maxLenght = 200;
        pos = gameObject.transform.position;
        GetNextPoint(1);
    }

    private void Update()
    {
        if (Vector3.Distance(gameObject.transform.position, pos) >0.7f)
        {
            //move
            transform.position += transform.forward/10;
        }
        else
        {
            GetNextPoint(2);
        }

    }

    void GetNextPoint(int num)
    {
        ray = new Ray(transform.position, transform.forward);
        float remaningLength = maxLenght;
        int t = 0;
        for (int i = 0; i < reflections; i++)
        {
            if (Physics.Raycast(ray.origin, ray.direction, out hit, remaningLength))
            {
                ray = new Ray(hit.point, Vector3.Reflect(ray.direction, hit.normal));
                t++;
                if (t == num)
                {
                    gameObject.transform.LookAt(hit.point);
                    pos = hit.point;
                    break;
                }
            }
        }
    }
}

check thisand this

Upvotes: 1

Ruzihm
Ruzihm

Reputation: 20269

First, you need to know the local direction of the image should be pointing in the direction of movement. This depends on your setup and the question does not include enough information to know exactly. It's probably either Vector3.up or Vector3.right. Of course, the world direction is known from the velocity.

Vector3 worldDirectionToPointForward = rb2d.velocity.normalized;
Vector3 localDirectionToPointForward = Vector3.right;

Then, you want to rotate the sprite around the z axis so that the local direction points in that direction. You can use transform.TransformDirection to find the current direction the ball is "pointing" and then calculate the angle using Vector3.SignedAngle:

Vector3 currentWorldForwardDirection = transform.TransformDirection(
        localDirectionToPointForward);
float angleDiff = Vector3.SignedAngle(currentWorldForwardDirection, 
        worldDirectionToPointForward, Vector3.forward);

Then, rotate it by that amount around the z axis, using transform.Rotate.

transform.Rotate(Vector3.forward, angleDiff);

And I would do this after a collision with the wall. An alternative is to put it in LateUpdate, although that may interfere with other things occurring in LateUpdate in other monobehaviours. However, the LateUpdate method is easiest to demonstrate so I will do that here:

void LateUpdate()
{
    Vector3 worldDirectionToPointForward = rb2d.velocity.normalized;
    Vector3 localDirectionToPointForward = Vector3.right;

    Vector3 currentWorldForwardDirection = transform.TransformDirection(
            localDirectionToPointForward);
    float angleDiff = Vector3.SignedAngle(currentWorldForwardDirection, 
            worldDirectionToPointForward, Vector3.forward);

    transform.Rotate(Vector3.forward, angleDiff, Space.World);
}

Upvotes: 2

Mike Heggie
Mike Heggie

Reputation: 83

I can't test this at the moment but the following should work.

Vector3 prevPosition = Vector3.zero;

void Update()
{
    if(prevPosition != Vector3.zero)
    {
        Vector3 movementDir = transform.position - prevPosition;
        transform.rotation = Quaternion.LookRotation(movementDir, Vector3.Up);
    }
    prevPosition = transform.position;
}

All we are doing is comparing the objects position last frame with it's position this frame, subtracting those positions to get a vector, then rotating to face along that vector.

In the update method this is called every frame, no problem if you only have one ball, but if you've got thousands you might want to move into a method that is only called after a collision.

Upvotes: 1

Related Questions