Game Development Community

Exposing advanced physics features (1.1)

by Kyle Kronyak · in Torque Game Builder · 02/09/2006 (10:46 pm) · 9 replies

EDIT: Updated to add boolean value "relative" to torque forces!

I purchased the 1.1 beta on the 8th. I have so far been impressed with the engine / SDK. One thing I did not like however was the lack script-based control over rigid-body physics. Sure, you could make objects twist and turn by smashing into each other, but one of the games / test apps I wanted to make would involve forces being applied to different parts of an object to make it fly around. I decided to do a little digging around in the code and the forums. Didn't find much of help in the forums or TDN but I found a gold mine in the code: shiny new physics functions, not used ANYWHERE, just WAITING to be exposed! I've decided to do myself and others a favor by creating interfaces to those functions as commands to use through TScript. Of course you will need to re-build the engine in order to take advantage of these commands, but if you want more precise physics control, it's well worth it!

Before I post the instructions, I'd like to give a summary of some of the things you can do:

Torque:
-Apply a force to a specific part of an object, causing it to rotate and/or move in a linear fashion. i.e. if you apply an upward torque force to the right side of an object, the object will move up, and rotate counter-clockwise

Angular:
-Make an object spin on its center of gravity!

The new commands are the following:
setImpulseTorqueForce(vector force, vector forcePosition, bool relative)
vector force is x/y specifying the magnitude of the force on each axis
vector forcePosition is x/y specifying the location the force applies to, relative to the center of the object
bool relative is a boolean value that specifies whether or not the force position is relative to the object's origin or the scene's origin
$player.setImpulseTorqueForce("0 10", "0 0"); makes the object move straight down by applying 10 force to its center

setImpulseTorqueForcePolar(float angle, float force, vector forcePosition relative)
float angle is a decimal # specifying the direction of the force
float force is a decimal # specifying the magnitude of the force
vector forcePosition is x/y specifying the location the force applies to, relative to the center of the object
bool relative is a boolean value that specifies whether or not the force position is relative to the object's origin or the scene's origin
$player.setImpulseTorqueForce(180, 10, "0 0"); makes the object move straight down by applying 10 force to its center

setImpulseAngularForce(float force)
float force is a decimal # specifying the magnitude of the force (positive == counter clockwise)
$player.setImpulseAngularForce(10); makes the object spin counter-clockwise


And now for the code! You will need to paste each piece of code into its source file, then re-build the T2D engine.

