0
\$\begingroup\$

Here is a little background on how my game objects are set up, and how the rotations and firing bullets work. I am working on this game in Unity.

I have two game objects that orbit a sphere (for simplicity lets say the player is a space ship and the enemy is a UFO). The UFO shoots at the ship in a spherical manner around the surface of the sphere (my intention at least).

The ship and UFO both have a parent game object that is located at the center of the sphere, and each are moved back on the z-axis by 10 units. All of the movement rotations are applied to the parent pivot points which causes the two objects to orbit freely in any direction as the pivot points rotate.

In this previous question I received some help to get my bullets to fire from the UFO towards the ship. The solution provided works great, the UFO always fires bullets towards the ship as the ship flies around. Once both objects move to opposite side of the sphere (past 180 degrees from the original starting point) the direction to fire the bullet seems mirrored. As the ship flies around the, the bullets fly in a mirrored direction.

Here is how I am rotating the bullets (note: I use the same pivot point technique as stated above for the bullets as well):

When shooting a bullet I first I generate a direction vector like so:

var ufoSpoke = ufo.transform.position - Vector3.zero;
var shipSpoke = ship.transform.position - Vector3.zero;
var pointOut = Quaternion.LookRotation(ufoSpoke, -shipSpoke);
var pointOnShortestArc = pointOut * Quaternion.Euler(90f, 0, 0);
var direction = (pointOnShortestArc * Vector3.right).normalized * 50f;

Now within the update method for the bullet pivot point, I rotate the pivot object in this direction:

transform.Rotate(direction.y * Time.deltaTime, -direction.x * Time.deltaTime, 0f);

This all is working great, until the ship and UFO start moving around the sphere. Eventually the calculated bullet direction goes from just slightly off, to mirrored once on the backside of the sphere... If I fly the ship back to the original starting point, the bullet direction comes back properly.

Not quite sure what the issue seems to be, and I've admittedly been looking at this far too long haha. Thanks in advance for any help on this!

\$\endgroup\$
  • 1
    \$\begingroup\$ There's your problem. Transform.Rotate rotates the object in Euler angles. That's not remotely the same thing as rotating about the axis specified by the direction vector. (In general, you should be wary about doing any kind of dynamic calculation with Euler angles — the majority of the time, they don't give the behaviour you want). I'll type up an alternative once I'm back at my keyboard. \$\endgroup\$ – DMGregory Dec 30 '17 at 17:36
  • \$\begingroup\$ Ah, yeah I have fought this sort of battle a few times with other issues along the way. Good to know that's what is causing it. \$\endgroup\$ – DRiFTy Dec 30 '17 at 17:42
1
\$\begingroup\$

transform.Rotate(x, y, z) rotates in local Euler angles. That means it applies a rotation of y degrees about the local y+ axis, then x degrees about the (resulting) local x+ axis, and finally z degrees about the (resulting) local z+ axis. It might look similar to rotating about the vector (x, y, z) for infinitesimal angles, but the compounding effects of each rotation changing the axes of the others can lead it to wander in unintuitive ways.

For this reason, I recommend using Euler angles in only two situations:

  • you want to serialize an orientation to a human-readable format for storage/manual editing, or deserialize such a rotation and then work with it in some other format

  • you're working in a latitude/longitude system, like a camera controller, where you control each axis completely, and don't have feedback of rotations compounding frame over frame

For most other situations, Quaternion, Matrix, or Angle-Axis representations tend to have more intuitive behaviour.

So we can use this overload instead:

transform.Rotate(
     direction,        // rotation axis
     degreesPerSecond * time.DeltaTime, // angle
     Space.World       // global coordinates
);

This ensures we're actually rotating about the axis we want.

(And you don't need to normalize the direction — Vector3.right is already a unit vector, and rotating it doesn't change its length — or scale it by 50. All we need from it is a direction)

\$\endgroup\$

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.