Help: Moving a func_train via an array of vectors

Discuss programming in the QuakeC language.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Help: Moving a func_train via an array of vectors

Post by Spike »

setorigin within a movetype_push's think function is a special case. the movement is detected upon return and the engine pushes all entities to get the pusher to match the setorigin.
Its common to call setorigin to try to kill any precision errors from SUB_CalcMove.

you can only 'swerve' around corners by updating the velocity in fairly small time increments. SUB_CalcMove can be used to update the velocity, but you need to calculate the position yourself and do the repeated callings each time it reaches the previous point.
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Re: Help: Moving a func_train via an array of vectors

Post by OneManClan »

[DISCLAIMER: My Maths is woeful, apologies for sloppy, potentially improper descriptions]
Spike wrote:you can only 'swerve' around corners by updating the velocity in fairly small time increments.
velocity? I thought we'd be updating the 'destination'.(?) ie if we're traveling forward, and making a sharp turn to the left (ie turning 90 degrees), rather than heading to the vertex of the two paths (not sure im describing this correctly), we change the direction of the cart earlier, moving it (slightly) to the left in segments, 'describing' (if that's the correct term) a curved path, until we end up facing 90 degrees from where we started. Or am I missing something?
Spike wrote:SUB_CalcMove can be used to update the velocity, but you need to calculate the position yourself and do the repeated callings each time it reaches the previous point.
The previous point? Not sure what you mean.. :(

Btw, being a mathematical Philistine, I have been reading 'Calculus for Dummies' (yes, I'm serious), but since making a 'quarter circle' involves a 'steady rate of change', is it still a job for Calculus?
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Help: Moving a func_train via an array of vectors

Post by frag.machine »

OneManClan wrote:Btw, I notice the cart is MOVETYPE_PUSH, but (IIUC) moves via :

Code: Select all

setorigin (self, self.goalentity.origin - self.mins);
Q: Is there a reason you didn't use SUB_CalcMove() (which I thought was the standard way to move MOVETYPE_PUSH?). IIUC, Spike mentions (above) that SUB_CalcMove would make it possible for the cart to 'swerve' around corners in a semi circle, rather than a sudden/sharp change in direction (though I have no idea how complex this would be to implement).

Actually,my code is based partially in SUB_CalcMove () code. Why to write my own movement code then ? Well, SUB_CalcMove () will set the required constant speed to cover the distance in the given time lapse, and this is just fine for regular plats and func_trains. However, the TF2 payload cart moves in a variable speed depending of the number of attacking players close to it; the more attackers nearby, the faster the movement (it checks constantly the percentual of players in the attacking team nearby and apply this to the final speed). About SUB_CalcMove () being able to make objects "turn" around corners: I can't remember any example of that in regular Quake. In fact, IIRC the cart won't turn at all, just change movement directions (that's why my example cart doesn't have defined "front" or "rear" sides, so it never looks "moving wrong").
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Re: Help: Moving a func_train via an array of vectors

Post by OneManClan »

Ok, I've found an example of an entity moving along a path, which rotates to face the way it's going. The map is called jgpcity4.bsp, and there's a police car which goes for a drive when someone steals blues gold. I had a look at the ent file (the complete ent file is here)and it contains the following interesting bits:

Code: Select all

{
"classname" "func_rotate_train"
"origin" "0 0 0"
"target" "auto"
"targetname" "start_auto"
"path" "move_0"
"model" "*70"
}
{
"classname" "info_rotate"
"origin" "1016 2136 -16"
"angle" "360"
"targetname" "centre_auto"
}
{
"classname" "path_rotate"
"origin" "768 2168 -16"
"targetname" "move_27"
"target" "move_1"
"rotate" "0"
"speed" "10"
"angle" "270"
"owned_by" "1"
"spawnflags" "4"
}
{
"classname" "path_rotate"
"origin" "1144 -1800 -16"
"targetname" "move_15"
"target" "move_16"
"rotate" "0"
"speed" "100"
"angle" "0"
"owned_by" "1"
"spawnflags" "2"
}
{
"classname" "path_rotate"
"origin" "768 2136 -16"
"targetname" "move_1"
"target" "move_2"
"rotate" "0"
"speed" "100"
"angle" "90"
"owned_by" "1"
"spawnflags" "2"
"noise" "ambience/police.wav"
"noise1" "ambience/police.wav"
}
{
"classname" "path_rotate"
"origin" "1000 2136 -16"
"target" "move_1"
"targetname" "move_0"
"speed" "100"
"rotate" "0"
"wait" "0"
"dmg" "0"
"noise" "items/cars.wav"
"noise1" "items/cars.wav"
"angle" "0"
"owned_by" "1"
"netname_team_broadcast" "la voiture part!\n"
"spawnflags" "2"
}
{
"classname" "path_rotate"
"origin" "648 1528 -16"
"targetname" "move_3"
"target" "move_4"
"rotate" "0"
"speed" "100"
"angle" "0"
"spawnflags" "2"
"owned_by" "2"
}
To my surprise, the relevant qc bits are already in CustomTF, in rotate.qc, (modified by OfteN), with some commentary:
"path" specifies the first path_rotate and is the starting position. If the train is the target of a button or trigger, it will not begin moving until activated. The func_rotate_train entity is the center of rotation of all objects targeted by it.
Also, quoting Scar3crow:
(The hypnotic mission packs) named everything new in qc regarding this "rotate" at some point, so a rotate train used path rotate entities... this was so it could get updated angles, without adding to the existing path rotate entity ..
I'm still trying to understand all this, but could someone familiar with this functionality (or Guruesque enough to give it a quick skim) tell me what the situation is regarding getting the func_cart to rotate, every time it changes direction. This 'hypnotic' rotate stuff seems to use some concept where an entity placed somewhere (?) acts like a 'centre' for all rotations (or something). I'll study it more to see if it starts making sense, but for now, my question is:

Q: Can this rotation code be 'incorporated' into the current system (ie just add it to frag.machines existing code), or does it require a rewrite, using a completely different concept of 'path_rotate' entities..

Also a 'dummies' explanation of how they work would be great, thanks.
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Re: Help: Moving a func_train via an array of vectors

Post by OneManClan »

frag.machine, could you please tell me what the following variables do:

.aflag = the carts previous state?
.state = the carts state ??
.enemy = this stores the the current waypoint?
.target = also this stores the the current waypoint?
.goalentity = *also* stores the the current waypoint?
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Help: Moving a func_train via an array of vectors

Post by frag.machine »

OneManClan wrote:frag.machine, could you please tell me what the following variables do:

.aflag = the carts previous state?
.state = the carts state ??
.enemy = this stores the the current waypoint?
.target = also this stores the the current waypoint?
.goalentity = *also* stores the the current waypoint?
.aflag = used to remember the last cart state, so i can detect state changes and react according (changing sounds, for example). You can notice it by this commented snippet on cart_think ():

// bprint ("cart_think: state changed from ");
// bprint (ftos (self.aflag));
// bprint (" to ");
// bprint (ftos (self.state));
// bprint (", pausetime = ");
// bprint (ftos (self.pausetime));
// bprint ("\n");

.state = tells the current cart state (stopped, forward, backward, etc) ;

.enemy = stores the previous target entity, if any (== world when the cart is traveling towards the first corner);

.target = works exactly like the .target attribute in a regular func_plat (ie. once you set the cart in your map, you need to also set its .target to the first path_corner). It's value can be changed in runtime.

.goalentity = it's used to hold the next path_corner (if the cart is going backwards, it holds the previous path_corner).

I know the code is not exactly trivial (and to make things worst I reused fields like .aflag), but the main idea itself is quite simple actually.
In a nutshell:

Forward: we look for the next step in goalentity.target;
Backward: we look for the previous step in self.enemy.targetname.

Basically, that's why the path_corners are first "moving" from .goalentity to .enemy before being discarded as the cart reaches the corners.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Re: Help: Moving a func_train via an array of vectors

Post by OneManClan »

frag.machine wrote:
OneManClan wrote:Btw, I notice the cart is MOVETYPE_PUSH, but (IIUC) moves via :

Code: Select all

setorigin (self, self.goalentity.origin - self.mins);
Q: Is there a reason you didn't use SUB_CalcMove() (which I thought was the standard way to move MOVETYPE_PUSH?).
Actually,my code is based partially in SUB_CalcMove () code. Why to write my own movement code then ? Well, SUB_CalcMove () will set the required constant speed to cover the distance in the given time lapse, and this is just fine for regular plats and func_trains. However, the TF2 payload cart moves in a variable speed depending of the number of attacking players close to it; the more attackers nearby, the faster the movement (it checks constantly the percentual of players in the attacking team nearby and apply this to the final speed).
Is this because calling setorigin every frame is more 'efficient' than calling SUB_CalcMove every frame - or was there another reason? ie why not just send multiple calls to SUB_CalcMove with a different speed each time?
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Help: Moving a func_train via an array of vectors

Post by frag.machine »

OneManClan wrote:
frag.machine wrote:
OneManClan wrote:Btw, I notice the cart is MOVETYPE_PUSH, but (IIUC) moves via :

Code: Select all

setorigin (self, self.goalentity.origin - self.mins);
Q: Is there a reason you didn't use SUB_CalcMove() (which I thought was the standard way to move MOVETYPE_PUSH?).
Actually,my code is based partially in SUB_CalcMove () code. Why to write my own movement code then ? Well, SUB_CalcMove () will set the required constant speed to cover the distance in the given time lapse, and this is just fine for regular plats and func_trains. However, the TF2 payload cart moves in a variable speed depending of the number of attacking players close to it; the more attackers nearby, the faster the movement (it checks constantly the percentual of players in the attacking team nearby and apply this to the final speed).
Is this because calling setorigin every frame is more 'efficient' than calling SUB_CalcMove every frame - or was there another reason? ie why not just send multiple calls to SUB_CalcMove with a different speed each time?
Wow, more than a year later, I can't remember all these minor details. Sorry :)
But feel free to try replacing things and see the outcome. I wasn't worried about performance when I wrote this.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
Post Reply