So I must apologize for (A) having gotten distracted from the combat-system scripting by thinking about the details of sailboat physics, and (B) posting some stuff here that is really just for me, but I thought it might someday be useful to someone else to, and besides this was a handy place to jot it down.
There are an annoying number of ways to write down rotations and directions and things in LSL, and different parts of the word want different ones. (And this is just, for the moment, talking about rotations in two dimensions!)
For instance, llWind() returns a vector representing the wind direction. Wind is (I believe!) always flat (parallel to the ground) in SL, so we can ignore Z. But what exactly are X and Y?
Well, Rule 1 (which I always forget and have to try out again) is that X is East and Y is North. So if for instance I am standing at 117, 119, 117 in Hughes Rise, on the walkway in the Park, and I walk one meter due North, I’ll be at 117, 120, 117. See how Y got bigger? And if I walk one meter due West from there, toward the stairs, I’ll be at 116, 120, 117; X got smaller.
So if llWind returns < 5, 0, 0 > for instance, that means the wind is blowing at five meters per second toward the East (and therefore is called a West wind, ’cause winds are called by where they are coming from, just to be confusing).
Now say you have a sail, and you want to know the angle between the sail and the wind. Well, the sail’s trim is represented as a rotation, which can be represented in LSL either as an actual rotation object (which has four components, corresponding to the four components of the corresponding quaternion, where a quaternion is of course an element of a four-dimensional associative normed division algebra over the real numbers), which is mathematically wonderful but not too useful for actually thinking about, or as a three-element vector, each element representing a rotation about the corresponding axis.
So for instance if your sail is flat in the X dimension, it will be facing head-on to winds coming from the east or west. If you then rotate it ninety degrees (which is a rotation of pi/2, or PI_BY_TWO, in radians) about the Z axis (the up-and-down one), it will be facing head-on to winds coming from the north or south.
To represent a rotation of pi/2 radians as a vector in LSL, we write < 0, 0, PI_BY_TWO >. Now the fun part! If I know the X and Y parts of the wind speed from llWind, and I have the rotation of my sail as a rotation about the Z axis, how do I figure out the angle at which the wind is hitting my sail?
Now I pause to think and experiment a little, so as to have an answer to write down in the next paragraphs. :)
Well, first of all notice that by using a symmetrical sail and a rotation of pi/2, I’ve sort of cheated; in particular, I didn’t have to figure out whether rotations are clockwise or counterclockwise (anticlockwise). This is probably obvious to smart people of various kinds, but I can never remember it (some Right Hand Rule or something is probably involved) so I have done the experiment and will write down Rule 2: Rotations are counterclockwise, or, to be precise and therefore meaningful, if you’re looking down at something that is not rotated, and you rotate it positively about the Z axis, it moves around anticlockwise.
This surprised me. :)
It makes sense, though, if we think back to like Trig 101 or whatever that was; X is East (i.e. to the right on the map), and Y is North (upward on the map), which is just how the graphs were all done on the board, and if you start out with a line running from the origin to < 1,0 >, say, and “rotate it” by some small angle theta, it goes up a bit into th’ ol’ First Quadrant there, which means it’s moved anticlockwise.
(Whoever designed clocks must have skipped that class or something.)
So we can represent wind direction as a rotation-about-Z by drawing it on the board there using the X and Y that we got from llWind(), and straightforwardly figure out what angle we would have to rotate that origin-to-1,0 line through to get it there, and it turns out to be (unless I’m wrong) llAtan2(Y,X); that is, the angle whose tangent is y over x.
So we have two rotation amounts, the amount that our sail’s been rotated and the amount that the wind’s been “rotated”, and we can just subtract them from each other to get the angle between them. If they’ve been rotated the same, the difference is zero, and our sail is getting (basically) all of the benefit of the wind. If they are ninety degrees apart, the sail is edge-on to the wind, and getting no benefit at all. Because we suspect there is probably something trigonometric going on here, we will note that llCos(0) is 1.0, and llCos(PI/2) is 0.0, and decide that we can do, say:
vector wind = llWind(ZERO_VECTOR); // The wind right here
float windrotz = llAtan2(wind.y,wind.x);
vector sailrot = llRot2Euler(llGetLocalRot());
float sailrotz = sailrot.z;
float rot_difference = windrotz - sailrotz;
float wind_effect_on_sail = llCos(rot_difference);
and so wind_effect_on_sail will be 1 if the wind’s blowing right onto the sale, will be 0 if the wind is blowing edge-on onto the sail (luffing!), and will be inbetween in between. (It will also be negative, I think, if the wind is blowing on the wrong side of the sail, but I haven’t thought about that yet.)
And some similar calculation can be used to get the angle between the sail and the hull (or, really, the keel), to figure out how much of the wind’s effect on the sail then contributes to the forward motion of the boat. But that’s a little later. :)