TGB/MiniTutorials/SimpleTankPhysics

From TDN

Back

Simple Tank Physics
Description:

This sample script will demonstrate how to set up a control object with simple tank physics including throttle, steering, and a mouse-controlled turret.


This demo uses the 'w' and 's' keys to control forward and reverse, and the 'a' and 'd' keys to control left and right steering. The turret aiming is controlled by the mouse pointer.


There will be further information on how to create and launch projectiles in other demos, however this demo is just meant to cover the movement of the tank itself.

Image:SimpleTankPhysics.JPG


 Download Files :

Simple Tank Physics Resource




Extract the zip file into your "../tgb/Resources" directory and load the Tank resource into a new project. Then just drop the body of the tank into your level and enjoy! Note: You only need to copy the body of the tank, the turret will be created and mounted automatically.


Note: In order to get your turret rotation to look as realistic as possible it helps to adjust the pivot to the center of the turret base. You can do this in your image editing software by leaving just the right amount of blank space at the bottom of your tank turret image. You can use the image in the resource as an example.

// Tank Datablock definition
// play with these variables to change the handling of your Tank!
datablock t2dSceneObjectDatablock(PhysTankDatablock)
{
   class = "PhysTank"; // associate this datablock with the PhysTank namespace
   maxSteerAngle = "55"; // the maximum angular force used for steering the tank (not an angle)
   cTrac = "15"; // coefficient of traction (max speed)
   size = "8.120 8.120"; // default size
};

// Turret Datablock definition
datablock t2dSceneObjectDatablock(PhysTankTurretDatablock)
{
   turnSpeed = "80"; // speed at which turret turns
   size = "2.755 11.132"; // default size
};

// PhysTank onLevelLoaded callback
function PhysTank::onLevelLoaded(%this, %scenegraph)
{   
   // set this tank's name so SceneWindow2D can find it
   %this.setName("MyTank");
   
   // init tank toggle vars
   %this.gasPedal = false;
   %this.brake = false;
   %this.left = false;
   %this.right = false;
   %this.turretLeft = false;
   %this.turretRight = false;
   
   // init tank input vars
   %this.throttle = 0; // ranges from -1 to 1 (full reverse to full forward)
   %this.steering = 0; // ranges from -1 to 1 (full left to full right)
   %this.lastMousePos = "0 0";
   
   // set up turret
   %this.initializeTurret();
   
   // map keys
   moveMap.bindCmd(keyboard, "w", %this @ ".throttleOn();", %this @ ".throttleOff();");
   moveMap.bindCmd(keyboard, "s", %this @ ".brakeOn();", %this @ ".brakeOff();");
   moveMap.bindCmd(keyboard, "a", %this @ ".leftOn();", %this @ ".leftOff();");
   moveMap.bindCmd(keyboard, "d", %this @ ".rightOn();", %this @ ".rightOff();");
   
   // enable the timer callback for this object for every 25 milliseconds
   %this.setTimerOn(25);
}

// create and attach a turret to this tank
function PhysTank::initializeTurret(%this)
{
   // create the new turret and store it on this object
   %this.turret = new t2dStaticSprite()
   {
      sceneGraph = %this.scenegraph; // make sure to set the scenegraph
      ImageMap = "tankTurretImageMap"; // set the image to use
      config = "PhysTankTurretDatablock"; // set the config datablock
   };

   // mount the turret to the tank and set 'trackRotation' (fourth argument)
   // to false so we can rotate our turret independently
   %this.turret.mount(%this, "0 -0.1", 0, false, true, true, true);
}

// this is called every time the mouse cursor is moved
function sceneWindow2D::onMouseMove(%this, %modifier, %worldPos, %clicks)
{
   // update MyTank's lastMousePos variable with fresh coordinates
   MyTank.lastMousePos = %worldPos;
}

// this is our update turret function to rotate the turret 
// towards the mouse pointer
function PhysTank::updateTurret(%this, %mousePos)
{
   // get a vector from the tank to the mouse pointer
   %vec = t2dVectorSub(%this.getPosition(), %mousePos);
   
   // get the desired angle required to point at the mouse pointer   
   %angle = -mRadToDeg(mATan(getWord(%vec,0),getWord(%vec,1)));
   
   // tell the tank turret to rotate towards that angle at a rate of 
   // 'turret.turnSpeed' which was set in our turret's datablock
   %this.turret.rotateTo(%angle, %this.turret.turnSpeed);
}

