In the mod I'm making for Q-Expo, I have the player hovering in the air invisible acting as the camera. He follows the character through the level. The player is testing his own movements to see what directional keys the user is pressing, and moves the "puppet" (as I call the character on the field) around accordingly.
It all works fine in single player, and I can even turn on deathmatch with no problem. A problem does, however, rear its ugly head when I run Darkplaces with the command -listen to start a real multiplayer game. Now all of a sudden when the camera changes angles (either with the left/right strafe keys or with impulses) it's very choppy, where in single player it was very smooth. Moving forward, backward, and strafing left & right is still perfectly smooth, only angles experience a problem.
Are net messages (such as setangle) sent to the client too infrequently in multiplayer to to give a smooth ride? Or is there something I could do differently?
Multiplayer and setangles incompadible?
Multiplayer and setangles incompadible?
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
DP lowers the effective ticrate of the server in multiplayer. Because of this, the server is not running at your client's framerate anymore. You'll experience something akin to a mild lag, but it prevents the server from flooding the holy hell out of other networked clients.
I'm guessing that's the problem here......
I'm guessing that's the problem here......
smooth camera
you can try stuffing
stuffcmd(self, "cl_nolerp 1\n");
when you are in camera view...
also old quake protocol used 256-byte variable as angle not float
in the engine. Unless you are using a modified client you should
try
angle_x = 360.0 / 256.0 * rint(self.movetarget.v_angle_x * 256.0 / 360.0);
angle_y = 360.0 / 256.0 * rint(self.movetarget.v_angle_y * 256.0 / 360.0);
angle_z = 0;
.movetarget points to the "puppet"
hope this is of some use...
stuffcmd(self, "cl_nolerp 1\n");
when you are in camera view...
also old quake protocol used 256-byte variable as angle not float
in the engine. Unless you are using a modified client you should
try
angle_x = 360.0 / 256.0 * rint(self.movetarget.v_angle_x * 256.0 / 360.0);
angle_y = 360.0 / 256.0 * rint(self.movetarget.v_angle_y * 256.0 / 360.0);
angle_z = 0;
.movetarget points to the "puppet"
hope this is of some use...
Better yet,
goto www.runequake.com and download runequake...
ok look in his poq source and u will find a file called
camera.qc
this file does exactly what you are trying to do!
and it works flawless, i have tried it online and its great!
Credit to slotzero!
goto www.runequake.com and download runequake...
ok look in his poq source and u will find a file called
camera.qc
this file does exactly what you are trying to do!
and it works flawless, i have tried it online and its great!
Credit to slotzero!
ok i tinkered with slot's code a bit and heres what i came up with
(sorry its long)
(sorry its long)
Code: Select all
void () W_SetCurrentAmmo;
void () Keep_cam_chasing_owner;
// Resets weapon model after changing view
// called by chase cam or player entities
void (entity player_ent)
Chase_cam_setweapon =
{
local entity e;
e = self;
self = player_ent;
W_SetCurrentAmmo ();
self = e;
};
// called either by player or chase cam entities (to restart)
void (entity cam_owner)
Start_chase_cam =
{
local entity chase_cam;
//look to see if we already have cam ent
chase_cam = find (world,classname, "chase_cam");
while ((chase_cam != world) && (chase_cam.owner != cam_owner))
{
chase_cam = find (chase_cam,classname, "chase_cam");
}
if (chase_cam == world)
{
chase_cam = spawn ();
}
chase_cam.owner = cam_owner;
chase_cam.owner.chase_active = TRUE;
chase_cam.solid = SOLID_NOT;
chase_cam.movetype = MOVETYPE_FLYMISSILE;
chase_cam.angles = chase_cam.owner.angles;
setmodel (chase_cam, "progs/eyes.mdl");
setsize (chase_cam, VEC_ORIGIN, VEC_ORIGIN);
setorigin (chase_cam, chase_cam.owner.origin);
chase_cam.classname = "chase_cam";
chase_cam.nextthink = time + sys_ticrate;
chase_cam.think = Keep_cam_chasing_owner;
msg_entity = chase_cam.owner; // target of message
WriteByte (MSG_ONE, SVC_SETVIEWPORT);
WriteEntity (MSG_ONE, chase_cam); // view port
cam_owner.weaponmodel = "";
};
// secondary think for cam entities
void ()Reable_chase_cam =
{
local entity boss;
self.nextthink = time + sys_ticrate;
if (self.owner.health <= 0)
{
remove (self);
return;
}
if (self.owner.waterlevel > 0)
return;
//refresh after water
boss = self.owner;
remove (self);
Start_chase_cam (boss);
};
// called only by chase cam entities
// opt values
// TRUE = remove completely
// FALSE = remove view but keep alive with Reable_chase_cam();
void (float opt)Remove_chase_cam =
{
// makes entity appear gone even if going into keep alive state
setmodel (self, "");
self.velocity = VEC_ORIGIN;
// set view-point back to normal
msg_entity = self.owner; // target of message
WriteByte (MSG_ONE, SVC_SETVIEWPORT);
WriteEntity (MSG_ONE, self.owner); // view port
Chase_cam_setweapon (self.owner);
if (!opt)
{
self.nextthink = time + sys_ticrate;
self.think = Reable_chase_cam;
}
else
{
remove (self);
}
};
/*
###########
main think function for cam entities
self.ammo_shells = distance clipping
self.ammo_nails = hang-up flag
self.ammo_cells = view offset direction
0 = up
1 = left
2 = right
###########
*/
void () Keep_cam_chasing_owner =
{
local vector pos;
local vector desired_angle;
local vector angle;
local vector dir;
local float dist, cap;
self.nextthink = time + sys_ticrate;
// check if player turned off
// or in water
if (self.owner.chase_active == FALSE)
{
Remove_chase_cam (TRUE);
return;
}
if (self.owner.waterlevel > 0)
{
if (self.owner.health > 0)
{
Remove_chase_cam (FALSE);
return;
}
}
desired_angle = self.owner.v_angle;
angle_x = ((self.oldangle_x * (1 - 0.6)) + (desired_angle_x * 0.6));
angle_y = angles_pick_angle (self.oldangle_y, desired_angle_y, 0.6);
angle_z = 0;
angle_x = (angle_x * 1);
angle_y = (angle_y * 1);
makevectors (angle);
pos = self.owner.origin;
traceline (pos, (pos + (32 * v_up)), TRUE, self.owner);
pos = (pos + ((trace_fraction * 22) * v_up));
traceline (pos, (pos - (120 * v_forward)), TRUE, self.owner);
pos = (pos - ((trace_fraction * 100) * v_forward));
traceline (pos, pos + '0 0 32', FALSE, self.owner);
if (trace_fraction < 1)
{
dir = trace_endpos - '0 0 32';
traceline (pos, pos - '0 0 32', FALSE, self.owner);
if (trace_fraction == 1)
pos = dir;
}
dir = normalize (pos - self.origin);
dist = vlen (pos - self.origin);
traceline (self.origin, pos, FALSE, self.owner);
if (trace_fraction == 1)
{
self.angles = self.owner.angles;
cap = dist * 0.2;
if (cap > 5.2)
self.velocity = dir * dist * 5.2;
else if (cap > 1)
self.velocity = dir * dist * cap;
else
self.velocity = dir * dist;
}
setorigin (self, pos);
angles_fixangle (angle);
self.owner.weaponmodel = "";
};
// called by player only
void ()
Toggle_chase_cam =
{
if ((self.chase_active == TRUE))
{
// will be noticed by next think
// of player's chase cam entity
self.chase_active = FALSE;
}
else
{
Start_chase_cam (self);
}
};
void ()
Chase_cam_lvlstart_think =
{
if ((self.owner.chase_active == TRUE))
Start_chase_cam (self.owner);
remove (self);
};
// called in CLIENT.QC by PutClientInServer
// player.chase_active is set and saved between levels using parm16
// in CLIENT.QC
void ()
Chase_cam_level_start =
{
local entity e;
e = spawn ();
e.owner = self;
e.movetype = MOVETYPE_NONE;
e.solid = SOLID_NOT;
setmodel (e, "");
setsize (e, VEC_ORIGIN, VEC_ORIGIN);
setorigin (e, e.owner.origin);
e.nextthink = time + 0.2;
e.think = Chase_cam_lvlstart_think;
};
Thanks, r00k.
Looking at that code, I notice a few things it's doing that I'm not. First of all, the camera isn't the player; instead, it's a separate entity that watches the player. My situation is comparable but different. I was using the player as a camera to watch another entity. I think I need to spawn another entity to act as the camera, and use the player only for motion capturing.
Another thing is the camera here uses velocity to move into position, rather than simply setorigins. I had some trouble with that because I'm using the same entity (the player) to capture the player's movement key presses to tell where he wants to go. I think if I use a separate camera entity, and have it do velocity, maybe it will be a bit smoother. However, moving forward and backward in my mod works fine - it is only turning that is choppy. So maybe that's not it.
I'll have to explore a little more. The choppiness could very well be because it's the player that I'm setting origin on and such.
Thanks again, r00k!
Looking at that code, I notice a few things it's doing that I'm not. First of all, the camera isn't the player; instead, it's a separate entity that watches the player. My situation is comparable but different. I was using the player as a camera to watch another entity. I think I need to spawn another entity to act as the camera, and use the player only for motion capturing.
Another thing is the camera here uses velocity to move into position, rather than simply setorigins. I had some trouble with that because I'm using the same entity (the player) to capture the player's movement key presses to tell where he wants to go. I think if I use a separate camera entity, and have it do velocity, maybe it will be a bit smoother. However, moving forward and backward in my mod works fine - it is only turning that is choppy. So maybe that's not it.
I'll have to explore a little more. The choppiness could very well be because it's the player that I'm setting origin on and such.
Thanks again, r00k!
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
are you capturing the player angles and using them? I tried doing that when I was working on the mouse cursor for cannon fodder quake, and I found that quake is very bitty when capturing angles. I found it to me far more accurate when capturing strafing. Perhaps you could have +strafe set, then capture the strafe direction and convert it to an angle change? I dunno how your mod works, so I dunno if that'll work
Apathy Now!