view
variable is actually NOT the view I keep mentioning. It's a viewmodel, or rather, a weapon model, as you can see around line 530:
// view is the weapon model (only visible from inside body )
view = gEngfuncs.GetViewModel();
Instead, we wanna look at pparams. To be exact, pparams->vieworg
is what we're looking for. It is the position of the player's view.// refresh position
VectorCopy ( pparams->simorg, pparams->vieworg );
pparams->vieworg[2] += bobRight;
VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg );
The initial view origin is playerOrigin + viewHeight. We can add more vectors to this to achieve interesting effects, for example, leaning left and right, or custom recoil, or custom earthquakes. Anything you can think of that involves moving the camera (not rotating it, that'll be a different story).pparams->vieworg[2] += 40.0f;
...your view will go 40 units up, but the weapon will stay below the view. No, that is not an FOV trick. The FOV was 90° in that screenshot.pparams->vieworg
at all. It independently calculates it based on the player's origin and the view height provided by the player movement code:
// Use predicted origin as view origin.
VectorCopy ( pparams->simorg, view->origin );
view->origin[2] += ( waterOffset );
VectorAdd( view->origin, pparams->viewheight, view->origin );
So, what can we do with this? All kinds of things. Let's try leaning, Thief-style.
...
kbutton_t in_moveleft;
kbutton_t in_moveright;
kbutton_t in_strafe;
kbutton_t in_speed;
kbutton_t in_use;
...
We're gonna declare a new one, call it in_lean
.gEngfuncs.pfnAddCommand( "+lean", [] { KeyDown( &in_lean ); } );
gEngfuncs.pfnAddCommand( "-lean", [] { KeyUp( &in_lean ); } );
extern kbutton_t in_lean;
Then, you will check if the key is being held, and if so, displace the view origin.
if ( in_lean.state & 1 )
{
// Displace the view origin on a 2D plane
// according to the player's yaw angle
Vector offset{
std::cosf( view->angles[YAW] * (M_PI / 180.0f) ),
std::sinf( view->angles[YAW] * (M_PI / 180.0f) ),
0.0f
};
// i will only be 0 and 1 because we're only displacing XY, not XY and Z here
for ( i = 0; i < 2; i++ )
{
pparams->vieworg[i] += 32.0f * offset[i];
}
// Z is displaced separately
pparams->vieworg[2] -= 4.0f;
}
This piece of code here is quite hefty, but it's really simple to understand.offset
vector essentially represents some kind of forward direction on a 2D plane. You can think of it as pparams->forward
except it's in 2D.view->origin
the same way as you modified pparams->vieworg
here, so like this:
if ( in_lean.state & 1 )
{
// Displace the view origin on a 2D plane
// according to the player's yaw angle
Vector offset{
std::cosf( view->angles[YAW] * (M_PI / 180.0f) ),
std::sinf( view->angles[YAW] * (M_PI / 180.0f) ),
0.0f
};
// i will only be 0 and 1 because we're only displacing XY, not XY and Z here
for ( i = 0; i < 2; i++ )
{
pparams->vieworg[i] += 32.0f * offset[i];
view->origin[i] += 32.0f * offset[i];
}
// Z is displaced separately
pparams->vieworg[2] -= 4.0f;
view->origin[2] -= 4.0f;
}
Now, there is another thing about this code, that is hard to tell from just 2 screenshots, but the transition between leaned and not leaned is VERY harsh. We need something that will smoothly float between the two states.
x = (a + b)/2
or
x = 0.5a + 0.5b
But what if you wanted to, say, take 20% of A and 80% of B? Easy:
x = 0.2a + 0.8b
Or rather:
x = a(1-α) + b(α)
Where α is currently 0.8.alpha += frameTime;
if ( alpha > 1.0f )
alpha = 1.0f;
Or decrease it by subtracting frametime:
alpha -= frameTime;
if ( alpha < 0.0f )
alpha = 0.0f;
This is EXACTLY what we need to fade between "leaning" and "not leaning".
if ( in_lean.state & 1 )
{
}
{
// Displace the view origin on a 2D plane
// according to the player's yaw angle
Vector offset{
std::cosf( view->angles[YAW] * (M_PI / 180.0f) ),
std::sinf( view->angles[YAW] * (M_PI / 180.0f) ),
0.0f
};
// i will only be 0 and 1 because we're only displacing XY, not XY and Z here
for ( i = 0; i < 2; i++ )
{
pparams->vieworg[i] += 32.0f * offset[i];
view->origin[i] += 32.0f * offset[i];
}
// Z is displaced separately
pparams->vieworg[2] -= 4.0f;
view->origin[2] -= 4.0f;
}
This way, the leaning will be executed every frame, but it's good, because we can control how much of it is applied over time.static float leanFactor = 0.0f;
You can put that at the start of the function.if ( in_lean.state & 1 )
{
leanFactor += pparams->frametime;
if ( leanFactor > 1.0f )
leanFactor = 1.0f;
}
else
{
leanFactor -= pparams->frametime;
if ( leanFactor < 0.0f )
leanFactor = 0.0f;
}
It's going to linearly interpolate towards 1 when the key is pressed, or towards 0 when the key isn't pressed. It will take it exactly 1 second. To change the speed at which this happens, you can multiply the frametime. For example, multiplying it by 4 will mean that leanFactor
will go from 0 to 1 in 0.25 seconds.leanFactor
.
{
// Displace the view origin on a 2D plane
// according to the player's yaw angle
Vector offset{
std::cosf( view->angles[YAW] * (M_PI / 180.0f) ),
std::sinf( view->angles[YAW] * (M_PI / 180.0f) ),
0.0f
};
// i will only be 0 and 1 because we're only displacing XY, not XY and Z here
for ( i = 0; i < 2; i++ )
{
pparams->vieworg[i] += 32.0f * leanFactor * offset[i];
view->origin[i] += 32.0f * leanFactor * offset[i];
}
// Z is displaced separately
pparams->vieworg[2] -= 4.0f * leanFactor;
view->origin[2] -= 4.0f * leanFactor;
}
The rest is tweaking. For example, you might wanna use pparams->frametime * 2.5
. Also, you might want to introduce some extra detail into the leaning movement:
pparams->vieworg[i] += 32.0f * leanFactor * offset[i];
view->origin[i] += 33.5f * leanFactor * offset[i];
This would make the weapon get pushed forward a little bit when leaning.
pparams->vieworg[2] -= 4.0f * leanFactor;
view->origin[2] -= 1.5f * leanFactor;
This would make the weapon go up a bit when leaning.
x = sin( time )
y = -cos( 2 * time )
Or in code:
V_CalcBob( pparams, 1.0f, VB_SIN, bobTimes[0], bobRight, lastTimes[0] );
V_CalcBob( pparams, 2.0f, VB_COS, bobTimes[1], bobUp, lastTimes[1] );
...
for ( i = 0; i < 3; i++ )
{
view->origin[i] += bobRight * 0.33 * pparams->right[i];
view->origin[i] -= bobUp * 0.17 * pparams->up[i];
}
This will give you view bobbing just like in Doom. view->origin[i] -= bobUp * 0.17 * pparams->up[i];
To:
view->origin[i] += bobUp * 0.17 * pparams->up[i];
Also, make sure you're adding bobUp
to the view origin and the weapon origin. The previous tutorial applied bobRight
to them, which worked, but it'd feel unnatural here.
pparams->vieworg[2] += bobUp * 0.5f;
...
view->origin.z += bobUp * 0.5f;
Notice 2 things:
pparams->onground
. I'll add this to part 3.You must log in to post a comment. You can login or register a new account.