Pans the camera around the car, and drive in a camera-relative direction using the WASD keys, like in a FPS game.
Look to the car's left while it drives to the right as you hold D, for example.
I haven't thoroughly tested it, so I'm not sure I should go plugin with it yet, but it's plugin_ named.
1st, link a CamChase, then a car. Disable all the car's keys. Add terrain and g-force, and it should be good to go.
Here's the script:
Look to the car's left while it drives to the right as you hold D, for example.
I haven't thoroughly tested it, so I'm not sure I should go plugin with it yet, but it's plugin_ named.
1st, link a CamChase, then a car. Disable all the car's keys. Add terrain and g-force, and it should be good to go.
Here's the script:
Code: [Select]
int objCam= OBJ_0;
int objCar= OBJ_22;
///
/// Modifiable parameters
string dikU= "DIK_W";
string dikD= "DIK_S";
string dikL= "DIK_A";
string dikR= "DIK_D";
string dikBrake= "DIK_SPACE";
string dikZoomIn= "DIK_PRIOR"; // PGUP
string dikZoomOut="DIK_NEXT"; // PGDN
float lookSmoothX= 0.75;
float lookSmoothY= 0.9;
float lookSpeedX= 300;
float lookSpeedY= 150;
float turnRate=360; // degrees/sec
float zStep= 15.0/16.0; // zoom step size
float wheelFactor=0.75; // wheel+-= zStep*wheelFactor
///
bool isBehind; // should be called inReverse. I'll rename that later
bool moving; // WASD key(s) are being pressed. Going forward or reverse
bool newBeginning; // Just began moving. isBehind/inReverse will be assigned a value
// (makes WASD circling possible)
float moveAngle=0;
void moveDirection() { // determine if player is WASDing, and which way
float x=0, z=0;
if (iKeyDown(iKeyCode(dikU))) z+= 1;
if (iKeyDown(iKeyCode(dikD))) z-= 1;
if (iKeyDown(iKeyCode(dikL))) x-= 1;
if (iKeyDown(iKeyCode(dikR))) x+= 1;
bool _moving= (x!=0 or z!=0);
newBeginning= _moving and not moving;
if (moving= isMoving) // assignment, not compair-fail
moveAngle= 57.295779*R_atan2(x, z);
}
Quaternion qCam, qCar;
// Get RadMath2.dll from Quaternion_to_cartesian.zip here:http://3dfoundry.net/forum/index.php?topic=32.0
int MathDLLHandle=0; // R_atan2 needs RadMath2.dll
void Main() { /// Main
if(iInitializing()) {
MathDLLHandle = iDLLLoad(".\\3DRad_res\\objects\\Script\\RadMath2.dll");
if (MathDLLHandle==0)
MathDLLHandle = iDLLLoad(".\\3DRad_res\\objects\\Script\\RadMath.dll");
iMouseLookSet(0, 0);
iMouseLookSpeedSet(lookSpeedY, lookSpeedX);
} else if (iDeinitializing()) {
if (MathDLLHandle != 0) iDLLUnload(MathDLLHandle);
} else if (MathDLLHandle != 0) {
iObjectOrientation(objCam, qCam);
iObjectOrientation(objCar, qCar);
mouseLook2D();
float a;
moveDirection(); // if so, updates moveAngle
steerToCamVec();
OUT_23= (moving ? (isBehind ? -5 : 5) : 0); // throttle
OUT_24= (moving ? 0 : 1); // brakes
}
}
///
float dist= 4; // objCam distance from objCar. Initial zoom level
float mouseX=0, mouseY=0; // for motion smoothing
void mouseLook2D() {
// camera zoom control. Scroll wheel & PgUp/PgDn
float mz= (iMouseZ(true));
if (mz<0) dist/= wheelFactor*zStep; else if (mz>1) dist*= wheelFactor*zStep;
if (iKeyDown(iKeyCode(dikZoomIn))) dist*= zStep;
if (iKeyDown(iKeyCode(dikZoomOut))) dist/= zStep;
mouseX= fInterpolate(iMouseLookX(), mouseX, lookSmoothY); // up/down, obviously
mouseY= fInterpolate(iMouseLookY(), mouseY, lookSmoothX); // left/right
qCam= qEulers(mouseX, mouseY, 0);
setQuat(objCam, qCam);
setLoc(objCam, getLoc(objCar) + dist*vecRot(qCam, Vector3(0,0.5,-1)));
}
float revAngle= 60; // go in reverse if car's rear vector is within this many degrees of desired heading. 0-180
///
void steerToCamVec() {
float s= yAngle(qDelta(qCar, qCam));
float rDir= degFix((degFix(moveAngle)-degFix(s)));
s= degFix(s - moveAngle);
if (newBeginning) isBehind= iFloatAbs(rDir)>(180-revAngle);
if (isBehind) s= sign(s)*(180-iFloatAbs(s));
setSteering(s);
}
float degFix(float a) {while (a<-180) a+=360; while (a>180) a-=360; return a;}
float RelativeSpeed() {
Vector3 SpeedVec, LocalZVec;
iObjectVelocity(objCar, SpeedVec);
iVectorRotate(LocalZVec, Vector3(0,0,1), qCar);
return iVectorDot(LocalZVec, SpeedVec);
}
float steerPos=0;
void setSteering(float f) {
float d= f-steerPos, s= turnRate/iFrameRate(false);
if (iFloatAbs(d)>s) d= s*sign(d);
steerPos+= d;
OUT_22= steerPos/IN_23;
}
float fInterpolate(float f1, float f2, float f2p) {return (1-f2p)*f1 + f2p*f2;}
///
// the brick - shorthand form for nesting expressions
float sign(float f) {return f<0?-1:f>0?1:0;}
float yAngle(Quaternion q) {return yAngle(vecRot(q, Vector3(0,0,1)));}
float yAngle(Vector3 v) {return 57.295779*R_atan2(v.x, v.z);}
Vector3 vecRot(Quaternion q, Vector3 d) {Vector3 r;iVectorRotate(r,d,q);return r;}
Quaternion qMul(Quaternion q1, Quaternion q2) {Quaternion qt;iQuaternionMultiply(qt,q1,q2);return qt;} // q1+q2
Quaternion qDelta(Quaternion q1, Quaternion q2) {return qMul(q1, qInv(q2));} // q1-q2
Quaternion qInv(Quaternion q) {return Quaternion(q.x,q.y,q.z,-q.w);} // -q
Vector3 getLoc(int obj) {Vector3 l; iObjectLocation(obj, l); return l;}
Vector3 setLoc(int obj, Vector3 l) {iObjectLocationSet(obj, l); return l;}
Quaternion getQuat(int obj) {Quaternion q; iObjectOrientation(obj, q); return q;}
Quaternion setQuat(int obj, Quaternion q) {iObjectOrientationSet(obj, q); return q;}
Quaternion qAxisAngle(Vector3 vUp, float dy) {Quaternion q; iQuaternionFromAxisAngle(q, vUp, dy); return q;}
Quaternion qEulers(float x, float y, float z) {Quaternion q;iQuaternionFromEulerAngles(q,x,y,z,"xyz");return q;}
Quaternion qInterpolate(Quaternion q1, Quaternion q2, float q1percent) {Quaternion q;iQuaternionInterpolate(q,q1,q2,q1percent);return q;}
float RelativeSpeed(int obj) {return iVectorDot(vecRot(getQuat(obj), Vector3(0,0,1)), objVelocity(obj));}
Vector3 objVelocity(int obj) {Vector3 SpeedVec;iObjectVelocity(obj, SpeedVec);return SpeedVec;}
float R_atan2(float value1, float value2) { // requires RadMath2.dll. Returns value1 without it
iDLLArraySet(0,value1); iDLLArraySet(1,value2);
iDLLCall(MathDLLHandle,"R_atan2",0);
return iDLLArrayGet(0);
}
Requires RadMath2.dll (zipped courtesy of XingBat)