Revisiting setting rotation from a specific course

(Nolan) #1

Hey folks. I’ve been working on my audio game for a while and making good progress, but sometimes it feels like one step forward and half a dozen back. In particular, I’ve just implemented a radar that plays a sound at the hit point between a ray along the player’s direction of travel and the edge of the field. Nice stuff, but as I invent better ways of seeing the game world through sound, I start to realize that maybe some of my earlier assumptions were flawed.

In particular, I’m trying to implement simplified motion. Players can set a course between 0 and PI*2, which is then converted back to degrees for display. My understanding was that the courses in radians should be the source of truth, then synced back to the underlying transforms. And that seemed to work, in that I can set a course and get motion along the correct axis. But if I sit at 0,0,0, place a sound at 0,0,-150, and spin around the Y axis, the sound’s motion isn’t circular. It feels choppy and uneven. This makes me wonder if I’m syncing my angles to my transforms incorrectly.

I’ll include code below, but it occurs to me that I might be getting the ranges of euler angles wrong. I only care about rotation around Y for now. I assumed the range was 0 to PI*2 radians, but it occurs to me that it might be -PI to +PI, or something else entirely.

Here’s my code. First my Course component which syncs an angle around Y in radians to the transform. I have other angles too, since I’ll eventually want 3-D motion but am starting out 2-D:

#[derive(Default, Deserialize, Serialize)]
struct Course(f32, f32, f32);

impl Component for Course {
    type Storage = DenseVecStorage<Self>;
}

struct CourseSystem;

impl<'s> System<'s> for CourseSystem {
    type SystemData = (WriteStorage<'s, Course>, WriteStorage<'s, Transform>);

    fn run(&mut self, (mut courses, mut transforms): Self::SystemData) {
        for (course, transform) in (&mut courses, &mut transforms).join() {
            while course.1 < 0. {
                course.1 += consts::PI * 2.;
            }
            while course.1 >= consts::PI * 2. {
                course.1 -= consts::PI * 2.;
            }
            transform.set_rotation_euler(course.0, course.1, course.2);
        }
    }
}

Then this set of actions to update my course. There are commands to snap the course to the nearest cardinal direction, but I’m not using those to diagnose this so don’t mind the snap stuff:

            if input_handler.action_is_down("rotate_left").unwrap()
                && !should_snap_left
                && !should_snap_right
            {
                course.1 += delta * config.player_rotation_rate;
            }
            if input_handler.action_is_down("rotate_right").unwrap()
                && !should_snap_left
                && !should_snap_right
            {
                course.1 -= delta * config.player_rotation_rate;
            }

And to the extent that the component updates, the values look OK. Pressing left-arrow may set my course to 32 degrees, another short press to 67, another to 103, and so on until I pass 360 and return to 0. The rotation rate seems fine too. The issue seems to be the actual sync of these angles to the transform.

I also added a info!("Current euler: {:?}", transform.euler_angles()); to the system, and it does seem like the range may not be 0-2*PI. It also seems like the X and Z rotations flip:

[INFO][onslaught] Current euler: (3.1415927, -0.00000008742278, 3.1415927)

That’s for a course of 180 degrees. I understand that rotations don’t tend to combine well, which is what I thought the point of explicitly setting them was. I’m also never setting the X and Z eulers to anything other than 0.

Any thoughts on what might be going on here? I understand audio positioning isn’t a perfect science, but I don’t think that can explain the amount of jitter I’m getting. Should I split my course system/component into something like a Yaw component/system that only sets a single rotation value, and if so, how would I update just that value without causing the jitter I seem to get now?

1 Like