Jump to content

Shooter Style Third Person Camera Orientated Movement


Steve_Yorkshire

Recommended Posts

Disclaimer: I haven't actually played GTA or Elden Ring so I've never actually experienced the camera and movement control system. But anyway - here's what I think it's like (probably). 😅 UPDATE: this camera and movement style is really more relevant to a 3rd person shooter.

This is a movement test based on third person camera direction, kind of like what I did top-down for Monsters Loot Swag but the camera remains fixed to the player rather than being independant - because of that I had apply inverse rotation to the camera when the player moved and turned to face the camera's original vector.

Horizontal camera rotation wraps around -/+M_PI_F rather than being constrained by the stock engine's playerDatablock maxFreeLook value, this means that the camera can loop seamlessly around the player using z axis but is still constrained to maximums when looking up and down, so it doesn't flip upside-down.

Code: Player.cpp, in UpdateMove(const Move* move)

void Player::updateMove(const Move* move)
{
  //...
           setImageAltTriggerState( 0, move->trigger[sImageTrigger1] );
   }

   //yorks
   F32 camZ = 0.0f;
   GameConnection* con = getControllingClient();
   bool thirdP = false;
   if (con && !con->isFirstPerson())
   {
      thirdP = true;
   }//yorks end

   // Update current orientation
   if (mDamageState == Enabled) {
      F32 prevZRot = mRot.z;
	  mDelta.headVec = mHead;

      bool doStandardMove = true;
      bool absoluteDelta = false;
      //GameConnection* con = getControllingClient();//yorks out and moved above so we can get this below too


#ifdef TORQUE_EXTENDED_MOVE
  //...
        if (doStandardMove)
      {
         F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f);
         if (p > M_PI_F) 
            p -= M_2PI_F;
         //mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
                          // mDataBlock->maxLookAngle);

         F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f);
         if (y > M_PI_F)
            y -= M_2PI_F;

         //yorks start
         //if (((move->freeLook && isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))//out
         if (thirdP)//from above
         {
            //yorks moved down here
            mHead.x = mClampF(mHead.x + (p * 0.5f), mDataBlock->minLookAngle, mDataBlock->maxLookAngle);//yorks added 0.5f to slow p down a bit

            //let us run the camera around in a big old never ending circle
            F32 camRot = mHead.z + (y * 0.5f);//slow y down a bit, techincally you should do this input script mouse sensitivity, also see p above
            //constrain the range of camRot within pi*2
            camRot = mWrapF(camRot, 0.0f, M_2PI_F);//yorks use the new method
            mHead.z = camRot;
            // mHead.z = mClampF(mHead.z + y,
                              // -mDataBlock->maxFreelookAngle,
                              // mDataBlock->maxFreelookAngle);
         }
         else
         {//yorks end block
            mHead.x = mClampF(mHead.x + p, mDataBlock->minLookAngle, mDataBlock->maxLookAngle);//yorks moved down here for normal cam/move mode

            mRot.z += y;
            // Rotate the head back to the front, center horizontal
            // as well if we're controlling another object.
            mHead.z *= 0.5f;
            if (mControlObject)
               mHead.x *= 0.5f;
         }//yorks added

         // constrain the range of mRot.z
         while (mRot.z < 0.0f)
            mRot.z += M_2PI_F;
         while (mRot.z > M_2PI_F)
            mRot.z -= M_2PI_F;
      }
     //...
     if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled && !isAnimationLocked())
   {
      if (thirdP)//yorks start big in
      {
         GameBase* cam = con->getCameraObject();
         if (cam)
         {
            //get the camera's transform
            F32 pos = 1; MatrixF camTrans;
            cam->getCameraTransform(&pos, &camTrans);

            //flatten the transform to X&Y (so when the camera
            //is facing up/down the move remains horizontal)
            camTrans[9] = 0;
            camTrans.normalize();

            //create a move vector and multiply by the camera transform
            VectorF temp(move->x, move->y, 0);
            camTrans.mulV(temp, &moveVec);

            // get the z rotation of the camera for working with right stick aiming
            camZ = camTrans.toEuler().z;
            if (camZ < 0.0f)
               camZ += M_2PI_F;

            //Con::printf("Camz %f", camZ);

            // Constrain the range of camZ within pi*2
            camZ = mWrapF(camZ, 0.0f, M_2PI_F);//yorks use the new method

            if ((!mIsZero(move->y)) || (!mIsZero(move->x)))
            {
               //we are moving and so should turn the player towards the direction that the camera is facing
               Point3F transVec = getTransform().getForwardVector();

               F32 tran = mAtan2(transVec.x, transVec.y);
               if (tran < 0.0f)
                  tran += M_2PI_F;

               mWrapF(tran, 0.0f, M_2PI_F);

               F32 yawDiff = camZ - tran;

               //Con::printf("camToDir %f; tran %f; yawDiff %f", dir, tran, yawDiff);

               //ignore very small rotations
               if (mFabs(yawDiff) < 0.005f && mFabs(yawDiff) > -0.005f)//yorks now less than a third of 1 degree//0.001f)//
                  yawDiff = 0.0f;

               if (!mIsZero(yawDiff))
               {
                  //Con::printf("yawDiff %f", yawDiff);
                  // now make sure we take the short way around the circle
                 if (yawDiff > M_PI_F)
                     yawDiff -= M_2PI_F;
                  else if (yawDiff < -M_PI_F)
                     yawDiff += M_2PI_F;
                 
                  F32 slower;//slower exists to slow the turn down otherwise it's instantaneous
                  slower = 0.15f;

                  mRot.z += yawDiff * slower;
                  mHead.z -= yawDiff * slower;//the camera is still attached to the player so we need to compensate for the player's new rotation
               }
            }
         }
      }//yorks end big in

         zRot.getColumn(0, &moveVec);
         moveVec *= (move->x * (mPose == SprintPose ? mDataBlock->sprintStrafeScale : 1.0f));
         VectorF tv;
         zRot.getColumn(1, &tv);
         moveVec += tv * move->y;

         // Clamp water movement
         if (move->y > 0.0f)
       //...

And there you go, that should be it. In 3rd person view and ONLY 3rd person view you can rotate the camera horizontally around the player without it stopping at maxLook and movement is tied to the camera view, so that the player will reorientate himself to that when moving.

This could be expanded by adding a lock-on feature to have the camera point constantly at the selected enemy, and also maybe add a toggle that allows the player to move relative to the camera but without turning to face the camera's vector.

Hope this helps some folks.

Edited by Steve_Yorkshire
Link to comment
Share on other sites

Games with third person view usually do not let you look around freely by default, the camera is more or less locked in place. Some games have like a delay where the camera gradually follows the movement direction, or moves around a little, so it feels more like a free view. Playing with an actually fully free view can get very confusing. You should play some games with it for reference or look at lets play videos. I have not played Elden Ring but from a lets play video it seems like free view but the camera automatically slowly assigns itself again to the player direction, but from just watching it you cannot fully tell how it actually works, what is manual and what automatic. I played GTA however and the third person is usually fixed, but there is a freeview feature for when you are in a vehicle, because in a drive by shooting your drive in one direction but look and shoot in another direction, which is where the free view comes in.

In your case I think your top down game would benefit from some slight variations of the camera angle to show off that it is all fully 3D.

Link to comment
Share on other sites

  • Steve_Yorkshire changed the title to Shooter Style Third Person Camera Orientated Movement

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...