
I am trying to implement Mario64/Sonic Adventure-like scheme of camera and controls into Half-Life singleplayer. Not working on it every single day but been trying to do it for over 6 months by now. Back then I started with a server-side camera as a reference point, then I moved to client side camera and now my reference point is just 0, 0, 0 with a camera as an irrelevant top-down observer. I did this because I've been trying to avoid the same weird bug that just kept occurring.
My assumption for a control scheme like this was: as long as the camera isn't moving and it is pointed straight at the player, and as long as player is moving 90 degrees left or right from camera's view direction, player would walk in perfect circles around the camera.
However I was mistaken and the following glitch kept occurring: player would walk not in circles but in a spiral.
https://www.youtube.com/watch?v=zg3iHxD1uFI
The code for this is simple:
Code: Select all
void V_CalcThirdPersonRefdef( struct ref_params_s * pparams )
{
// make a variable with shorter name
VectorCopy ( pparams->simorg, v_sim_org );//player origin
// ======Make camera calculations======
VectorAngles ( player->curstate.origin, pparams->cl_viewangles );
// write back new values into pparams
pparams->vieworg[2]=999;
pparams->viewangles[0]= 90;// top-down
// end of block for thirdperson camera
At that point I was kind of desperate already. I tried to do the same thing in Quake and it turned out to be exactly the same:
https://www.youtube.com/watch?v=0XPmVA9DnmE
Code: Select all
void Chase_UpdateForDrawing (void)
{
int i;
float dist;
vec3_t forward, up, right;
vec3_t crosshair, temp;
r_refdef.vieworg[0] = 0;
r_refdef.vieworg[1] = 0;
r_refdef.vieworg[2] = 999;
VectorAngles (cl.viewent.origin, cl.viewangles);
r_refdef.viewangles[PITCH] = 90;
r_refdef.viewangles[YAW] = 0;
}
But may be this lag is not that severe and the real bug is somewhere else? For example, in my assumption about moving at perfect 90 degrees to the side. Considering how smooth movement doesn't really exist in a game but a sequence of discrete frames only, I can imagine a circle as a really smooth n-gon and try to predict a correction I have to apply to cl_viewangles as an angle between its sides. I need a horda, radius, and frametime: angle=2*asin(horda/2*Radius)
Code: Select all
//==========================
// V_CalcThirdPersonRefdef
//==========================
Vector plyawtracker, plyawtrackerold, plyawtrackerdiff;
void V_CalcThirdPersonRefdef( struct ref_params_s * pparams )
{
cl_entity_t *ent = GET_LOCAL_PLAYER();
static float M_RADIAN = 57.2958;
pparams->vieworg[2] = 999;
pparams->viewangles[0]=90;
ALERT (at_console, "radius = %.3f ", pparams->simorg.Length());
Vector onefrmvel = ent->curstate.velocity * pparams->frametime;
float fl_onefrmvel = onefrmvel.Length();
float sinusfood = fl_onefrmvel / ( 2 * pparams->simorg.Length() );
//ALERT (at_console, "sinfood = %.3f\n", sinusfood);
float yaw_corr_rad = 2 * asin (sinusfood);
float yaw_corr_deg = yaw_corr_rad * M_RADIAN;
VectorAngles (pparams->simorg, pparams->cl_viewangles);
ALERT (at_console, "pl yaw, raw and corrected: %.3f, ", pparams->cl_viewangles[1] );
if (pparams->cl_viewangles[1]<0)
yaw_corr_deg = -yaw_corr_deg;
pparams->cl_viewangles[1] += yaw_corr_deg;
ALERT (at_console, "%.3f\n", pparams->cl_viewangles[1] );
Code: Select all
float yaw_corr_rad = 2 * asin (sinusfood);
Of course I can keep trying to perfect this approach: consider which key, strafe left of strafe right is held down, or I can get rid of curstate.velocity and substract old origin from new one to calculate 1-frame movement, I can also consider CL_Keystate multiplier. But am I even moving in a right direction with all this? I have a history of being too humble to admit that the problem whose solution I am trying to perfect, shouldn't exist at all.