Game Development Community

Player Drift

by Jon Jorajuria · in Torque Game Builder · 12/14/2006 (3:08 pm) · 3 replies

I have been trying to get a slight drift working in my game, but both result in a slightly noticeable "tick" or jitter to the player. I am using I have tried two different functions and I was wondering if anybody knew a way to get rid of the jotter:

onTimer callback method:
function playerClass::onTimer(%this)
{
   if(%this.moveUp && !%this.moveDown)
   {
      %this.planeThrottle -= 0.15;
      
      // clamp throttle at 1 for full forward
      if(%this.planeThrottle < -50)
      {
         %this.planeThrottle = -50;
      }
   }
   if(%this.moveDown && !%this.moveUp)
   {
      %this.planeThrottle += 0.15;
      
      // clamp throttle at 1 for full forward
      if(%this.planeThrottle > 50)
      {
         %this.planeThrottle = 50;
      }
   }
   if((!%this.moveDown && !%this.moveUp))
   {
      if(%this.planeThrottle < -0.02)
      {
         %this.planeThrottle += 0.05;
      }
      else if(%this.planeThrottle > 0.02)
      {
         %this.planeThrottle -= 0.05;
      }
      else
      {
         %this.planeThrottle = 0;
      }
   }
   if(%this.moveLeft && !%this.moveRight)
   {
      %this.planeBank -= 0.15;
      
      // clamp throttle at 1 for full forward
      if(%this.planeBank < -50)
      {
         %this.planeBank = -50;
      }
   }
   if(%this.moveRight && !%this.moveLeft)
   {
      %this.planeBank += 0.15;
      
      // clamp throttle at 1 for full forward
      if(%this.planeBank > 50)
      {
         %this.planeBank = 50;
      }
   }
   if((!%this.moveLeft && !%this.moveRight))
   {
      if(%this.planeBank < -0.02)
      {
         %this.planeBank += 0.05;
      }
      else if(%this.planeBank > 0.02)
      {
         %this.planeBank -= 0.05;
      }
      else
      {
         %this.planeBank = 0;
      }
   }   
   %this.setLinearVelocityY(%this.planeThrottle);
   %this.setLinearVelocityX(%this.planeBank);
}

#1
12/14/2006 (3:08 pm)
Continued...

Custom function:
function playerAdjustVelocityX()
{
   %increment = $playerPlane01.velocityIncrement;
   
   %currentVelocityX = $playerPlane01.getLinearVelocityX();
   
   %velocityTickRate = 10;
   
   //echo("requested Velocity is " @ $playerPlane01.requestedVelocity);
         
   if($playerPlane01.requestedVelocityX > 0)
   {
      if((%currentVelocityX + %increment) < $playerPlane01.requestedVelocityX)
      {
         $playerPlane01.setLinearVelocityX(%currentVelocityX + %increment);
         //echo("incrementing VelocityX from " @ %currentVelocityX @ " by " @ %increment);
         schedule(%velocityTickRate, 0, "playerAdjustVelocityX");
      }
      else if(%currentVelocityX + %increment == $playerPlane01.requestedVelocityX)
         $playerPlane01.setLinearVelocityX(%currentVelocityX + %increment);
      else //set to max VelocityX
         $playerPlane01.setLinearVelocityX($playerPlane01.maxVelocityX);
   }
   else if ($playerPlane01.requestedVelocityX < 0)
   {
      //echo("in reqVel < 0, current = " @ %currentVelocityX);
      if((%currentVelocityX - %increment) > $playerPlane01.requestedVelocityX)
      {
         //echo("decrementing VelocityX from " @ %currentVelocityX @ " by " @ %increment);
         $playerPlane01.setLinearVelocityX(%currentVelocityX - %increment);
         schedule(%velocityTickRate, 0, "playerAdjustVelocityX");
      }
      else 
         $playerPlane01.setLinearVelocityX($playerPlane01.requestedVelocityX);
   }
   else // requested VelocityX == 0
   {
      if(%currentVelocityX < 0) // start increasing the VelocityX
      {
         if((%currentVelocityX + %increment) > 0)
            $playerPlane01.setLinearVelocityX(0);
         else
         {
            $playerPlane01.setLinearVelocityX(%currentVelocityX + %increment);
            schedule(%velocityTickRate, 0, "playerAdjustVelocityX");
         }
      }
      else if (%currentVelocityX > 0) //start decreasing the velocity
      {
         if((%currentVelocityX - %increment) < 0) //would set VelocityX too far, so go to zero
            $playerPlane01.setLinearVelocityX(0);
         else
         {
            $playerPlane01.setLinearVelocityX(%currentVelocityX - %increment);
            schedule(%velocityTickRate, 0, "playerAdjustVelocityX");
         }
      }
   }
   $playerPlane01.setCurrentAnimation();
}

Thank you in advance for your help.
#2
12/15/2006 (8:11 pm)
Hi, Jon.

There is no built in functionality to interpolate between velocities, but you can manually throttle it like you're doing. First of all, for those purposes I would have to suggest using your onUpdateScene callback, rather than a timer or schedule, because you are guaranteed to get it every 'tick'.

Part of the jitter you're seeing is probably due to the fact that there are scene updates between your physics updates. The onUpdateScene callback is on the scenegraph namespace. You can break some stuff by just using it there, so what you can do is name your scenegraph in the level editor. Make sure nothing is selected and go to the edit tab -> scripting rollout and type in a name. If that name was "myScene" you can define "function myScene::onUpdateScene(%this)" and call your player's update function from there. You probably want to register your player with the scenegraph to avoid doing global BS, so you in your player's onLeveLoaded callback create a field on the scenegraph for your player. Something like "%scenegraph.player = this;" Then just define an update function and call it from your onUpdateScene callback.

