Game Development Community

8 Directional Movement

by Kevin Mitchell · in Torque 3D Professional · 01/18/2010 (11:38 pm) · 29 replies

Source Code

This code resource is a guide for implementing my version, of a 8 Directional movement system in T3D.

There are always multiple ways to skin a cat so here's my way.

Step 1 Grab the tail....



player.h

enum {
      // *** WARNING ***
      // These enum values are used to index the ActionAnimationList
      // array instantiated in player.cc
      // The first several are selected in the move state based on velocity

   // *** WARNING ***
   // This array is indexed using the enum values defined in player.h

   // Root is the default animation
   // These are selected in the move state based on velocity
   Root_0,
   Root_45,
   Root_90,
   Root_135,
   Root_180,
   Root_225,
   Root_270,
   Root_315,
   // These are selected in the move state based on velocity
   Run_0,
   Run_45,
   Run_90,
   Run_135,
   Run_180,
   Run_225,
   Run_270,
   Run_315,
   //swim
   SwimRoot_0,
   SwimRoot_45,
   SwimRoot_90,
   SwimRoot_135,
   SwimRoot_180,
   SwimRoot_225,
   SwimRoot_270,
   SwimRoot_315,
   //swim
   Swim_0,
   Swim_45,
   Swim_90,
   Swim_135,
   Swim_180,
   Swim_225,
   Swim_270,
   Swim_315,
   //Crouch
   Crouch_0,
   Crouch_45,
   Crouch_90,
   Crouch_135,
   Crouch_180,
   Crouch_225,
   Crouch_270,
   Crouch_315,
   //Crouch
   CrouchWalk_0,
   CrouchWalk_45,
   CrouchWalk_90,
   CrouchWalk_135,
   CrouchWalk_180,
   CrouchWalk_225,
   CrouchWalk_270,
   CrouchWalk_315,
   //Jump
   Jump_0,
   Jump_45,
   Jump_90,
   Jump_135,
   Jump_180,
   Jump_225,
   Jump_270,
   Jump_315,
   //Fall
   Fall_0,
   Fall_45,
   Fall_90,
   Fall_135,
   Fall_180,
   Fall_225,
   Fall_270,
   Fall_315,
   //Land
   Land_0,
   Land_45,
   Land_90,
   Land_135,
   Land_180,
   Land_225,
   Land_270,
   Land_315,
   //StandJump
   StandJump_0,
   StandJump_45,
   StandJump_90,
   StandJump_135,
   StandJump_180,
   StandJump_225,
   StandJump_270,
   StandJump_315,
   //ProneRoot
   ProneRoot_0,
   ProneRoot_45,
   ProneRoot_90,
   ProneRoot_135,
   ProneRoot_180,
   ProneRoot_225,
   ProneRoot_270,
   ProneRoot_315,
   //ProneWalk
   ProneWalk_0,
   ProneWalk_45,
   ProneWalk_90,
   ProneWalk_135,
   ProneWalk_180,
   ProneWalk_225,
   ProneWalk_270,
   ProneWalk_315,
   //Jet
   Jet_0,
   Jet_45,
   Jet_90,
   Jet_135,
   Jet_180,
   Jet_225,
   Jet_270,
   Jet_315,
      
      // 
      NumMoveActionAnims = Run_315 + 1,
      NumTableActionAnims = Jet_315 + 1,

      NumExtraActionAnims = 512 - NumTableActionAnims,
      NumActionAnims = NumTableActionAnims + NumExtraActionAnims,
      ActionAnimBits = Jet_315,
      NullAnimation = (1 << ActionAnimBits) - 1
   };



player.cpp



...
static F32 sTractionDistance = 0.04f;
static F32 sNormalElasticity = 0.01f;
static U32 sMoveRetryCount = 5;
[b]
//8 DIRECTION ----
F32 YDIR;
F32 XDIR;

F32 PRE_YDIR;
F32 PRE_XDIR;
//8 DIRECTION ----
[/b]
...



// Root is the default animation

