Game Development Community

T2D Physics Demo

by Matthew Langley · 03/14/2005 (10:08 pm) · 12 comments

Note: here is a standalone T2D Physics Demo

This is a resource that uses a modified recent example by Melv (displaying settings that make a block bounce accross walls)... I have added a gui that has sliders to control some of the major physics factors, as well as constant force direction and speed slides and impulse force (degrees and speed)... so you can test out physics in this.

razedskyz.com/games/torque/tutorials/T2D/physicsDemo2.JPG
There is also a button to create a new block, all of the blocks data are stored in

$blocks
$blocks::ammount
$blocks::names[]

when you add a new block it adds to names, for example, first block is

$blocks::names[0]...

if you did

echo($blocks::names[0]);

it would produce "block0" in the console... a simple naming convention...

all of the sliders apply when you release the mouse button, except the degrees and force for setImpulse... you set the degrees, then the force ammount and click the setImpulse button. All of the sliders effect every block, have some loops that apply it to all of them.

Just a demo that you can play around with physics, test friction, interaction, etc etc...

NOTE: Non-Windows users disregard the comments on creating files in windows and to the quirks in such, you probably already know how to create a script file in your own operating system :)

ok lets start...


first go to your Torque 2D\SDK\Example\T2D\client folder... create a new text file (right click -> go to new -> go to "Text Document")... name it "slidersGUI.gui" ... click yes on any warning prompts (simple windows making sure you want to change the extension - the .txt to .gui)...

now copy this code in the file and save it

if(!isObject(GuiPhysicsTextProfile)) new GuiControlProfile (GuiPhysicsTextProfile)
{
   fontColor = "255 0 0";
   fontColorLink = "255 96 96";
   fontColorLinkHL = "0 0 255";
   autoSizeWidth = true;
   autoSizeHeight = true;
};


//--- OBJECT WRITE BEGIN ---
new GuiControl(slidersGUI) {
   profile = "GuiDefaultProfile";
   horizSizing = "right";
   vertSizing = "bottom";
   position = "0 20";
   extent = "225 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 0";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Friction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiFrictionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 10";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(Friction,guiFrictionSlider.value);";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 40";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Restitution";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiRestSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 50";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(Restitution,guiRestSlider.value);";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "1";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 80";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Relaxation";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiRelaxSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 90";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(Relaxation,guiRelaxSlider.value);";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 120";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Density";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiDensSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 130";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(Density,guiDensSlider.value);";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.01";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 160";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Damping";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiDampSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 170";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(Damping,guiDampSlider.value);";
      range = "0.000000 5.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "65 200";
      extent = "40 18";
      minExtent = "8 2";
      visible = "1";
      text = "Max Angular Velocity";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiMaxAngularSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 210";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(MaxAngularVelocity,guiMaxAngularSlider.value);";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "65 240";
      extent = "40 18";
      minExtent = "8 2";
      visible = "1";
      text = "Max Linear Velocity";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiMaxLinearSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 250";
      extent = "204 40";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.set(MaxLinearVelocity,guiMaxLinearSlider.value);";
      range = "0.000000 2000.000000";
      ticks = "10";
      value = "200";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "35 280";
      extent = "50 28";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Direction (Degrees)";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceDirecSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 290";
      extent = "204 41";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.setForce(guiForceDirecSlider.value, guiForceSpeedSlider.value);";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 320";
      extent = "25 28";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 330";
      extent = "204 41";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.setForce(guiForceDirecSlider.value, guiForceSpeedSlider.value);";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 360";
      extent = "25 28";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Direction (Degrees)";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "204 41";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "76 400";
      extent = "25 28";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseForceSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "204 41";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };
   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 440";
      extent = "80 15";
      minExtent = "8 2";
      visible = "1";
      command = "slidersGUI.setImpulse( guiImpulseDirectionSlider.value, guiImpulseForceSlider.value );";
      text = "Impulse Force!";
      groupNum = "1";
      buttonType = "PushButton";
   };

   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "85 440";
      extent = "105 15";
      minExtent = "8 2";
      visible = "1";
      command = "createBlock();";
      text = "Add a Bouncy Block";
      groupNum = "1";
      buttonType = "PushButton";
   };

};
//--- OBJECT WRITE END ---

function slidersGUI::setForce(%this, %direc, %speed)
{
	for(%i=0;%i<$blocks::ammount;%i++)
	{
		eval($blocks::names[%i] @ ".setConstantForcePolar(%direc, %speed);");
		echo("setting force direc:" SPC %direc SPC "and speed:" SPC %speed);
	}
}

function slidersGUI::set(%this, %type, %val)
{
	
	for(%i=0;%i<$blocks::ammount;%i++)
	{
		eval($blocks::names[%i] @ ".set" @ %type @ "(%val);");
		echo("Setting the" SPC %type SPC "to" SPC %val);
	}
	eval("bouncyMaterial." @ %type @ "=" @ %val @ ";");
}

function slidersGUI::setImpulse(%this, %direc, %force)
{
	for(%i=0;%i<$blocks::ammount;%i++)
	{
		eval($blocks::names[%i] @ ".setImpulseForcePolar(%direc, %force);");
		echo ("setting impulse force for num:" SPC %i SPC "direc = " @ %direc SPC "force = " @ %force);
	}
}

