So I am working on the 3D breakout.
Here's something that came as a pleasant surprise and felt like a real feat of genius, but doubtless someone else has thought of it before, so I want to find out what its called to learn more about it.
If you give an object an x, y, and z velocity, it can move in any direction. Pretty straightforward -- that's a simple vector. Now, if instead you just assign it a velocity, and then x y z values clamped 0.0 to 1.0 such that they total 1.0 (as absolute numbers), you can apply these to the velocity and do the same thing (if x is 0.5, and y -0.5, and z 0.0, it moves diagonally down to the right).
My first happy realization was that you can then bounce that object off any surface that extents straight along an axis (eg, all values in one of x y or z are the same, like the walls in a normal room), and all you have to do to get a perfect reflection is invert the appropriate value. Going with the object x=0.5, y=0.25, z=0.25, if it hits the ceiling, you just invert y to -0.25 -- its inertia in z and x do not change (is that real physics?) It reflects exactly like a tennis ball would, anyway.
So, that's nice (and a surprise, because in all the hundreds of pages on 3D programming I've read, this is never referred to). But what about surfaces that angle across all three dimensions? You could use a local coordinate system, but this is problematic. I wondered if there could be a simpler way.
I wanted to make it possible to tilt the paddle in x and y, so you could direct the ball up or down and to the sides (right now, it looks like a racket ball court). Fortunately, math is really hard for me so real trigonometry is a last resort.
Here's what I figured out: you assign the paddle a rotation, not in degrees, not in radians, but where 1.0 = 45 degrees, and you use that as an adjustment. Here "obj" refers to the ball and "Pad" to the paddle, ie, the angled surface; the obj "R" values are the velocity modifiers I mentioned:
Code:
if ( ball has hit paddle ) {
hit = 1;
/* horizontal tilt */
if (Pad.yR > 0.0f) { /* left */
obj->xR = Pad.yR - fabsf(obj->xR);
} else { /* right or straight */
obj->xR += Pad.yR;
}
/* vertical tilt */
if (Pad.xR > 0.0f) { /* up */
obj->yR = Pad.xR - fabsf(obj->yR);
} else { /* down */
obj->yR += Pad.xR;
}
if ((obj->xR > 1.01f) || (obj->xR < -1.01f) ||
(obj->yR < -1.01f) || (obj->yR > 1.01f)) {
Those values indicate contact with the surface
would have been impossible, OR that the angle of
reflection would be back so:
hit = 0;
}
}
if (hit) obj->zR = 1.0 - (fabsf(obj->xR) + fabsf(obj->yR));
The last line just makes the z value the balance after x and y are calculated. z is also inverted.
Now, this is pretty cool because 1) it totally works, 2) there's no trig, vectors, or dot products involved.
Of course, applying this to other circumstances may not be so easy -- that last condition is significant, because those angles are in error (but it doesn't matter, the ball is out).
I have done some googling and there is amazingly little to be found about simple "vector reflection", etc, and this is not really it. But some other people must use a system like this and have hopefully figured out a way to make it more generally applicable.
Anyone know? Any thoughts, comments, questions? In case it does not make sense, here's the line in red again:
obj->xR = Pad.yR - fabsf(obj->xR); [edited]
So if the object was travelling dead staight on z (so yR = 0.0, zR = 1.0) and hit the paddle angled 45 degrees left (-1.0), it's new yR value would be -1.0, and so the balance (zR) would be 0.0. These modify the velocity in each dimension, so now instead of moving straight on z, it moves straight on y.
I may post all the code for this here tomorrow for other reasons, but I have been playing with it and tweaking stuff half the day -- it looks totally real.
ps. if you are so smart and gracious as to identify a flaw in the code there that'd be great too...