Valerie Valerie - 6 days ago 10
C# Question

How do I rotate an object to a specific position around another object? (Essentially orbiting to specified position)

I have a planet and a moon. The moon is parented to a dummy object, which is located at the center of the planet (essentially 0,0,0). The moon is free to rotate around (to any position on) the planet. It should maintain a constant distance from the planet.

I have a specific point in mind that I want to rotate the moon to, though it needs to stay upright. That is, the moon should consistently point "up" relative to the planet's surface. Basically it's like a "moveTo" script only in my case the moon should "rotate" around the planet until it reaches the point I'm looking for.

Here's what I have so far, though I can't work out the correct logic to use:

Vector3 targetDir = moveToPos - moon.transform.position;

float angle = Vector3.Angle( targetDir, moon.transform.up );

dummy.transform.RotateAround (moveToPos, moon.transform.up, angle);


Am I thinking of this correctly? Once I get this working, I'd like to feed the moon different
Vector3
positions and have the moon rotate to them on the surface of the planet. I have searched for something similar but can't find what I'm looking for.

The marker displayed in this screenshot should say "Rotate here", but this is essentially what my scene looks like:

Marker shows where the moon should be moved

enter image description here

Answer

You've already made things a lot easier by nesting your moon inside an empty transform. If it's properly set up*, this means you won't have to directly manipulate the moon's transform - you just need to rotate the container object until it faces the target position.

*By this, I mean the container object is at (0, 0, 0) relative to the planet, and the moon is only locally translated along the z-axis so it lines up with the container's transform.forward vector.

The problem is easier to approach if we break it down into smaller steps:

  • Determining the target direction the container needs to face. We can get this by just subtracting the container's position from the target position.
  • Calculating the required rotation for the container to face the target direction. This is a good place for Quaternion.LookRotation().
  • Rotating the container until its direction matches the target direction. Quaternion.Lerp() can be used to achieve this.

Here's how you might implement these steps:

Quaternion targetRotation;
Quaternion startRotation;
float progress = 1;

void SetTargetPosition(Vector3 position)
{
    // Calculating the target direction
    Vector3 targetDir = position - dummy.transform.position;

    // Calculating the target rotation for the container, based on the target direction
    targetRotation = Quaternion.LookRotation(targetDir);
    startRotation = dummy.transform.rotation;

    // Signal the rotation to start
    progress = 0;
}

void Update()
{
    if (progress < 1)
    {
        // If a rotation is occurring, increment the progress according to time
        progress += Time.deltaTime;

        // Then, use the progress to determine the container's current rotation
        dummy.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
    }
}

Note: If the moon is rotating too quickly (it will currently complete the rotation in ~1 second), just add less to progress every frame, eg. Divide it by a factor.

As long as the container is centered in the planet, the moon should remain a constant distance away from the surface at all times, and by this method will always keep a consistent "up" direction relative to the planet's surface.

Hope this helps! Let me know if you have any questions.