//8 DIRECTION ----
	{ "Root_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Root_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Root_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Root_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Root_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Root_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Root_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Root_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	// These are selected in the move state based on velocity
	{ "Run_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Run_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Run_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Run_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Run_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Run_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Run_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Run_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//swimRoot
	{ "SwimRoot_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "SwimRoot_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "SwimRoot_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "SwimRoot_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "SwimRoot_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "SwimRoot_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "SwimRoot_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "SwimRoot_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//swim
	{ "Swim_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Swim_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Swim_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Swim_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Swim_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Swim_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Swim_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Swim_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//Crouch
	{ "Crouch_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Crouch_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Crouch_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Crouch_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Crouch_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Crouch_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Crouch_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Crouch_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//Crouch
	{ "CrouchWalk_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "CrouchWalk_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "CrouchWalk_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "CrouchWalk_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "CrouchWalk_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "CrouchWalk_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "CrouchWalk_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "CrouchWalk_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//Jump
	{ "Jump_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Jump_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Jump_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Jump_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Jump_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Jump_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Jump_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Jump_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//Fall
	{ "Fall_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Fall_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Fall_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Fall_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Fall_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Fall_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Fall_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Fall_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//Land
	{ "Land_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Land_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Land_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Land_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Land_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Land_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Land_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Land_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//StandJump
	{ "StandJump_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "StandJump_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "StandJump_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "StandJump_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "StandJump_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "StandJump_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "StandJump_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "StandJump_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//ProneRoot
	{ "ProneRoot_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "ProneRoot_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "ProneRoot_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "ProneRoot_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "ProneRoot_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "ProneRoot_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "ProneRoot_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "ProneRoot_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//ProneWalk
	{ "ProneWalk_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "ProneWalk_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "ProneWalk_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "ProneWalk_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "ProneWalk_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "ProneWalk_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "ProneWalk_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "ProneWalk_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
	//ProneWalk
	{ "Jet_0",	{ 1.0f, 0.0f, 0.0f } },       // RunForwardAnim,
	{ "Jet_45",	{ 0.707f, 0.707F, 0.0f } },       // BackBackwardAnim
	{ "Jet_90",	{ 0.0f, 1.0f, 0.0f } },       // SideLeftAnim,
	{ "Jet_135",  { -0.707f, 0.707F, 0.0f } },       // RunForwardAnim,
	{ "Jet_180",	{ -1.0f, 0.0f, 0.0f } },       // BackBackwardAnim
	{ "Jet_225",	{ -0.707f, -0.707F, 0.0f } },       // SideLeftAnim,
	{ "Jet_270",  { 0.0f, -1.0f, 0.0f } },       // RunForwardAnim,
	{ "Jet_315",  { 0.707f, -0.707F, 0.0f } },       // RunForwardAnim,
};


Line 578
bool PlayerData::isJumpAction(U32 action)
{
	return ((action >= Jump_0 && action <= Jump_315) || (action >= StandJump_0 && action <= StandJump_315));
}


void Player::setState(ActionState state, U32 recoverTicks)
{
	if (state != mState) {
		// Skip initialization if there is no manager, the state
		// will get reset when the object is added to a manager.
		if (isProperlyAdded()) {
			switch (state) {
			case RecoverState: {
				mRecoverTicks = recoverTicks;
				mReversePending = U32(F32(mRecoverTicks) / sLandReverseScale); 
				// Our feet are on something
				// Pick animation that is the best fit for our current velocity.
				// Assumes that root is the first animation in the list.
				VectorF vel;
				mWorldToObj.mulV(mVelocity,&vel);
				for (U32 i = PlayerData::Land_0; i < PlayerData::Land_315+1; i++)
				{
					PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
					if (anim.sequence != -1 && anim.speed) 
					{
						if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
							setActionThread(i, true, false, true, true);
							break;
						}
					}
				}


				break;
				}

			default:
				break;
			}
		}

		mState = state;
	}
}


Add any where above "void Player::updateMove(const Move* move)"


float CalcTheta( const Point3F Point1, const Point3F Point2 )
{
	float Theta;
	if ( Point2.x - Point1.x == 0 ){
		if ( Point2.y > Point1.y ){
			Theta = 0;
		}else{
			Theta = static_cast<float>( M_PI_F );
		}
	}else{
		Theta = std::atan( (Point2.y - Point1.y) / (Point2.x - Point1.x) );
		if ( Point2.x > Point1.x ){
			Theta = static_cast<float>( M_PI_F ) / 2.0f - Theta;
		}else{
			Theta = static_cast<float>( M_PI_F ) * 1.5f - Theta;
		}
	}
	return Theta;
}

Inside "void Player::updateMove(const Move* move)"
if (mState == MoveState && mDamageState == Enabled)
	{
		zRot.getColumn(0,&moveVec);
		moveVec *= move->x;
		VectorF tv;
		zRot.getColumn(1,&tv);
		moveVec += tv * move->y;

		//Con::printf("movex: %g  movey: %g movez: %g",move->x,move->y,move->z);
		//if(move->y!=0||move->x!=0){
		Point3F Point1;
		Point3F Point2;
		F32 DIR_ANGLE;
		Point1.x=10;
		Point1.y=10;
		Point1.z=0;
		Point2.x=10+(move->y);
		Point2.y=10+move->x;
		Point2.z=0;
		DIR_ANGLE = (CalcTheta(Point1,Point2)*180)/M_PI_F;
		//Con::printf("degree: %g rad: %g",(CalcTheta(Point1,Point2)*180)/M_PI_F,CalcTheta(Point1,Point2));
		YDIR=move->y;
		XDIR=move->x;
		if(move->y!=0||move->x!=0){
			if(DIR_ANGLE<22.5 || DIR_ANGLE>=337.5){//0
				YDIR=0;
				XDIR=1;
			}else if(DIR_ANGLE<67.5 && DIR_ANGLE>=22.5){//45
				YDIR=0.707f;
				XDIR=0.707f;
			}else if(DIR_ANGLE<112.5 && DIR_ANGLE>=67.5){//90
				YDIR=1;
				XDIR=0;
			}else if(DIR_ANGLE<157.5 && DIR_ANGLE>=112.5){//135
				YDIR=0.707f;
				XDIR=-0.707f;
			}else if(DIR_ANGLE<202.5 && DIR_ANGLE>=157.5){//180
				YDIR=0;
				XDIR=-1;
			}else if(DIR_ANGLE<247.5 && DIR_ANGLE>=202.5){//225
				YDIR=-0.707f;
				XDIR=-0.707f;
			}else if(DIR_ANGLE<292.5 && DIR_ANGLE>=247.5){//270
				YDIR=-0;
				XDIR=0;
			}else if(DIR_ANGLE<337.5 && DIR_ANGLE>=292.5){//315
				YDIR=-0.707f;
				XDIR=0.707f;
			}
		}


		//}
		// Clamp water movement


// Cancel any script driven animations if we are going to move.
		if (moveVec.x + moveVec.y + moveVec.z != 0.0f &&
			(mActionAnimation.action >= PlayerData::NumTableActionAnims
			|| (mActionAnimation.action >= PlayerData::Land_0&&mActionAnimation.action <= PlayerData::Land_315)))
			mActionAnimation.action = PlayerData::NullAnimation;
	}


// If we don't have a StandJumpAnim, just play the JumpAnim...
		S32 seq = (mVelocity.len() < 0.5) ? PlayerData::StandJump_0: PlayerData::Jump_0; 
		//if ( mDataBlock->actionList[seq].sequence != -1 ){			
			// Our feet are on something
			// Pick animation that is the best fit for our current velocity.
			// Assumes that root is the first animation in the list.
			VectorF vel;
			F32 dirBased=false;
			if(seq==PlayerData::Jump_0) dirBased=true;
			mWorldToObj.mulV(mVelocity,&vel);
			for (U32 i = seq; i < seq+9; i++)
			{
				PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
				if (anim.sequence != -1 && anim.speed) 
				{
					if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
						seq=i;
						break;
					}
				}
			}
		//}
		setActionThread( seq, true, false, true );


// Can't crouch if no crouch animation!
	if ( mDataBlock->actionList[PlayerData::Crouch_0].sequence == -1 )
		return false;

// Can't go prone if no prone animation!
	if ( mDataBlock->actionList[PlayerData::ProneRoot_0].sequence == -1 )
		return false;

if ( ((mActionAnimation.action >= PlayerData::Land_0)&&(mActionAnimation.action <= PlayerData::Land_315)) &&
		(mActionAnimation.action != PlayerData::NullAnimation) )
	{


void Player::pickActionAnimation()
{
	// Only select animations in our normal move state.
	if (mState != MoveState || mDamageState != Enabled)
		return;

	if (isMounted())
	{
		// Go into root position unless something was set explicitly
		// from a script.
		if (((mActionAnimation.action >= PlayerData::Root_0)&&(mActionAnimation.action <= PlayerData::Root_315)) &&
			mActionAnimation.action < PlayerData::NumTableActionAnims){
				// Our feet are on something
				// Pick animation that is the best fit for our current velocity.
				// Assumes that root is the first animation in the list.
				VectorF vel;
				mWorldToObj.mulV(mVelocity,&vel);
				for (U32 i = PlayerData::Root_0; i < PlayerData::Root_315+1; i++)
				{
					PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
					if (anim.sequence != -1 && anim.speed) 
					{
						if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
							setActionThread(i, true, false, false);
							break;
						}
					}
				}
		}
		return;
	}

	bool forward = true;
	U32 action = PlayerData::Root_90;
	bool fsp = false;

	// Jetting overrides the fall animation condition
	if (mJetting)
	{
		// Play the jetting animation
		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		VectorF vel;
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::Swim_90; i <= PlayerData::Swim_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(XDIR!=0||YDIR!=0){
					if(anim.dir.x==XDIR && anim.dir.y==YDIR){
						PRE_XDIR=XDIR;
						PRE_YDIR=YDIR;
						action = i;
						forward = true;
						break;
					}
				}else if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
					action = i;
					forward = true;
					break;
				}
			}
		}
	}
	else if (mFalling)
	{
		// Not in contact with any surface and falling		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		VectorF vel;
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::Fall_90; i <= PlayerData::Fall_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(XDIR!=0||YDIR!=0){
					if(anim.dir.x==XDIR && anim.dir.y==YDIR){
						PRE_XDIR=XDIR;
						PRE_YDIR=YDIR;
						action = i;
						forward = true;
						break;
					}
				}else if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
					action = i;
					forward = true;
					break;
				}
			}
		}
	}
	else if ( mSwimming )
	{
		action = PlayerData::SwimRoot_90;

		VectorF vel;

		for (U32 i = PlayerData::SwimRoot_0; i < PlayerData::SwimRoot_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				// We bias towards picking the forward/backward anims over
				// the side to prevent oscillation between anims.  This seems 
				// to work ok but the real fix is to have 8 way directional 
				// animations.
				/*VectorF biasedDir = anim.dir * VectorF(0.5f,1.0f,0.5f);*/

				if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
					action = i;
					forward = true;
					break;
				}
			}
		}



		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::Swim_90; i <= PlayerData::Swim_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(anim.dir.x==XDIR && anim.dir.y==YDIR){
					if(XDIR!=0||YDIR!=0){
						PRE_XDIR=XDIR;
						PRE_YDIR=YDIR;
					}
					action = i;
					forward = true;
					break;
				}
			}
		}
	}
	else if ( mPose == StandPose )
	{
		if (mContactTimer >= sContactTickTime) {
			// Nothing under our feet
			action = PlayerData::Root_90;

			// Our feet are on something
			// Pick animation that is the best fit for our current velocity.
			// Assumes that root is the first animation in the list.
			VectorF vel;
			mWorldToObj.mulV(mVelocity,&vel);
			for (U32 i = PlayerData::Root_0; i < PlayerData::Root_315+1; i++)
			{
				PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
				if (anim.sequence != -1 && anim.speed) 
				{
					if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
						action = i;
						forward = true;
						break;
					}
				}
			}
		}
		else
		{

			action = PlayerData::Root_90;

			// Our feet are on something
			// Pick animation that is the best fit for our current velocity.
			// Assumes that root is the first animation in the list.
			VectorF vel;
			mWorldToObj.mulV(mVelocity,&vel);
			for (U32 i = PlayerData::Root_0; i < PlayerData::Root_315+1; i++)
			{
				PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
				if (anim.sequence != -1 && anim.speed) 
				{
					if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
						action = i;
						forward = true;
						break;
					}
				}
			}
			// Our feet are on something
			// Pick animation that is the best fit for our current velocity.
			// Assumes that root is the first animation in the list.
			mWorldToObj.mulV(mVelocity,&vel);
			for (U32 i = PlayerData::Run_0; i < PlayerData::Run_315+1; i++)
			{
				PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
				if (anim.sequence != -1 && anim.speed) 
				{
					if(anim.dir.x==XDIR && anim.dir.y==YDIR){
						if(XDIR!=0||YDIR!=0){
							PRE_XDIR=XDIR;
							PRE_YDIR=YDIR;
						}
						action = i;
						forward = true;
						break;
					}
				}
			}
		}
	}
	else if ( mPose == CrouchPose )
	{
		VectorF vel;
		mWorldToObj.mulV(mVelocity,&vel);

		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::Crouch_0; i < PlayerData::Crouch_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
					action = i;
					forward = true;
					break;
				}
			}
		}


		fsp = true;

		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::CrouchWalk_0; i < PlayerData::CrouchWalk_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(anim.dir.x==XDIR && anim.dir.y==YDIR){
					if(XDIR!=0||YDIR!=0){
						PRE_XDIR=XDIR;
						PRE_YDIR=YDIR;
					}
					action = i;
					forward = true;
					break;
				}
			}
		}
	}
	else if ( mPose == PronePose )
	{
		VectorF vel;
		mWorldToObj.mulV(mVelocity,&vel);

		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::ProneRoot_0; i < PlayerData::ProneRoot_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(anim.dir.x==PRE_XDIR && anim.dir.y==PRE_YDIR){
					action = i;
					forward = true;
					break;
				}
			}
		}



		fsp = true;

		// Our feet are on something
		// Pick animation that is the best fit for our current velocity.
		// Assumes that root is the first animation in the list.
		mWorldToObj.mulV(mVelocity,&vel);
		for (U32 i = PlayerData::ProneWalk_0; i < PlayerData::ProneWalk_315+1; i++)
		{
			PlayerData::ActionAnimation &anim = mDataBlock->actionList[i];
			if (anim.sequence != -1 && anim.speed) 
			{
				if(anim.dir.x==XDIR && anim.dir.y==YDIR){
					if(XDIR!=0||YDIR!=0){
						PRE_XDIR=XDIR;
						PRE_YDIR=YDIR;
					}
					action = i;
					forward = true;
					break;
				}
			}
		}
	}
	setActionThread(action,forward,false,false,fsp);
}


