float SUB_True() { return 1; }
float SUB_False() { return 0; }
-void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
void() SUB_CalcMoveDone;
void() SUB_CalcAngleMoveDone;
//void() SUB_UseTargets;
self.think1 ();
}
+.float bezier_turn;
void SUB_CalcMove_controller_think (void)
{
entity oldself;
traveltime = self.animstate_endtime - self.animstate_starttime;
phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
- if(self.platmovetype != 1)
+ if(!self.platmovetype)
+ self.platmovetype = 2; // default
+ switch(self.platmovetype)
{
- phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
- phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1]
- phasepos = phasepos + 1; // correct range to [0, 2]
- phasepos = phasepos / 2; // correct range to [0, 1]
+ case 1: // linear
+ break;
+ case 2: // cosine
+ /* old version, good for mathematical reference
+ phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
+ phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1]
+ phasepos = phasepos + 1; // correct range to [0, 2]
+ phasepos = phasepos / 2; // correct range to [0, 1]
+ */
+
+ phasepos = (1 - cos(phasepos * 3.14159265)) / 2;
+ break;
+ case 3: // inverted cosine
+ phasepos = acos(1 - phasepos * 2) / 3.14159265;
+ break;
+ case 4: // half cosine
+ phasepos = (1 - cos(phasepos * (3.14159265 / 2)));
+ break;
+ case 5: // inverted half cosine
+ phasepos = sin(phasepos * (3.14159265 / 2));
+ break;
}
nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
// derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
}
self.owner.velocity = veloc;
+ if(self.owner.bezier_turn)
+ {
+ vector vel;
+ vel = delta + 2 * delta2 * phasepos;
+ vel_z = -vel_z; // invert z velocity
+ vel = vectoangles(vel);
+ self.owner.angles = vel;
+ }
self.nextthink = nexttick;
} else {
// derivative: delta + 2 * delta2 (e.g. for angle positioning)
controller.destvec = 2 * control; // control point
controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point
+ // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (dest - control)
}
void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest)
controller.destvec2 = '0 0 0';
}
-void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeed, void() func)
+float TSPEED_TIME = -1;
+float TSPEED_LINEAR = 0;
+float TSPEED_START = 1;
+float TSPEED_END = 2;
+// TODO average too?
+
+void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
{
float traveltime;
entity controller;
self.finaldest = tdest;
self.think = SUB_CalcMoveDone;
- if(tspeed > 0) // positive: start speed
- traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
- else // negative: end speed
- traveltime = 2 * vlen(tcontrol - tdest) / -tspeed;
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
+ break;
+ case TSPEED_END:
+ traveltime = 2 * vlen(tcontrol - tdest) / tspeed;
+ break;
+ case TSPEED_LINEAR:
+ traveltime = vlen(tdest - self.origin) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
if (traveltime < 0.1) // useless anim
{
self = self.owner;
}
-void SUB_CalcMove (vector tdest, float tspeed, void() func)
+void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
{
vector delta;
float traveltime;
}
delta = tdest - self.origin;
- traveltime = vlen (delta) / tspeed;
+
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ case TSPEED_END:
+ case TSPEED_LINEAR:
+ traveltime = vlen (delta) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
// Very short animations don't really show off the effect
// of controlled animation, so let's just use linear movement.
// Alternatively entities can choose to specify non-controlled movement.
// The only currently implemented alternative movement is linear (value 1)
- if (traveltime < 0.15 || self.platmovetype == 1)
+ if (traveltime < 0.15 || self.platmovetype < 2)
{
self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
self.nextthink = self.ltime + traveltime;
}
// now just run like a bezier curve...
- SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeed, func);
+ SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
}
-void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
+void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
{
entity oldself;
oldself = self;
self = ent;
- SUB_CalcMove (tdest, tspeed, func);
+ SUB_CalcMove (tdest, tspeedtype, tspeed, func);
self = oldself;
}
}
// FIXME: I fixed this function only for rotation around the main axes
-void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
+void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
{
vector delta;
float traveltime;
self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
delta = destangle - self.angles;
- traveltime = vlen (delta) / tspeed;
+
+ switch(tspeedtype)
+ {
+ default:
+ case TSPEED_START:
+ case TSPEED_END:
+ case TSPEED_LINEAR:
+ traveltime = vlen (delta) / tspeed;
+ break;
+ case TSPEED_TIME:
+ traveltime = tspeed;
+ break;
+ }
self.think1 = func;
self.finalangle = destangle;
self.nextthink = self.ltime + traveltime;
}
-void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
+void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
{
entity oldself;
oldself = self;
self = ent;
- SUB_CalcAngleMove (destangle, tspeed, func);
+ SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
self = oldself;
}