Owned: Bobbing Platforms (Tutorial)
Moderator: InsideQC Admins
7 posts
• Page 1 of 1
Owned: Bobbing Platforms (Tutorial)
frag.machine wrote:AFAIK you cannot have bobbing platforms with just vanilla QuakeC.
You had me scared
Lardarse 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.
Well, actually it is smooth
Lardarse wrote:Not sure how you make sure it stops at exactly the correct top/bottom points every time, though.
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.
----
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
};
Video, map, map source code, progs and progs source code tomorrow. I'm tired. But happy and satisfied. It works like a charm.
It is as smooth as frag,machine's Q2K4 wavey water or Lardarse's board gaming.
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Definitely gotta give this a try later, would be awesome for stuff floating in water / slime / lava. 
-

Dr. Shadowborg - InsideQC Staff
- Posts: 1110
- Joined: Sat Oct 16, 2004 3:34 pm
Crappy fullbright testing map.
Video link: http://www.youtube.com/watch?v=OD_kZYFdBJ4
It's totally smooth, no jerkiness, no weirdness when standing on the platforms. Feels completely natural.
Map and mod download: http://quake-1.com/docs/mods/bobbing.zip
Unzip in Quake folder, start Quake with -game bobbing +map bobbing
Making a bobbing platform: Make a func_wall. Set the speed property to -1 or 1 (or some integer like 2). Set the height property to the max radius of the bob.
Map source looks like this:
Video link: http://www.youtube.com/watch?v=OD_kZYFdBJ4
It's totally smooth, no jerkiness, no weirdness when standing on the platforms. Feels completely natural.
Map and mod download: http://quake-1.com/docs/mods/bobbing.zip
Unzip in Quake folder, start Quake with -game bobbing +map bobbing
Making a bobbing platform: Make a func_wall. Set the speed property to -1 or 1 (or some integer like 2). Set the height property to the max radius of the bob.
"classname" "func_wall"
"speed" "1"
"height" "16"
Map source looks like this:
{
"classname" "func_wall"
"speed" "1"
"height" "16"
{
( -64 -192 96 ) ( 64 -192 96 ) ( 64 -320 96 ) SPEEDBZ_W0 [ 1 0 0 128 ] [ 0 -1 0 0 ] 0 1 1
( -64 -320 80 ) ( 64 -320 80 ) ( 64 -192 80 ) SPEEDBZ_W0 [ 1 0 0 128 ] [ 0 -1 0 0 ] 0 1 1
( -64 -192 96 ) ( -64 -320 96 ) ( -64 -320 80 ) SPEEDBZ_W0 [ 0 1 0 0 ] [ 0 0 -1 32 ] 0 1 1
( 64 -192 80 ) ( 64 -320 80 ) ( 64 -320 96 ) SPEEDBZ_W0 [ 0 1 0 0 ] [ 0 0 -1 32 ] 0 1 1
( 64 -192 96 ) ( -64 -192 96 ) ( -64 -192 80 ) SPEEDBZ_W0 [ 1 0 0 128 ] [ 0 0 -1 32 ] 0 1 1
( 64 -320 80 ) ( -64 -320 80 ) ( -64 -320 96 ) SPEEDBZ_W0 [ 1 0 0 128 ] [ 0 0 -1 32 ] 0 1 1
}
}
{
"classname" "func_wall"
"speed" "2"
"height" "15"
{
( 336 -192 96 ) ( 464 -192 96 ) ( 464 -320 96 ) SPEEDBZ_W0 [ 1 0 0 112 ] [ 0 -1 0 0 ] 0 1 1
( 336 -320 80 ) ( 464 -320 80 ) ( 464 -192 80 ) SPEEDBZ_W0 [ 1 0 0 112 ] [ 0 -1 0 0 ] 0 1 1
( 336 -192 96 ) ( 336 -320 96 ) ( 336 -320 80 ) SPEEDBZ_W0 [ 0 1 0 0 ] [ 0 0 -1 48 ] 0 1 1
( 464 -192 80 ) ( 464 -320 80 ) ( 464 -320 96 ) SPEEDBZ_W0 [ 0 1 0 0 ] [ 0 0 -1 48 ] 0 1 1
( 464 -192 96 ) ( 336 -192 96 ) ( 336 -192 80 ) SPEEDBZ_W0 [ 1 0 0 112 ] [ 0 0 -1 48 ] 0 1 1
( 464 -320 80 ) ( 336 -320 80 ) ( 336 -320 96 ) SPEEDBZ_W0 [ 1 0 0 112 ] [ 0 0 -1 48 ] 0 1 1
}
}
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Mathlib sin uses radians, not degrees. sin (90) degrees == sin (M_PI / 2) radians.
PF_sin and friends should be in every engine, and there should also be a PF_sin_degrees, etc to avoid some QC ops.
PF_sin and friends should be in every engine, and there should also be a PF_sin_degrees, etc to avoid some QC ops.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-

mh - Posts: 2292
- Joined: Sat Jan 12, 2008 1:38 am
mh wrote:Mathlib sin uses radians, not degrees. sin (90) degrees == sin (M_PI / 2) radians.
PF_sin and friends should be in every engine, and there should also be a PF_sin_degrees, etc to avoid some QC ops.
Ah well I didn't know that. Knowing how thorough FrikaC is, I was a little surprised it wasn't working for me (in the way I was expecting).
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Nice. Didn't think to use a sine table. That long mad elseif chain can be made more efficient (for matters of runaway loops). But other than that, good stuff.
Edit:
Actually, the other way around. The sin() builtin uses radians. The mathlib version of the function uses degrees. Mathlib also provides a wrapper for sin() and cos() to give degrees. So I don't know what caused the issues.
Edit 2: Ok, I see what you're doing now. sin() should reach its peak at 90, not 45. To get the correct answer out of mathlib sin(), you would need to double the angle you give to it.
Edit:
mh wrote:Mathlib sin uses radians, not degrees. sin (90) degrees == sin (M_PI / 2) radians.
Actually, the other way around. The sin() builtin uses radians. The mathlib version of the function uses degrees. Mathlib also provides a wrapper for sin() and cos() to give degrees. So I don't know what caused the issues.
Edit 2: Ok, I see what you're doing now. sin() should reach its peak at 90, not 45. To get the correct answer out of mathlib sin(), you would need to double the angle you give to it.
Roaming status: Testing and documentation
-

Lardarse - Posts: 266
- Joined: Sat Nov 05, 2005 1:58 pm
- Location: Bristol, UK
7 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest