Jump to content

Elden Ring/GTA Third Person Free Camera With ScreenSpace Movement


Steve_Yorkshire

Recommended Posts

After my previous Third Person camera movement system which I have edited to label as a shooter style, I decided to expand it and make an actual Elden Ring/GTA/Sleeping Dogs (the last one I actually have played) style third person free camera with screenSpace based movement input; eg: move left makes the player move screen left. The player also turns to face the direction that they are moving in. In the video this is exaggerated by having side and backwards speed set very low and forward speed set very high. Standard code of Move->x and Move->y are not taken into account and movement speed is based purely on player datablock move speeds and I didn't include "prone" as a pose.

void Player::updateMove(const Move* move)
{
   struct Move my_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) {
     
     //...
     
     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);//yorks out

         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())))
         if (thirdP)//
         {
               //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
               /*if (camRot > M_PI_F)
                  camRot -= M_2PI_F;
               else if (camRot < -M_PI_F)
                  camRot += M_2PI_F;*/
               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);//yorks end
         }
         else
         {
            //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

            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;
         }
      }
     
     //...
     
     if ((mState == MoveState || (mState == RecoverState && mDataBlock->recoverRunForceScale > 0.0f)) && mDamageState == Enabled && !isAnimationLocked())
   {
      F32 yawDiff = 0.0f;
      if (thirdP)
      {
         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)))
            {
                // This is make the player turn towards the direction that they are moving
               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 moveDir = mAtan2(getVelocity().x, getVelocity().y);//it's the x and y of player velocity we want
               if(moveDir < 0.0f)
                  moveDir += M_2PI_F;

               yawDiff = moveDir - tran;

               //Con::printf("moveDir %f; tran %f; yawDiff %f", moveDir, 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))
               {
                  // 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
                  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
               }
            }
         }
      }

      if (thirdP)//yorks this is broken up a bit for debug testing
      {
         //get facing movement direction as yawDiff
         F32 dirSpeed = 0.0f;
  
         if (yawDiff < 0.785f)//0-45deg
         {
            if (mSwimming)
               dirSpeed = mDataBlock->maxUnderwaterForwardSpeed;
            else if (mPose == CrouchPose)
               dirSpeed = mDataBlock->maxCrouchForwardSpeed;
            else if (mPose == SprintPose)
               dirSpeed = mDataBlock->maxSprintForwardSpeed;
            else
               dirSpeed = mDataBlock->maxForwardSpeed;
            //Con::printf("forward 0-0.785; %f", yawDiff);
         }
         else if (yawDiff > 5.497f)//315-360deg
         {
            if (mSwimming)
               dirSpeed = mDataBlock->maxUnderwaterForwardSpeed;
            else if (mPose == CrouchPose)
               dirSpeed = mDataBlock->maxCrouchForwardSpeed;
            else if (mPose == SprintPose)
               dirSpeed = mDataBlock->maxSprintForwardSpeed;
            else
               dirSpeed = mDataBlock->maxForwardSpeed;
            //Con::printf("forward 5.497-6.283; %f", yawDiff);
         }
         else if (yawDiff > 0.784f && yawDiff < 2.356f)
         {
            if (mSwimming)
               dirSpeed = mDataBlock->maxUnderwaterSideSpeed;
            else if (mPose == CrouchPose)
               dirSpeed = mDataBlock->maxCrouchSideSpeed;
            else if (mPose == SprintPose)
               dirSpeed = mDataBlock->maxSprintSideSpeed;
            else
               dirSpeed = mDataBlock->maxSideSpeed;
            //Con::printf("side right 0.784-2.356; %f", yawDiff);
         }
         else if(yawDiff < 5.496f && yawDiff > 3.926f)
         {
            if (mSwimming)
               dirSpeed = mDataBlock->maxUnderwaterSideSpeed;
            else if (mPose == CrouchPose)
               dirSpeed = mDataBlock->maxCrouchSideSpeed;
            else if (mPose == SprintPose)
               dirSpeed = mDataBlock->maxSprintSideSpeed;
            else
               dirSpeed = mDataBlock->maxSideSpeed;
            //Con::printf("side left 3.926-5.496; %f", yawDiff);
         }
         else
         {
            if (mSwimming)
               dirSpeed = mDataBlock->maxUnderwaterBackwardSpeed;
            else if (mPose == CrouchPose)
               dirSpeed = mDataBlock->maxCrouchBackwardSpeed;
            else if (mPose == SprintPose)
               dirSpeed = mDataBlock->maxSprintBackwardSpeed;
            else
               dirSpeed = mDataBlock->maxBackwardSpeed;
            //Con::printf("back 2.356-5.496; %f", yawDiff);
         }
         moveSpeed = dirSpeed;
      }
      else
      {
        //move the first person standard movement here - yorks
         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)
         {
            if (mSwimming)
               moveSpeed = getMax(mDataBlock->maxUnderwaterForwardSpeed * move->y,
                  mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
            else if (mPose == PronePose)
               moveSpeed = getMax(mDataBlock->maxProneForwardSpeed * move->y,
                  mDataBlock->maxProneSideSpeed * mFabs(move->x));
            else if (mPose == CrouchPose)
               moveSpeed = getMax(mDataBlock->maxCrouchForwardSpeed * move->y,
                  mDataBlock->maxCrouchSideSpeed * mFabs(move->x));
            else if (mPose == SprintPose)
               moveSpeed = getMax(mDataBlock->maxSprintForwardSpeed * move->y,
                  mDataBlock->maxSprintSideSpeed * mFabs(move->x));
            else // StandPose
               moveSpeed = getMax(mDataBlock->maxForwardSpeed * move->y,
                  mDataBlock->maxSideSpeed * mFabs(move->x));
         }
         else
         {
            if (mSwimming)
               moveSpeed = getMax(mDataBlock->maxUnderwaterBackwardSpeed * mFabs(move->y),
                  mDataBlock->maxUnderwaterSideSpeed * mFabs(move->x));
            else if (mPose == PronePose)
               moveSpeed = getMax(mDataBlock->maxProneBackwardSpeed * mFabs(move->y),
                  mDataBlock->maxProneSideSpeed * mFabs(move->x));
            else if (mPose == CrouchPose)
               moveSpeed = getMax(mDataBlock->maxCrouchBackwardSpeed * mFabs(move->y),
                  mDataBlock->maxCrouchSideSpeed * mFabs(move->x));
            else if (mPose == SprintPose)
               moveSpeed = getMax(mDataBlock->maxSprintBackwardSpeed * mFabs(move->y),
                  mDataBlock->maxSprintSideSpeed * mFabs(move->x));
            else // StandPose
               moveSpeed = getMax(mDataBlock->maxBackwardSpeed * mFabs(move->y),
                  mDataBlock->maxSideSpeed * mFabs(move->x));
         }
      }

      // 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::LandAnim))
         mActionAnimation.action = PlayerData::NullAnimation;
   }
   else
   {
      moveVec.set(0.0f, 0.0f, 0.0f);
      moveSpeed = 0.0f;
   }
     
     //...

Hope this helps someone. ☺️

Edited by Steve_Yorkshire
Link to comment
Share on other sites

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...