The following code should be pasted in t2dSceneObject.h somewhere near setImpulseForce (directly under it wouldn't hurt):
void			setImpulseTorqueForce( const t2dVector& force, const t2dVector& forcePosition, const bool gravitic, const bool relative);
void			setImpulseAngularForce( const F32& force, const bool gravitic );

#1
02/09/2006 (10:46 pm)
EDIT: added boolean relative parameter!
EDIT: corrected mistake in setImpulseTorqueForce function!
EDIT: added 'gravitic' property, made relative 'true' by default

The following code should be pasted in t2dSceneObject.cc somewhere in the file (at the bottom is a good location if you think you may remove it):
//-----------------------------------------------------------------------------
// Set Impulse Torque Force
//-----------------------------------------------------------------------------
ConsoleMethod(t2dSceneObject, setImpulseTorqueForce, void, 3, 8, "(forceX / forceY, forcePosX / forcePosY, [gravitic?], [relative?] ) - Apply an instantaneous force to a specific location.")
{
   // The force.
   t2dVector force;
   // The force position.
   t2dVector forcePosition;
   // Absolute or Relative force position
   bool relative = true;
   // Gravitic force
   bool gravitic = false;
   // Grab the element count.
   U32 elementCount1 = t2dSceneObject::getStringElementCount(argv[2]);
   U32 elementCount2 = t2dSceneObject::getStringElementCount(argv[3]);
   U32 elementCount3 = t2dSceneObject::getStringElementCount(argv[4]);

   // ("forceX forceY", ...)
   if ((elementCount1 == 2) && (argc < 9))
   {
      force = t2dSceneObject::getStringElementVector(argv[2]);  
	  // ( ..., "forcePosX forcePosY", [gravitic], [relative])
	  if ((elementCount2 == 2) && (argc < 9))
	  {
		forcePosition = t2dSceneObject::getStringElementVector(argv[3]);  
		if(argc > 4) gravitic = dAtob(argv[4]);
		if(argc > 5) relative = dAtob(argv[5]);		
	  }
	  // ( ..., forcePosX, forcePosY, [gravitic], [relative])
	  else if ((elementCount2 == 1) && (argc > 3))
	  {
		forcePosition = t2dVector(dAtof(argv[3]), dAtof(argv[4]));
		if(argc > 5) gravitic = dAtob(argv[5]);
		if(argc > 6) relative = dAtob(argv[6]);
	  }
   }

   // (forceX, forceY, ...)
   else if ((elementCount1 == 1) && (argc > 3))
   {
      force = t2dVector(dAtof(argv[2]), dAtof(argv[3]));
	  // ( ..., "forcePosX forcePosY", [gravitic], [relative])
	  if ((elementCount3 == 2) && (argc < 9))
	  {
		forcePosition = t2dSceneObject::getStringElementVector(argv[4]);  
		if(argc > 5) gravitic = dAtob(argv[5]);
		if(argc > 6) relative = dAtob(argv[6]);
	  }
	  // ( ..., forcePosX, forcePosY, [gravitic], [relative])
	  else if ((elementCount3 == 1) && (argc > 3))
	  {
		forcePosition = t2dVector(dAtof(argv[4]), dAtof(argv[5]));
		if(argc > 6) gravitic = dAtob(argv[6]);
		if(argc > 7) relative = dAtob(argv[7]);
	  }
   }

   // Invalid
   else
   {
      Con::warnf("t2dSceneObject::setImpulseTorqueForce() - Invalid number of parameters!");
      return;
   }

   // Set Torque Force.
   object->setImpulseTorqueForce(force, forcePosition, gravitic, relative);
}

//-----------------------------------------------------------------------------
// Set Impulse Torque Force Polar
//-----------------------------------------------------------------------------
ConsoleMethod(t2dSceneObject, setImpulseTorqueForcePolar, void, 3, 8, "(angle, force, forcePosX / forcePosY, [gravitic?], [relative?]) - Apply an instantaneous polar force to a specific location.")
{
   // Renormalise Angle.
   F32 angle = mFmod(dAtof(argv[2]), 360.0f);
   // Fetch Force.
   F32 force = dAtof(argv[3]);
   // The force position.
   t2dVector forcePosition;
   // Absolute or Relative force position
   bool relative = true;
   // Gravitic force;
   bool gravitic = false;
   // Grab the element count.
   U32 elementCount = t2dSceneObject::getStringElementCount(argv[4]);
   
   // (angle, force "forcePosX forcePosY", [relative], [gravitic])
   if ((elementCount == 2 && argc < 9))
   {
      forcePosition = t2dSceneObject::getStringElementVector(argv[4]);
	  if(argc > 5) gravitic = dAtob(argv[5]);
	  if(argc > 6) relative = dAtob(argv[6]);
   }

   // (angle, force forcePosX, forcePosY, [relative], [gravitic])
   else if ((elementCount == 1) && (argc > 3))
   {
      forcePosition = t2dVector(dAtof(argv[4]), dAtof(argv[5]));
	  if(argc > 6) gravitic = dAtob(argv[6]);
	  if(argc > 7) relative = dAtob(argv[7]);
   }
   // Invalid
   else
   {
      Con::warnf("t2dSceneObject::setImpulseTorqueForce() - Invalid number of parameters!");
	  return;
   }
   
   // Set Torque Force.
   object->setImpulseTorqueForce(t2dVector( mSin(mDegToRad(angle))*force, -mCos(mDegToRad(angle))*force ), forcePosition, relative, gravitic);
}

// Set Torque Force.
void t2dSceneObject::setImpulseTorqueForce( const t2dVector& force, const t2dVector& forcePosition, const bool gravitic, const bool relative)
{
	t2dVector objectPosition;
	//Determine where to apply force
	if(relative){
		// Get absolute location of force, relative to object
		objectPosition = getWorldPoint(forcePosition);
	}else{
		// Get absolute location of force, relative to center of scene
		objectPosition = forcePosition;
	}
    // Add Impulse Torque Force to Physics.
    getParentPhysics().addGrossTorqueForce( gravitic ? force * getParentPhysics().getMass() : force, objectPosition );
}

//-----------------------------------------------------------------------------
// Set Angular Force
//-----------------------------------------------------------------------------
ConsoleMethod(t2dSceneObject, setImpulseAngularForce, void, 2, 4, "(force, gravitic) - Apply an instantaneous rotational force.")
{
   F32 force = dAtof(argv[2]);
   bool gravitic = false;
   if(argc > 3) gravitic = dAtob(argv[3]);
   // Set Angular Force.
   object->setImpulseAngularForce( force, gravitic );
}

// Set Angular Force.
void t2dSceneObject::setImpulseAngularForce( const F32& force, const bool gravitic )
{
    // Add Impulse Torque Force to Physics.
    getParentPhysics().addGrossAngularForce( gravitic ? force * getParentPhysics().getMass() : force );
}

I hope this is helpful to everyone! Please let me know if I have made any errors in the modifications. I would also be interested in finding out if this (or something similar / virtually identical) will be included in later betas / final 1.1 release!
#2
02/10/2006 (1:38 pm)
First the terrible lack of docs, and now secret functions? GG.. how could you!?! This is getting out of hand;D
#3
02/10/2006 (1:54 pm)
@Joe: thanks for finally making me laugh on this topic!
#4
02/10/2006 (7:04 pm)
You should probably make a resource out of this.
#5
02/10/2006 (7:39 pm)
More likely that it should be rolled into the engine next update!
#6
02/10/2006 (8:18 pm)
How would I got about 'making a resource'? Sorry about being a 'n00b' but as indicated I am in fact new here.

BTW I'm going to provide an update to the code later tonight which will make it much more powerful, by allowing the coder to specify (via a boolean value) whethe the force position is relative (0,0 is Object's position) or absolute (0,0 is center of play field). I will explain why when I post.
#7
02/10/2006 (9:43 pm)
This looks cool!

As for submitting a resource, go to:

www.garagegames.com/index.php?sec=mg&mod=resource&page=overview

I'm actually not sure how to navigate to this page, but you can find it by searching "submit new resource".
#8
02/11/2006 (10:59 pm)
I discovered an error in the code and corrected it. The current code should work as expected when using relative positions. I had to change the line from:

objectPosition = getParentPhysics().getPosition() + forcePosition;

to

objectPosition = getWorldPoint(forcePosition);

I was unaware of the getWorldPoint function and did not realize the significant difference between "object points" and "world points".
#9
02/12/2006 (1:39 pm)
Sorry for all of the posts, I've been trying to improve this 'hack' and I think it's just about 'there'.

I've added the 'gravitic' property to all 3 commands. I've also set the 'relative' property to default to 'true' since these commands will most likely be used in reference to an object anyway (of course, users could always use the getLocalPoint() function to convert an arbitrary point in the scene to be relative to the object so this propertly may be obsolete).

I've also cleaned up the code a bit, adding comments and sanity checks where necessary.