You had me scaredfrag.machine wrote:AFAIK you cannot have bobbing platforms with just vanilla QuakeC.
Well, actually it is smoothLardarse wrote:You can make them bob, but they won't be that smooth. Basic idea is that the platform nextthinks a lot to adjust velocity.
That was a difficult challenge at first, actually. In the end, it was just math and timing. Kind of ironic, since this is the first QuakeC I've ever truly wrote myself.Lardarse wrote:Not sure how you make sure it stops at exactly the correct top/bottom points every time, though.
----
Getting to the tutorial
I was rather worried that it couldn't be done in vanilla QuakeC or that it would suck or be jerky. It isn't. It always wasn't easy. FrikaC's mathlib sin function wasn't giving me the right values (could be user error somehow, but I couldn't get it to work) and this almost presented an insurmountable obstacle. I wanted to have base QuakeC functionality and was about ready to add the DP SIN engine extension, which would make the usefulness of bobbing platforms rather engine-locked. Then I realized I could fake the sin function with a table of 91 values.
Changed files: Just misc.qc
Instructions:
Locate the void func_wall () function in misc.qc. Replace it with this. The END.
Code: Select all
float pi = 3.14159265;
//START - Baker mod
.vector orbitorigin;
.float nextangle;
// For calculating speed to reach next destination point in our
// Circlish thing
.float sinresult;
.float orbitrelative;
.vector targetspot;
.float targetdistance;
.float lastthink;
// END - Baker mod
// Baker: Sad to report, but mathlib's sin function doesn't actually work (or at least I could find no evidence
// that it does --- it gave me values, but they weren't correct, but could be user error on my part. In fact, go with possible user error as the default assumption)
// So we fake it with a table. This limits us to integer values.
float(float x) sin_angle_pi =
{
if (x== 0) return 0;
else if (x== 1) return .035;
else if (x== 2) return .07;
else if (x== 3) return .105;
else if (x== 4) return .139;
else if (x== 5) return .174;
else if (x== 6) return .208;
else if (x== 7) return .242;
else if (x== 8) return .276;
else if (x== 9) return .309;
else if (x== 10) return .342;
else if (x== 11) return .375;
else if (x== 12) return .407;
else if (x== 13) return .438;
else if (x== 14) return .469;
else if (x== 15) return .5;
else if (x== 16) return .53;
else if (x== 17) return .559;
else if (x== 18) return .588;
else if (x== 19) return .616;
else if (x== 20) return .643;
else if (x== 21) return .669;
else if (x== 22) return .695;
else if (x== 23) return .719;
else if (x== 24) return .743;
else if (x== 25) return .766;
else if (x== 26) return .788;
else if (x== 27) return .809;
else if (x== 28) return .829;
else if (x== 29) return .848;
else if (x== 30) return .866;
else if (x== 31) return .883;
else if (x== 32) return .899;
else if (x== 33) return .914;
else if (x== 34) return .927;
else if (x== 35) return .94;
else if (x== 36) return .951;
else if (x== 37) return .961;
else if (x== 38) return .97;
else if (x== 39) return .978;
else if (x== 40) return .985;
else if (x== 41) return .99;
else if (x== 42) return .995;
else if (x== 43) return .998;
else if (x== 44) return .999;
else if (x== 45) return 1;
else if (x== 46) return .999;
else if (x== 47) return .998;
else if (x== 48) return .995;
else if (x== 49) return .99;
else if (x== 50) return .985;
else if (x== 51) return .978;
else if (x== 52) return .97;
else if (x== 53) return .961;
else if (x== 54) return .951;
else if (x== 55) return .94;
else if (x== 56) return .927;
else if (x== 57) return .914;
else if (x== 58) return .899;
else if (x== 59) return .883;
else if (x== 60) return .866;
else if (x== 61) return .848;
else if (x== 62) return .829;
else if (x== 63) return .809;
else if (x== 64) return .788;
else if (x== 65) return .766;
else if (x== 66) return .743;
else if (x== 67) return .719;
else if (x== 68) return .695;
else if (x== 69) return .669;
else if (x== 70) return .643;
else if (x== 71) return .616;
else if (x== 72) return .588;
else if (x== 73) return .559;
else if (x== 74) return .53;
else if (x== 75) return .5;
else if (x== 76) return .469;
else if (x== 77) return .438;
else if (x== 78) return .407;
else if (x== 79) return .375;
else if (x== 80) return .342;
else if (x== 81) return .309;
else if (x== 82) return .276;
else if (x== 83) return .242;
else if (x== 84) return .208;
else if (x== 85) return .174;
else if (x== 86) return .139;
else if (x== 87) return .105;
else if (x== 88) return .07;
else if (x== 89) return .035;
else if (x== 90) return 0;
};
void() bobbing_think
{
// Calculate next angle. Used to calculate the speed we need
self.nextangle = self.nextangle + 1;
if (self.nextangle > 90)
self.nextangle = self.nextangle - 90;
if (self.nextangle < 0) // In case we are cycling backwards with speed value of -1 or some negative integer value
self.nextangle = self.nextangle + 90;
// Calculate next z position
self.sinresult = sin_angle_pi(self.nextangle); // Get the sin result of angle div 90 times pi
self.orbitrelative = (self.sinresult - 0.5) * self.height*2; // Calculate the relative Z distance from the center of the origin
self.targetspot = self.origin; // The target spot is the orbit origin ...
self.targetspot_z = self.orbitorigin + self.orbitrelative;
self.targetdistance = self.targetspot_z - self.origin_z;
// What velocity is required to reach that by the nextthink
self.velocity_z = self.targetdistance/(self.ltime - self.lastthink); // Speed required = distance divided by time between thinks
self.think = bobbing_think;
self.nextthink = self.ltime + 0.00001; // Act next frame!
self.lastthink = self.ltime; // Store this. Our only home for trying to calculate real time orbit correction is to measure last reading
}
/*QUAKED func_wall (0 .5 .8) ?
This is just a solid wall if not inhibitted
*/
void() func_wall =
{
self.angles = '0 0 0';
self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything
self.solid = SOLID_BSP;
self.use = func_wall_use;
setmodel (self, self.model);
// Begin Baker mod
if (self.speed > 0 || self.speed <0) // Non-zero speed = bobbing. Must be integer. 1 is bobbing starting up. -1 is bobbing starting down. 2 or -2 = faster
{
local vector fakeorigin;
// speed = Starting direction 1 up or -1 down. Can be integer value like 2 or -2 to increase the speed. Cannot be non-integer due to sin fakery unless using extension like DarkPlaces
// height = the radius of the bob.
self.orbitorigin_x = 0;
self.orbitorigin_y = 0;
self.orbitorigin_z = self.size_z / 2;
self.nextangle = 15; // Set the anglecycle to 15 which is equilbrium.
if (self.speed < 0)
self.height = -self.height; // "height" is the bobbing radius. Invert the radius if speed is negative
// Give it a nextthink
self.think = bobbing_think;
self.nextthink = self.ltime + .00001;
self.lastthink = self.ltime; // We need this to measure time between thinks to calculate speed (Quake's quote unquote "velocity") to hit target
}
// End Baker mod
};It is as smooth as frag,machine's Q2K4 wavey water or Lardarse's board gaming.