void Player::onUnmount( ShapeBase *obj, S32 node )
{
	// Reset back to root position during dismount.
	setActionThread(PlayerData::Root_90,true,false,false);

	// Re-orient the player straight up
	Point3F pos,vec;
	getTransform().getColumn(1,&vec);
	getTransform().getColumn(3,&pos);
	Point3F rot(0.0f,0.0f,-mAtan2(-vec.x,vec.y));
	setPosition(pos,rot);

	// Parent function will call script
	Parent::onUnmount( obj, node );
}






Video:






Let me know if you have problems implementing this.
Page «Previous 1 2
#1
01/19/2010 (2:38 am)
Awesome, I will throw these into the Tori model :p
#2
01/19/2010 (4:03 am)
Excellent resource, I will try this one.
Currently I am using the old 8 way direction resource.
#3
01/19/2010 (5:26 am)
ok, but I think that you can have a speed problem, because your move vectors on the 45, 135, 225, 315 angles are longer than the others : 1.414 length (sqrt(2)) rather than 1 unit.

I don't know if the engine normalize this directional vector, but if it doesn't, you will move 1.414 times more in your 45, 135,… angles than at 0, 90, 180 and 270 angles.

To correct this, your vector components should be (0.71, 0.71,0) for instance.

Nicolas Buquet
www.buquet-net.com/cv/
#4
01/19/2010 (7:52 am)
Forgot about that. Let me try that and see if i see a difference.