// PhysTank onTimer callback
function PhysTank::onTimer(%this)
{
   // 1. interpret input flags
   // Throttle:
   // if only the gas pedal is pressed and we aren't reversing
   if((%this.gasPedal && !%this.brake) && %this.throttle >=0)
   {
      // increment trottle (forward)
      %this.throttle += 0.005;
      
      // clamp throttle at 1 for full forward
      if(%this.throttle > 1)
      {
         %this.throttle = 1;
      }
   }
   // if only the 'brake' is pressed and we aren't going forward
   else if((%this.brake && !%this.gasPedal) && %this.throttle <= 0)
   {
      // decrement throttle (reverse)
      %this.throttle -= 0.005;
      
      // clamp throttle at -1 for full reverse
      if(%this.throttle < -1)
      {
         %this.throttle = -1;
      }
   }
   // either *neither* or *both* gas petal and throttle are activated
   // -or- we are trying to throttle in the opposite direction we are moving
   else
   {
      // lower the throttle from either direction by 0.02
      // if magnitude of throttle is less than 0.02 then set to 0
      // Note: without checking for this, our throttle could skip between
      // negative and positive as it tries to hit zero. 
      // for example, immagine the throttle is 0.1
      if(%this.throttle < -0.02)
      {
         %this.throttle += 0.02;
      }
      else if(%this.throttle > 0.02)
      {
         %this.throttle -= 0.02;
      }
      else
      {
         %this.throttle = 0;
      }
   }
   
   // Steering:
   // if only pressing left and steering isnt to the right
   if((%this.left && !%this.right) && %this.steering <= 0)
   {
      // decrement steering (left)
      %this.steering -= 0.025;
      
      // clamp steering at -1 (full left)
      if(%this.steering < -1)
      {
         %this.steering = -1;
      }
   }
   // if only pressing right and steering isnt to the left
   else if((%this.right && !%this.left) && %this.steering >= 0)
   {
      // increment steering (right)
      %this.steering += 0.025;
      
      // clamp stering at 1 (full right)
      if(%this.steering > 1)
      {
         %this.steering = 1;
      }
   }
   else
   {
      // lower the steering from either direction by 0.02
      // if magnitude of steering is less than 0.02 then set to 0
      if(%this.steering < -0.05)
      {
         %this.steering += 0.05;
      }
      else if(%this.steering > 0.05)
      {
         %this.steering -= 0.05;
      }
      else
      {
         %this.steering = 0;
      }
   }
   
   // 2. calculate longitudinal force
   // get current forward traction force (speed)
   %traction = %this.cTrac * %this.throttle;
   
   // get longitudinal force vector
   // remember that neg Y is up, so we need -cos(rotation) for Y
   %longVelX = mSin(mDegToRad(%this.getRotation())) * %traction;
   %longVelY = -mCos(mDegToRad(%this.getRotation())) * %traction;
   
   // 3. steering / angular vel   
   // adjust steering force:
   // get a base steering force based on speed of movement
   %steerVel = %this.steering * %this.maxSteerAngle;
   
   // 4. apply forces
   // apply linear velocity
   %this.setLinearVelocity(%longVelX SPC %longVelY);
   
   // apply angular velocity
   %this.setAngularVelocity(%steerVel);
   
   // 5. set turret's rotation!
   %this.updateTurret(%this.lastMousePos);
}


// ____ input functions ____
// gas
function PhysTank::throttleOn(%this)
{
   %this.gasPedal = true;
}
function PhysTank::throttleOff(%this)
{
   %this.gasPedal = false;
}

// brake / reverse
function PhysTank::brakeOn(%this)
{
   %this.brake = true;
}
function PhysTank::brakeOff(%this)
{
   %this.brake = false;
}

// steer left
function PhysTank::leftOn(%this)
{
   %this.left = true;
}
function PhysTank::leftOff(%this)
{
   %this.left = false;
}

// steer right
function PhysTank::rightOn(%this)
{
   %this.right = true;
}
function PhysTank::rightOff(%this)
{
   %this.right = false;
}

// rotate turret left
function PhysTank::turretLeftOn(%this)
{
   %this.turretLeft = true;
}
function PhysTank::turretLeftOff(%this)
{
   %this.turretLeft = false;
}

// rotate turret right
function PhysTank::turretRightOn(%this)
{
   %this.turretRight = true;
}
function PhysTank::turretRightOff(%this)
{
   %this.turretRight = false;
}


Back