#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);
        }
}

Reply via email to