#5
01/19/2010 (8:01 am)
Ah, this is separate from the movement. This is only used to choose what model to select for the angle of the current move direction. But that math will be duly noted. I believe it will become a factor when i add in more calculations of the joy stick.
#6
01/19/2010 (9:57 am)
Wait... you have one animation for each one of the 8 directions the character can be facing? Why not just rotate the character to face that direction instead? More or less like the camera-relative movement resource did.
#7
01/19/2010 (10:19 am)
Thats what I've been trying to do fir the last two weeks. I found that the players camera is liked to the players rotation so if you rotate one you rotate the other. I've tried the advance camera source but it did not seem to work at all at the end. I have not given up on a better solution this is only a temp fix. I want to get a feel for my games movement.

Also if you know how to fix a conobject error I'd really appreciate it. I've followed the exact flow for camera variable declarations and I still get an error when trying to make an instance of advance cam. Any information on this would help.
#8
01/19/2010 (12:47 pm)
Not terribly helpful here but I'll second that the camera is now directly linked to the control object. I had an attempt to unlink it - like it was back in TGE1.5.2 - but just baffled myself. (which sometimes doesn't take too much effort!)
#9
01/19/2010 (1:04 pm)
Steve you seem to help in ever problem u have. I didn't think of code reverting. Hmm let me see how camera and player operated in TGEA 1.7 I know advanced came worked then and that was a T3D shell
#10
01/19/2010 (1:33 pm)
I know that in my TGE demo (cos I tried it), I can split the control object and the camera independantly - cos that's really how it comes and the spawn script in game.cs is where they get linked together. Thus you can control your player from a 3rd person view ... which is weird! In T3D it appears to "autolinked", so I'd guess that it's now hardcoded that way.

