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
player.cpp
Line 578
Add any where above "void Player::updateMove(const Move* move)"
Inside "void Player::updateMove(const Move* move)"
Video:
Let me know if you have problems implementing this.
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.
About the author
Riding Solo since 2005. Current Project: Fated World 2005-Present RPG Engine Tool Kit - Now available.
#2
Currently I am using the old 8 way direction resource.
01/19/2010 (4:03 am)
Excellent resource, I will try this one.Currently I am using the old 8 way direction resource.
#3
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/
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/
#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
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.
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
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.
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
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.
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 setTargetObjectfunction 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
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.
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
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?
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
# 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.
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
public member of class Player, then it's works
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
when i added "death" animation, and when player suicide, it crash....
when i debug it, it's from unpackUpdate
in
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);
Torque Owner Sean Rice
HNGamers