The second possible reason for the jitter is because you're not scaling your values by time. Get the elapsed time between ticks at the beginning of your update function and scale all velocity increments by multiplying them by that value. You can get the elapsed time by storing the previous total sim time in a field on the scenegraph or somewhere and subtracting the current time from it in the next update.

Here's an example:
// note: scenegraph must be named "myScene" for this to work
// replace that name with whatever you want to call your scenegraph
function myScene::onUpdateScene(%this)
{
   // get the elapsed time since last scene update and update the previous time field
   %currTime = getSimTime();
   %elapsed = %currTime - %this.previousUpdateTime;
   %this.previousUpdateTime = %currTime;

   // update the player's physics and pass it the elapsed time
   if(isObject(%this.player))
      %this.player.updatePhysics(%elapsed);
}

function Player::onLevelLoaded(%this, %scenegraph)
{
   // store a reference to this object on the scenegraph so it can call our update for us
   %scenegraph.player = %this;
}

function Player::updatePhysics(%this, %elapsed)
{
   ....
   // interpret input, etc.
   ...

   // example of some physics operation scaled by elapsed time
   if(%moveRight)
      %this.setVelocityX(%baseAccel * %elapsed);

  // then maybe clamp the value or something
  ...
}

If you have multiple characters that need updates you can just replace the player field with a "characters" or "actors" field that stores a simset of all things that need to be updated. In that case you would have a for loop that iterates through those objects and calls update on all of them. In the onLevelLoaded for those objects just have them add themselves to the scenegraph's simset to allow them to get updates.

I hope this was helpful. Let me know if you have any trouble with any of this.

Edit: Spelling.. Forgot some '%' signs.
#3
12/17/2006 (9:49 pm)
I wanted to place the final code up here so that the community can use it...here goes:

Create a file called driftFunction.cs or attach the following code to an existing onUpdateScene function:

function demoLevelScene::onUpdateScene(%this)
{
   // get the elapsed time since last scene update and update the previous time field
   %currTime = getSimTime();
   %elapsed = %currTime - %this.previousUpdateTime;
   %this.previousUpdateTime = %currTime;

   // update the player's physics and pass it the elapsed time
   if(isObject(playerPlane01))
      playerPlane01.updatePhysics(%elapsed);
}

In player.cs under the onLevelLoaded function add as stated above:

function Player::onLevelLoaded(%this, %scenegraph)
{
...   
// store a reference to this object on the scenegraph so it can call our update for us
   %scenegraph.player = %this;
...
}

I have movement functions that basically return a true/false value. With that in mind, I created the following function:

[code]
function playerClass::updatePhysics(%this, %elapsed)
{   
   if(%this.moveUp && !%this.moveDown)
   {
      %this.planeThrottle -= (0.1 * %elapsed);
      
      // clamp throttle at 1 for full forward
      if(%this.planeThrottle < -50)
      {
         %this.planeThrottle = -50;
      }
   }
   if(%this.moveDown && !%this.moveUp)
   {
      %this.planeThrottle += (0.1 * %elapsed);
      
      // clamp throttle at 1 for full forward
      if(%this.planeThrottle > 50)
      {
         %this.planeThrottle = 50;
      }
   }
   if((!%this.moveDown && !%this.moveUp))
   {
      if(%this.planeThrottle < -0.02)
      {
         %this.planeThrottle += (0.1 * %elapsed);
      }
      else if(%this.planeThrottle > 0.02)
      {
         %this.planeThrottle -= (0.1 * %elapsed);
      }
      else
      {
         %this.planeThrottle = 0;
      }
   }
   if((%this.moveDown && %this.moveUp))
   {
      if(%this.planeThrottle < -0.02)
      {
         %this.planeThrottle += (0.1 * %elapsed);
      }
      else if(%this.planeThrottle > 0.02)
      {
         %this.planeThrottle -= (0.1 * %elapsed);
      }
      else
      {
         %this.planeThrottle = 0;
      }
   }
   if(%this.moveRight && !%this.moveLeft)
   {
   	%this.planeBank += (0.1 * %elapsed);   	
   	
   	if(%this.planeBank > 50)
      {
         %this.planeBank = 50;
      }   	
   }
   if(%this.moveLeft && !%this.moveRight)
   {
    %this.planeBank -= (0.1 * %elapsed);   	
   	
   	if(%this.planeBank < -50)
      {
         %this.planeBank = -50;
      }
   }
   if((!%this.moveLeft && !%this.moveRight))
   {
      if(%this.planeBank < -0.02)
      {
         %this.planeBank += (0.1 * %elapsed);
      }
      else if(%this.planeBank > 0.02)
      {
         %this.planeBank -= (0.1 * %elapsed);
      }
      else
      {
         %this.setLinearVelocityX(0);
      }
   } 
   if((%this.moveLeft && %this.moveRight))
   {
      if(%this.planeBank < -0.02)
      {
         %this.planeBank += (0.1 * %elapsed);
      }
      else if(%this.planeBank > 0.02)
      {
         %this.planeBank -= (0.1 * %elapsed);
      }
      else
      {
         %this.setLinearVelocityX(0);
      }
   }  
   %this.setLinearVelocityX(%this.planeBank);
   %this.setLinearVelocityY(%this.planeThrottle);
}

This causes a nice drift on all both the x axis and the y axis.