I had looked into it because of this thread here but in the end decided to "bugger this for a game of monkies" and just found a different way to get the same sort of effect without using changing cameras or controlobjects.
#11
01/19/2010 (11:21 pm)
Steve I'm going to work harder to get this working in a better more efficient way. You gave me some good idea's I'm about to look into this.
#12
01/20/2010 (1:32 am)
So ive been trying to figure out how to use the T3D cameras that are simular to the advanced camera. In it i see a setMode and setTargetObject

function serverCmdSetEditorOrbitCamera(%client)
{
   %client.camera.setEditOrbitMode();
   %client.camera.setMode(6,0,"TrackObject");
   %client.setControlObject(%client.camera);
   %client.camera.setTrackObject(%client.player, "4 4 4");
   clientCmdSyncEditorGui();
}

When i tried this the camera moved and looked at the target so i might be able to use this and link in the control to the player and then have what i desire.
#13
01/22/2010 (6:43 am)
I'm going to attempt to make a new camera based off orbit that can still control the character. Since its the character that has to be there and the Camera it's self is created at start. I can switch to the camera and pas calls to update the players movement. This should work in theory but I can not work on this this week end because I have 2 projects, 2 midterms, and 8 Postings to do. ... Curse you Devry.
#14
01/23/2010 (2:52 pm)
%client.setCameraObject() works as it should in T3D. The GameConnection class has distinct ControlObject and CameraObject objects. However, you must make sure the GameConnection isn't in first person mode, otherwise the ControlObject will be used as the Camera.