now right click and create another new text file... name it "bounce.cs" (click yes again if needed)... copy the following code into it and save it. (note: the following code was modified from one of Melv's examples)

function pongBounce()
{
   // Setup some immovable walls and allow them to receive collisions only...
   
   // Left.
   %sprite = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
   %sprite.setPosition( "-40 0" );
   %sprite.setSize( "2 75" );
   %sprite.setImageMap( tileMapImageMap );
   %sprite.setCollisionActive( false, true );
   %sprite.setImmovable();
   // Right.
   %sprite = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
   %sprite.setPosition( "40 0" );
   %sprite.setSize( "2 75" );
   %sprite.setImageMap( tileMapImageMap );
   %sprite.setCollisionActive( false, true );
   %sprite.setImmovable();
   // Top.
   %sprite = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
   %sprite.setPosition( "0 -33" );
   %sprite.setSize( "80 2" );
   %sprite.setImageMap( tileMapImageMap );
   %sprite.setCollisionActive( false, true );
   %sprite.setImmovable();
   // Bottom.
   %sprite = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
   %sprite.setPosition( "0 33" );
   %sprite.setSize( "80 2" );
   %sprite.setImageMap( tileMapImageMap );
   %sprite.setCollisionActive( false, true );
   %sprite.setImmovable();
   
   // Bouncy Material.
   datablock fxCollisionMaterialDatablock2D(bouncyMaterial)
   {
      friction = 0;
      restitution = 1.0;
      relaxation = 0.5;
      density = 0.01;
      forceScale = 1;
      damping = 0;
   };   

   $blocks::ammount = 0;
}

function createBlock()
{

   $blocks::names[$blocks::ammount] = "block" @ $blocks::ammount;
   // Create Bouncy Ball.
   %ball = new fxStaticSprite2D($blocks::names[$blocks::ammount]) { scenegraph = t2dSceneGraph; };
   %ball.setSize( 4 );
   %ball.setImageMap( tileMapImageMap );
   %ball.setCollisionActive( true, true );
   %ball.setCollisionPhysics( true, true );
   //%ball.setLayer( 0 );
   //%ball.setGroup( 0 );
   %ball.setCollisionMasks( BIT(0), BIT(0) );
   %ball.setCollisionMaterial( bouncyMaterial );
   %ball.setMaxAngularVelocity( guiMaxAngularSlider.value );
   %ball.setMaxLinearVelocity( guiMaxLinearSlider.value );
   
   // Give it a random direction.
   %ball.setImpulseForcePolar( getRandom()*360, 700 );

   $blocks::ammount++;
}


ok now we're almost done... go to your client.cs and open it...

after
exec("./mainScreenGui.gui");

add this

exec("./bounce.cs");
exec("./slidersGUI.gui");

then after

Canvas.setCursor(DefaultCursor);

add this

mainScreenGui.add(slidersGUI);

what this does is first it "exec"s the .gui and .cs files, that way the function and gui calls will be made... then it addes the slidersGUI onto the main gui, this way you can use the sliders and still use the main menu.

ok last step

now go down to...
// ************************************************************************
	//
	// Add your custom code here...
	//
	// ************************************************************************

make sure you aren't calling anything else here (for this example)... you can use the "//" to comment out other calls... like
//createPlayer();

put the following there

pongBounce();


thats it... now fire up your T2D.exe... you should see the sliders on the left (I recommend adding the debug buttons from this resource debug gui as well)

and nothings happening... well to make things more interesting click on the "Add a bouncy block" button, you can add as many as you want!

Remember to apply impulses (especially usefull when things stop - sometimes due to adding damping) you need to set the degree, somwhere from 0 - 360... 0 by default works (will push them up) and then set the force speed slider after it, at the default of 0 it does nothing when you click the button!

:)

#1
03/15/2005 (8:58 am)
the demo file is not there..
#2
03/15/2005 (9:01 am)
sorry was just reloading a new version :) its up now
#3
03/15/2005 (10:40 am)
downloading now
Thanks!
#4
03/15/2005 (10:41 am)
hope you enjoy, on the boards I have a tutorial going step by step on how to create it... half of the t utorial is done...

lol sorry bout the download, you caught me exactly as I was uploading a new version :)
#5
03/15/2005 (6:22 pm)
Ooo this is great!
#6
03/20/2005 (7:50 pm)
This is really a great Tutorial. I've learned so much about T2D from this one. Thanks much!!!

BTW: In testing the final product I noticed that the walls can be penetrated by the blocks if "Relaxation" is set to zero and you apply a constant force and regular impulse forces along the same vector. They seem more impassible with Relaxation set >0. What exactly does "relaxation" do?

Thanks again, you've done an absolutely fantastic job one this one.

Ken
#7
03/28/2005 (10:50 am)
Another winner Matt!

I am creating a pong-pinball hybrid game in an effort to learn TorqueScript and this demo will be a great learning tool.

Many thanks!

Richard
#8
04/15/2006 (11:07 pm)
the file is missing again :( ???
#9
06/12/2006 (4:59 am)
Still missing files:((((
#10
03/11/2009 (11:26 pm)
Matt, the domain has been hijacked, I think. Can't GarageGames.com just host the file?
#11
03/12/2009 (9:28 am)
I posted this in early 2005 :)
#12
01/15/2011 (4:11 am)
Physics link broken... anyone with a mirror? Thanks