#include"project.h"
#include"FollowBehindController.h"
#include "Game.h"
#include "Position.h"
#include "GamepadDirector.h"
#include "Character.h"
#define HOR_DISTANCE 450.0f
#define ANGLULAR_VELOCITY 180.0f
#define VER_DISTANCE 200.0f
#define VERT_ANGU_VELOCITY 100.0f
#define COLLISION_SPHERE_SIZE 30.0f
FollowBehindController::FollowBehindController()
{
mFirstProcess = true;
mVAngle = 0.0f;
mTargetFOV = mFOV = 75.0f;
setMaxDistance(10000.0f);
setMinDistance(50.0f);
setDesiredDistance(5000.0f);
//setCameraParams(45, f32 envNear, f32 envFar, f32 clipNear, f32 clipFar );
setTrackParams(true, true, false, false);
//void setFogParams(f32 fogRed, f32 fogGreen, f32 fogBlue, f32 fogNear, f32
fogFar);
setMaxVertAngle(90.0f);
setHorizontalOffset(0);
setFloatingOffset(0);
setFloatingUpLimit(0);
setFloatingDownLimit(0);
}
FollowBehindController::~FollowBehindController()
{
}
void FollowBehindController::control(f32 deltaTime)
{
mDeltaTime = deltaTime;
if( mFirstProcess )
{
mFirstProcess = false;
reset();
}
calculateHorizontal();
calculateVertical();
calculateController();
calculateHorizontal();
worldCollision();
PivotController::control(deltaTime);
mOldPosition = mPosition;
}
void FollowBehindController::reset()
{
goMatrix m;
goVector3 v;
goMatrixIdentity(&m);
m.position = mTarget;
goVector3Scale(&v, &m.yAxis, HOR_DISTANCE);
goVector3Add(&m.position, &mTarget, &v);
m.position.z += VER_DISTANCE;
setPosition(m.position.x, m.position.y, m.position.z);
setForward(m.yAxis.x, m.yAxis.y, m.yAxis.z);
mOldPosition = mPosition;
}
void FollowBehindController::calculateHorizontal()
{
goVector3 vectorToTarget;
goVector3 delta;
goVector3 pos;
f32 distance;
goVector3Sub(&vectorToTarget, &mTarget, &mPosition);
// vectorToTarget.z = 0.0f;
distance = goVector3Magnitude(&vectorToTarget);
if( distance != 0.0f )
{
pos = mPosition;
goVector3Normalize(&vectorToTarget, &vectorToTarget);
goVector3Scale(&delta, &vectorToTarget, (HOR_DISTANCE - distance));
goVector3Sub(&pos, &pos, &delta);
setPosition(pos.x, pos.y, pos.z);
setForward(vectorToTarget.x, vectorToTarget.y, vectorToTarget.z);
}
}
void FollowBehindController::calculateVertical()
{
setPosition(mPosition.x, mPosition.y, mTarget.z );
}
void FollowBehindController::calculateController()
{
if( mDeltaTime == 0.0f )
return;
goVector3 vectorFromTarget;
goVector3 pos = mPosition;
goVector3 up = { 0, 0, 1 };
f32 a = goInputGetAnalog(GamepadDirector::getActivePad(), goINPUT_RSTICKX);
f32 b = goInputGetAnalog(GamepadDirector::getActivePad(), goINPUT_RSTICKY);
goVector3Sub(&vectorFromTarget, &mPosition, &mTarget);
f32 distance = goVector3Magnitude(&vectorFromTarget);
if( distance != 0.0f )
{
mVAngle += b * VERT_ANGU_VELOCITY * mDeltaTime;
f32 maxVAngle = 80.0f;
f32 minVAngle = -80.0f;
if( mVAngle > maxVAngle )
{
mVAngle = maxVAngle;
}
if( mVAngle < minVAngle )
{
mVAngle = minVAngle;
}
goVector3Normalize(&vectorFromTarget, &vectorFromTarget);
goMatrix m;
goMatrixIdentity(&m);
goVector3 zAxis = { 0, 0, 1 };
goVector3 crossAxis;
m.yAxis = vectorFromTarget;
goVector3Cross(&crossAxis, &vectorFromTarget, &zAxis);
if( goVector3Normalize(&crossAxis, &crossAxis) )
{
goMatrixRotateAxis(&m, &crossAxis, mVAngle);
}
goMatrixRotateAxis(&m, &zAxis, a * ANGLULAR_VELOCITY * mDeltaTime);
goVector3Scale(&vectorFromTarget, &m.yAxis, distance);
goVector3Add(&pos, &mTarget, &vectorFromTarget);
setPosition(pos.x, pos.y, pos.z);
}
}
void FollowBehindController::worldCollision()
{
s32 numCollisions = 0;
// get movement
goVector3 startPos = mTarget;
goVector3 endPos = mPosition;
goIsectResult results[goMAX_ISECT_SLIDE_RECURSION];
// Calculate a bounding sphere that envelopes both start and end spheres.
-Shane
goBSphere sphere;
goVector3 spherePos;
f32 radius;
goVector3Sub( &spherePos, &endPos, &startPos );
// Relative vector from start to end.
goVector3Scale( &spherePos, &spherePos, 0.5f );
// Midpoint between start and end.
radius = goVector3Magnitude( &spherePos ) + COLLISION_SPHERE_SIZE; //
Radius envelopes both points.
goVector3Add( &spherePos, &startPos, &spherePos );
// Add midpoint to start for world pos.
goBSphereSet(&sphere, spherePos.x, spherePos.y, spherePos.z, radius );
goCollisionListClear(Game::sCollisionList);
goOctreeCollisionListBSphere(Game::sCurOctree, &sphere, Game::sCollisionList);
// grab dynamic collision too
Game::sSceneState->flags |= goSCENE_FLAG_ISECT_SPHERE;
Game::sSceneState->isectSphere = sphere;
Game::sSceneState->colList = Game::sCollisionList;
goSceneISect(Game::sScene, Game::sSceneState);
u32 collisionFlags = CF_CHARACTER_COLLIDABLE;
numCollisions = goCollisionIsectSphere(Game::sCollisionList, &startPos,
&endPos, COLLISION_SPHERE_SIZE, false, 0, false, 0, collisionFlags, results, 0);
f32 distance = goVector3Distance(&endPos, &startPos);
f32 tooCloseDistance = 125.0f;
f32 raiseAmount = 200.0f;
if ( distance < tooCloseDistance )
{
endPos.z += raiseAmount * ( 1.0f - distance / tooCloseDistance);
}
setPosition(endPos.x, endPos.y, endPos.z);
goVector3 vectorToTarget;
goVector3Sub(&vectorToTarget, &mTarget, &mPosition);
if( goVector3Normalize(&vectorToTarget, &vectorToTarget) )
{
setForward(vectorToTarget.x, vectorToTarget.y, vectorToTarget.z);
}
}