Then all you need is to setup the camera in orbit mode around your player and set it to locked so it doesn't use the mouse input to rotate. You can get this far without any source code changes.

I even think it might be possible to use some clever scripting in the control binding to make a "character turns to face the direction I'm moving to" instead of strafing by checking the ghost's transform and calculating a yaw value that turns it into the desired position in the functions bound to the WASD/arrow keys.
#15
01/23/2010 (3:35 pm)
I'll try this after the mid term
#16
02/19/2010 (3:32 am)
i was implement this code,
but something weird happens when playing in multiplayer,
the other player is controlled by me !!!
also in my screen the other player do the animation, but in other players screen both of us was gliding, did not play the animation just change the orientation

is there a way to make this resource can be played in multiplayer normally?
#17
02/19/2010 (5:14 pm)
Yep try making:

# F32 YDIR;
# F32 XDIR;
#
# F32 PRE_YDIR;
# F32 PRE_XDIR;

public to the mDataBlock or some other server object, and store the variables inside that.
#18
02/22/2010 (11:44 pm)
thanks, i was just place it to player.h in
public member of class Player, then it's works
#19
02/23/2010 (7:10 am)
Cool congrats, I'll be sure to make my other changes more multi-player friendly.
#20
04/09/2010 (3:53 am)
i've found something strange.
when i added "death" animation, and when player suicide, it crash....

when i debug it, it's from unpackUpdate
in
U32 action = stream->readInt(PlayerData::ActionAnimBits);
Page «Previous 1 2