Torque 2D Tutorial - Creating the Physics Demo

by: Matthew "King BoB" Langley

this tutorial will cover the following:

By the end of this you will have created a GUI that will not only dynamically change the physics settings, but you will have learned how to store object data in an array, dynamically create sprites, set and change datablock settings, and create dynamic efficient functions.

Table of contents

1 - Step 1: The Walls
2 - Step 2: The Bouncy Block
3 - Step 3: Creating the first GUI Controls
4 - Step 4: Creating all of the GUI Controls
5 - Step 5: Creating the Script for the GUI


Physics Demo Tutorial!

Overview: Ok now that you have seen the basic physics demo, its really just a bunch of blocks that bounce around on the screen, albeit that you can control some interesting physics factors real-time. All in all the nifty part about it is that you can do that real-time through the magnificent Torque gui interface! So how do you do it... if you know this already then you probably won't have much use for this tutorial (other than setting some basic physics values lol)...


To start out I'd highly recommend you copy your entire Torque 2D directory and only modify the copy (that way you still have all the original files)...

so we start... first lets create the objects we need in game before we make an interface to manipulate them...

create a new script file in the same directory as you client.cs file... (simply right click and go to New... then text document)... name the file "bounce.cs"... now open it for editing

---------------------------------------------------------
Step 1: The Walls - back
---------------------------------------------------------

Creating the walls (this was used from Melv's example)... well before we want a bouncing box we should probably put some walls in there.

lets start this off in a function... with a basic comment

function pongBounce()
{
   // Setup some immovable walls and allow them to receive collisions only...



First lets create the left wall by setting a local variable called "%sprite" equal to a new static sprite.. like this
// Left.
   %sprite = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };


remember you must assign a scenegraph to put the sprite in on creation... in this case its simply the default "t2dSceneGraph" you should be used to from the tutorial..

next lets set some basic values for this wall

   %sprite.setPosition( "-40 0" );
   %sprite.setSize( "2 75" );
   %sprite.setImageMap( tileMapImageMap );
   %sprite.setCollisionActive( false, true );
   %sprite.setImmovable();


ok lets start with "%sprite.setPosition( "-40 0");"

heres a grid of the world.

the red outline is our view of the world through the camera... what I'll call our "visible world"



first let me explain how the "world" is set up....

you can see it goes from x location -50 to x location posotive 50

thats 100 x units accross

while it goes roughly -37.5 y location to 37.5 y location

thats 75 y units up and down

this is specified in the client.cs
in this line of code
sceneWindow2D.setCurrentCameraPosition( "0 0 100 75" );


this specifies that the center of the camera (or you could say the the "visible world") is 0,0 ... and it extends a total of 100x and 75y units... placing the outer extents -50 to 50 x... and -37.5 to 37.5 y...

now right off the top you may be asking yourself why this... most 2d is referenced by pixel, with 0,0 (the origin) being the top left, or a similar system... well this gives you a huge ammount of flexibility... rather than simply going by pixel, T2D uses a local location system that you define... one advantage straight off the top is if you change resolutions... say you were at 640 x 480... and you designed it using pixel locations... what if you changed to 800 x 600... exactly, either the game goes screwy or the engine tries to guesstimate... I dont know about you but I prefer not to have guesstimation in my game lol... T2D gives you the reigns, it does the calculations... this also makes scaling very independent and powerful...

ok moving on...

so we have
%sprite.setPosition( "-40 0");

that means the center of this wall will be near the left border of the "visible world"... good start


next we have

%sprite.setSize( "2 75");

... you may have guessed it... 2 units wide along the x axis, while 75 units along the y... this should fill the screen (considering we already went over the visible world size :) )

next is
%sprite.setImageMap( tileMapImageMap );

this simply sets the sprites image to the datablock (already defined) "tileMapImageMap"... now you may notice from working with T2D already, if not then I'll let you know, tileMapImageMap is a multi-frame imagemap... it is basically one image file divided into 4 areas that match a certain width and height specification so they can be accessed by T2D as four seperat images... quite nifty and efficient (been used in 2D Games for a long time)... by default if it is a multi-frame sprite and you don't specify which frame on the "setImageMap()" command, it defaults to 0... if we wanted to use the second frame we would do
%sprite.setImageMap( tileMapImageMap, 1);
(note: this can all be read in the wonderful reference documentation included!) :)

ok next line...

%sprite.setCollisionActive( false, true );

ok this sets the collision for the wall... first parameter is send, the second is receive... as you can see it will not send collisions, though it will recieve them... this can be a bit tough to understand at first... this wont be "sending" its collision information... its a wall, we want it to remain static... however, it will "receive" collision calls from other objects, this way the block can then "bounce" off it...

this leads us to the next setting

%sprite.setImmovable();
by setting it Immovable we ensure its a sturdy wall... you know the old saying about having a good foundation... ok well not much to do with this; however, making this immovable ensures proper physics will be applied.


so we have our left wall! here is the code for the rest of the walls... I won't explain each one considering they use the same properties, just different positions to surround the screen.... altogether you should have

   // 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();


again this will simply set some immovable walls around the screen that will receive collision from other objects. (as Melv's comment specifies).




---------------------------------------------------------
Step 2: The Bouncy Block - back
---------------------------------------------------------

Don't ask why the block bounces, it doesn't have much of a motivation except for our ammusement (and using images everyone already has)... Ok lets set up the bouncy material

   // Bouncy Material.
   datablock fxCollisionMaterialDatablock2D(bouncyMaterial)
   {
      friction = 0;
      restitution = 1.0;
      relaxation = 0.5;
      density = 0.01;
      forceScale = 1;
      damping = 0;
   };   



ok... so first we put this line of code

datablock fxCollisionMaterialDatablock2D(bouncyMaterial)

if you arent used to datablocks then its a good idea to become so, many things in any of the Torque engines use datablocks... the best way to describe a datablock and its use is to lead you down the logical path of them...

lets say you want to make a bunch of bouncy blocks...

say you create them... then each time you set its parameters to be bouncy... now not only is this tedious, but it is repitious... repition often is a sign of optimization in code... so instead of setting all of the bouncy blocks collision paramaters individually, we create a data set called "datablocks"... now think of these as static configurations for commonly used data... in this case every bouncy block needs to start with the same collision settings, so we create a Material datablock that holds these settings and then simply assign that datablock to the boxes on creation... this also allows us to change the values of the datablocks (before run time) to change how many objects start out... quite efficient... think of them as static data that is commonly used...

so we create an "fxCollisionMaterialDatablock2D" datablock named "bouncyMaterial"...

then we set numerous settings for the material

friction = 0;
restitution = 1.0;
relaxation = 0.5;
density = 0.01;
forceScale = 1;
damping = 0;

these are the physics settings we want to make the blocks bouncy... now all the blocks that we assign this "bouncyMaterial" to will start out with the same settings! Saves much time as I'm sure you can imagine...

don't forget the ending
};

it is easy to forget the ; at the end... but keep in mind functions use { and }
and functions cannot be in another functions... so other structures use an ending }; instead... (just a way to think of things to keep an eye out for renegade }'s and ;'s
they can be sneaky little buggers

ok the material is set, though I added another line of code

$blocks::ammount = 0;


this sets the ammount variable in the global variable $blocks namespace to 0... this is simply an initiation setting in preperation for storing all the blocks as we create them dynamically in the engine... to be able to change the settings for all of them in real time we need to create some storage, this is one of multiple ways to do it...


now we're off to a new funciton so end this with
}


right now you should have

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;
}




now the new function... lets start it

function createBlock()
{


a simply function start... now lets add some meat
$blocks::names[$blocks::ammount] = "block" @ $blocks::ammount;


ok now this line can look scary to those that are new... let me break this down...

this takes the $blocks global variable namespace (as described previously) and sets a new variable for it... names... this variable is also an array...

------
for those that don't know code too well or are refreshing an array is a way to store multitudes of data under one variable... for example
data[0] = 1;
data[1] = 2;
data[2] = 3;
etc...
this allows a numerical index to easily loop through data, in this case this is invaluable considering we will have to loop through the bouncy blocks to change their settings
------

ok... so we have
$blocks::names[$blocks::ammount]

now when this runs the first time "ammount" is set to 0... (we set that at the end of the last function)... so basically its the same as saying

$blocks::names[0] =

(later we incriment this so each time we all this function it sets a new numerical index of the names array)...

now we set this equal to
"block" @ $blocks::ammount;

this is nothing to be scared by (if your new to Torquescript)...

basically we'ere assembling a string here, we start off with "block"... the @ sign means we are then adding additional data onto the string... we already know $blocks::ammount equals 0 (this time through)... so basically we are making this string
"block0"... the next time we run through this it should add a number and name the next block
"block1"...

so
$blocks::names[$blocks::ammount] = "block" @ $blocks::ammount;
really equals (the first time through)
$blocks::names[0] = "block0";

that should be much more readable... this is just a simple way to accomplish adding dynamic values that can later be referenced... we are creating alist of names that can later be cycled through to set the bouncy block's values... this brings us to the question that arises next... so if we set the array list to equal these names, how then can we set the bouncy blocks to equal the same name... that brings us to our next line

// Create Bouncy Ball.
%ball = new fxStaticSprite2D($blocks::names[$blocks::ammount]) { scenegraph = t2dSceneGraph; };

here we set a local variable "%ball"as a new staticSprite2D... similar to what we've already done.

what is different is instead of using empty ()'s we have included something... we put the value of
$blocks::names[$blocks::ammount] into the ()'s...
from what we already know $blocks::ammount equals 0...
so its saying $blocks::names[0]... and we just set that equal to "block0"

you may have guessed it, on creation if you pass a name into the ()'s during the creation of an object, it sets that object's name to that... so we are crating a new sprite and setting its name to "block0"...
later we can reference the object by using
block0.setDensity(0);...
etc... this makes applying dynamic physics settings much easier.


then we set some basic paramaters (some you should already know)


%ball.setSize( 4 );
   %ball.setImageMap( tileMapImageMap );
   %ball.setCollisionActive( true, true );
   %ball.setCollisionPhysics( true, true );
   %ball.setCollisionMasks( BIT(0), BIT(0) );
   %ball.setCollisionMaterial( bouncyMaterial );
   %ball.setMaxAngularVelocity( 0 );
   
   // Give it a random direction.
   %ball.setImpulseForcePolar( getRandom()*360, 700 );

   $blocks::ammount++;


ok, setImageMap you already know...
setCollisionActive you already know... this time we are telling it to send and recieve collision data...

next we have
%ball.setCollisionPhysics( true, true );

this is set up the same as setCollisionActive... you are telling it to send physics data and receive physics data

then we have
%ball.setCollisionMasks( BIT(0), BIT(0) );

this tells the bouncy block that it will collide with objects in group 0 and on layer 0 (which the walls defaulted to, so this is basically saying the bouncy block will collide with the walls)

then
%ball.setMaxAngularVelocity( 0 );

this simply tells the engine that the maximum rotation velocity of the blocks is 0... so it stops them from rotating

then there is

// Give it a random direction.
%ball.setImpulseForcePolar( getRandom()*360, 700 );

this (as the comment says) gives the ball a random direction... and applies "700" force to it in that direction... resulting in it shooting off in a random direction...

getRandom returns a number between 0 and 1... so to get the desired range, simply multiply it by the max number you want and you get a number between 0 and that number...

lastly we have

$blocks::ammount++;

this is that increment I mentioned earlier, this prepared this function for the next block... resulting in the next block being named block1 rather than block0... then block2 after that, etc etc... creating unique references for them to be easily cycled through later.

end the function with a
}


and you should have this as the function

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( 0 );
   
   // Give it a random direction.
   %ball.setImpulseForcePolar( getRandom()*360, 700 );

   $blocks::ammount++;
}



lets test this out... open up your "client.cs"

find

	exec("./mainScreenGui.gui");


and after it add

      exec("./bounce.cs");


Now scroll down a little ways and find this code

	
	// ************************************************************************
	//
	// Add your custom code here...
      // ************************************************************************


and after it add

	pongBounce();



now fire up T2D.exe ... hit the "~" tilde key... this should bring up the console (later on you will use this a lot)... now type this command

createBlock();


it should look something like this


hit the tilde key again to bring down the console... now you should see a block bouncing around four walls... like this pic



if you don't then compare it to this

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( 0 );
   
   // Give it a random direction.
   %ball.setImpulseForcePolar( getRandom()*360, 700 );

   $blocks::ammount++;
}




ok, now we got the objects created... not really a lot of work though took a bit to explain it all, hopefully you can understand this proccess a bit better... the next part I will go over is the gui interface and the function calls to make to change the setting real-time









Part 2 of the Torque 2D Physics Demo Tutorial...


Overview: this will go over the gui end of things... the gui controls, setting and positioning them (using the in game gui editor as well as editing the .gui files) and then the functions to manipulate the game using the gui.


ok I'll start with creating the gui controls...

---------------------------------------------------------
Step 3: Creating the first GUI Controls - back
---------------------------------------------------------
The Torque GUI editor is quite powerful; however, with this power comes a bit of complexity and difficulty in understanding. First of all, as you may or many not know, pressing "F10" while in game brings up the gui editor... this is extremely useful... however keep in mind you don't have to use it. I often use it a little bit, then edit the .gui files it creates to customize it quickly (one of the reasons is one of my dev machines is very slow and runs the in game gui editor rather slowly)...


Ok lets start by firing up T2D.exe (try and comment out any function calls so it just loads a blank canvas (with the Torque 2D background)...
This means that where it has
	// ************************************************************************
	//
	// Add your custom code here...
	//
	// ************************************************************************

you should have either nothing after it (or have whats after it commented out)...

like
//createPlayer();

(during the last tutorial I suggested you create a copy of your Torque 2D folder and work from the copy, do this now if you hadn't already, that way you don't change anything you already have working)



fire up Torque 2D and then hit "F10"... you should see



ok, now were going to create a new gui, whats very effective about the GUI editor is you can create a new GUI, or you can modify an existing GUI... in this example I'll show you how I prefer to create and edit GUIs...

go to File -> New GUI...

in GUI Name put:
slidersGUI

keep the class as GuiControl
this is just a basic control, you can click on it and browse the multitude of gui controls... at first this may seem intimidating, just think of it as many many different configurable options you can use, not that you have to use. Many things can be accomplished many different ways, so don't be scared to fire up different controls and test them out... ok moving on

you should see something like this


click Create

now it goes to a blank green window... what the green represents is transparency, much like in photoshop (and paintshop) you see a checkerboard... that means if we loaded this over any gui, all of the green would show whatever gui is loaded behind this (this works well for what we're doing since we want to make a menu that can be added easily to the main screen... you can also make the background a solid image if you like, if we were to do that instead of leaving the "class" as GuiControl when we created a new gui, we would go to "GuiBitmapCtrl")

our side bar is basically the same, except it now says "slidersGUI"...

lets get a little more familiar with the interface, here is an outline, I will explain each number as well



note: before describing them, I figured I'd explain one thing a little more... you see the word "control" a lot... lets say you see a button in a GUI interface in Torque... thats a control... a text box... thats a control... etc etc.. everything is basically based off of controls... including a window control, an image control, and an over control... nothing to be affraid of, just a word that represents each gui "element"... in fact if you changed "control" with "element" it seems a bit more understandable but doesn't change what they are, they are just GUI elements. ok now moving on.

1. Adding Controls -

To add controls into the present GUI you click here, this will bring up the same dropdown that you got when going to New GUI... and selecting the "Class" Drop down.

2. Switching Controls -

This is how you can switch to different controls in the GUI Editor... This has all of the GUIs the game uses, for example you can switch to the mainScreenGui and see the main screen of Torque 2D

3. GUI Control List

This will list the present GUI Controls in your GUI... you can branch down and select any GUI Control, when selected the properties show up in the Property List and the GUI is highlighted on the screen

4. Property List

When you select a GUI control from the GUI list it shows its properties here.


Ok to start, select the "slidersGUI" in the GUI Control List... now you can see its properties in the property list... like this



as you can see in my screen things are getting a bit cramped... (my resolution is a bit low and I have it running windowed)... so to view the properties better you can select the border and drag... like I'll show in these pics




pretty nifty... on a quick side note... the view that your seeing, how its split to two sides that can be adjusted, thats a GUI control that you can use! ... its a frame set control, quite handy in fact (but thats for another tutorial).

so now I can actually read the properties lol and can scroll down them to see more... browse them quickly and see all the different properties...

most you can probably understand, some maybe not... for not don't worry so much about those... I'll explain some coming up... Now I'm the type of person that likes to edit the code vs. a graphical editor, you may not be, if not then you can do almost all of your work in here, at least layout wise... Right now I'll show you how I tend to do things...

lets get started... first off what is our gui... well its a bunch of sliders that control physics. Well in all reality its more than that... if you just see a bunch of sliders you don't know what they do... so we need some text in there also, some labels to put names on the sliders... then we have two buttons as well..

so lets make a list of the different type of controls (note this is just design documentation not using the techinical control names yet)

we need the following:
slider controls
text controls
button controls

(a good design is essential to just about anything)

ok... well lets create one of each and position them some...

go to "Adding Controls" and click on "New Control" (top left - print out the diagram I did if needed for reference)

now we get a long drop down, first we need some sort of slider control... it isn't hard to find being called
"GuiSliderCtrl"

so click it when you see it ( might need to scroll down )

now you should see something like this


but thats not quite how we want it... so simply grab the little black handles and drag it out to a more acceptable size

more like this


note: if you ever lose the handles just click on the slider itself and it should re-select

next go to "New Control" and find a text control - now this one we have a couple options, we will go with the most basic of them though
"GuiTextCtrl"
click it and this is what you get



now thats definately not the right size lol... so grab those little handles and resize (also keep in mind if you ever lose the handles and in this case its very small to try and reselect, you can go and branch down in the right menu and select it there)

once you get it bigger (keep in mind this is a label for the slider) you can now notice that the slider is definately too high to put a label over it... ok so how do we reselect the slider... well since its big enough we can simply click it, but when we do the text box completely disapears... before we deal with that move the slider down some like this



now since we made the text control bigger and because it also was placed after the slider we can still click it... however lets find another way to selec things a bit more specific... go to the right "GUI Control List"... and click the "+" next to slidersGUI... now you should see




from here you can select the "GuiTextCtrl" easily

now move it above the slider where it could server as a label, like this



next go to "New Control" and find a button control - you guessed it
"GuiButtonCtrl"...
click it and move it down below the slider

should look something like this



ok... before we save and leave the GUI editor lets set some simple values first so for those that choose to use the editor more can have a starting place.

select GuiTextCtrl in the right GUI Control list... now go down to the Property List and scroll till you find the "text" property... put "Label" in it and click the "APPLY" button... now you should see



you can change the buttons text the same way... just remember if you change things on the property list always click "APPLY"

ok now click on File -> Save GUI...

you ought to see something like this



click on the top drop down "common"

and change that to
"T2D/client"
then click save... this way it saves it to the folder we're used to accessing

Now you've created a basic GUI... now we can go into the slidersGUI.gui file we created and edit it manually (just like script)

ok the easiest way to exit out of this is to bring up the console with the "~" tilde key... then type "quit();" and hit enter...

now browse down to your T2D/client folder and open the "slidersGUI.gui" file


you should see the following

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

   new GuiSliderCtrl() {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "2 19";
      extent = "174 45";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };
   new GuiTextCtrl() {
      profile = "GuiTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "57 5";
      extent = "26 18";
      minExtent = "8 2";
      visible = "1";
      text = "Label";
      maxLength = "255";
   };
   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "25 59";
      extent = "140 30";
      minExtent = "8 2";
      visible = "1";
      text = "Button";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---



This is what you created in the GUI editor... I like working with these figures in script vs the editor, though as you can see there ar ea handful of default properties to each type of control, so its best to create at least the first one in the editor, save out, then you can copy and modify in script... (or you can do this part in the editor of you so choose :) )


ok lets start with

new GuiControl(slidersGUI) {
   profile = "GuiDefaultProfile";
   horizSizing = "right";
   vertSizing = "bottom";
   position = "0 0";
   extent = "640 480";
   minExtent = "8 2";
   visible = "1";


similar to all script you see "new GuiControl(slidersGUI){"

just create a new "GuiControl" and naming it "slidersGUI"... just like when we create a new fxStaticSprite2D and name it "Block0"

beyond this we are setting some starting values...

profile = "GuiDefaultProfile";

all Gui's work off of a profile, so you can create your own profile with font colors etc and then set the controls to that profile... you can find the starting profiles in
Torque 2D\SDK\example\common\ui\defaultProfiles.cs
you an also create your own profile (as we will later on)

the next two lines...
horizSizing = "right";
vertSizing = "bottom";


you get 5 horizSIzing options
Right
Wdith
Left
Center
Relative

and 4 vertSizing options
Bottom
height
Top
Center
Relative


this is straight from the source code

    enum horizSizingOptions
    {
        horizResizeRight = 0,   ///< fixed on the left and width
        horizResizeWidth,       ///< fixed on the left and right
        horizResizeLeft,        ///< fixed on the right and width
        horizResizeCenter,
        horizResizeRelative     ///< resize relative
    };
    enum vertSizingOptions
    {
        vertResizeBottom = 0,   ///< fixed on the top and in height
        vertResizeHeight,       ///< fixed on the top and bottom
        vertResizeTop,          ///< fixed in height and on the bottom
        vertResizeCenter,
        vertResizeRelative      ///< resize relative


This is affected when the parent control (the one above it in the GUI Control Listing - if there is one) causes it to resize

next we have

position = "0 0";

this is what you might've guess... first number is x second it y... one thing to keep in mind is that this is relative to the parent control... so lets say the parent control is only taking up the bottom right corner of the screen, this would make the position "0 0" be at the starting point in the bottom right of the screen for example



Another thing to remember is the first control is always resized to the full extents of the screen... this keeps your main control the size of the resolution even when changed... In this case this is the first control, so if later we loaded this up no matter what setting we put it would go the size of the screen; however if we "add" it to another GUI it then becomes a child of that GUI and uses the positions correctly

remember the locations in the GUI are different than the locations in Torque 2D

ok moving on

extent = "640 480";

now this is the "extent" of the control... the position sets where it starts, this sets how far in the x and y direction it goes... (remember again the first control is always resized to fit the screen)

minExtent = "8 2";
visible = "1";


these are fairly self explanitory... minExtent is the minimum extents and visible toggles whether it is visible or not... visible is very useful considering you can toggle GUI properties like any other... in this case you can do th is

slidersGUI.setVisible(0);

and then it would become invisible

what you may notice in this GUI control (vs all the ones further down) it doesnt have an end bracket
"};"

however, if you look at the end of the GUI file you can see an extra "};"... this means that all of the other controls are children of this control... this also means if we set this to not be visible all the child controls are hidden as well... can have some nifty control manipulation depending on how you set things up.

ok, instead of re-explaining everything I'll just point out some unique properties for each different type of control

GuiSliderCtrl - Unique Properties:

range = "0.000000 1.000000";
ticks = "10";
value = "0.5";


range is the starting and ending range for the slider... in this case it will go from 0 - 1...

ticks are the ammount of little tick marks

value is the starting value of the slider... presently set in the middle at 0.5 by default


GuiTextCtrl - Unique Properties:

text = "Label";
maxLength = "255";


text you already know is the visible text of the control... if we named it "textBox"... then we could do
textBox.setText("textBox");
to set the text...
maxLength is what you might have guessed, the maximum ammount of characters

GuibuttonCtrl - Unique Properties:

text = "Button";
groupNum = "-1";
buttonType = "PushButton";



text you already know will change the display text on the button
groupNum comes into use when you do radio buttons or similar and just want one button out of a group active at once
buttonType is the different type of button types... I won't get into this considering this could be a tutorial on its own



ok so now you should have a pretty good understanding of how each of these controls work, how to place them in the editor, how to save out a gui file... and how each has special properties and at least have a concept of what they do (if not then I suggest you re-read the tutorial to this point, or maybe skim it)


---------------------------------------------------------
Step 4: Creating all of the GUI Controls - back
---------------------------------------------------------

Now that we have some beginning GUI controls we can then copy and past these to our desired configuration... I just use the GUI editor to create a barebones example of all the properties I need then copy, paste, and modify

Before we do that lets do one more thing... as you notice these are all using the default profile; however, the default text color is black, that is very hard to see on many backgrounds (including the one here)... so lets create our own profile, its really not that hard... here is the code (place it at the beginning of the slidersGUI.gui file)

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



nothing new or mysterious here, some font colors and autosizing setting... the one thing that might be new is the
if(!isObject(


In this case we are simply making sure we haven't created the gui profile already, if we haven't then we create it... this statement can be useful for any script testing... simply put the object name in the ()'s that you want to test.... now we have a profile called "GuiPhysicsTextProfile"... (to example the default profiles check out the "defaultProfiles.cs" file in "Torque 2D\SDK\example\common\ui"

all I did was copy the default text profile and change the font color and name :) not very hard to make profiles.

ok now we want to switch out the "GuiTextProfile" with "GuiPhysicsTextProfile" (it should make the text red)...

now your entire slidersGUI.gui file should look like this

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 0";
   extent = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiSliderCtrl() {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "2 19";
      extent = "174 45";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };
   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "57 5";
      extent = "26 18";
      minExtent = "8 2";
      visible = "1";
      text = "Label";
      maxLength = "255";
   };
   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "25 59";
      extent = "140 30";
      minExtent = "8 2";
      visible = "1";
      text = "Button";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---




ok, well before we worry about making the gui do something we should finish our layout, we need more sliders and need everything placed correctly.

now positioning can be done for the most part in the editor if you like, personally I like working with numbers especially since I can see the height (the second number under "extent") and place everything in equal intervals quickly as easily... lets start by positioning our main control

new GuiControl(slidersGUI) {
   profile = "GuiDefaultProfile";
   horizSizing = "right";
   vertSizing = "bottom";
   position = "0 0";
   extent = "640 480";
   minExtent = "8 2";
   visible = "1";


so right now it starts at "0 0"... in the end we will be adding this to the main gui for Torque 2D; however, we don't want it to overlap the drop-down menus, so we will move it down some
position = "0 20";

Here is where we can make structural changes as well, considering we have the text label 'above' the slider lets move it so it is listed before the slider (it doesn't really change much, just easier to set positions when everything is in proper order, plus easier to edit later)

so

new GuiSliderCtrl() {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "2 19";
      extent = "174 45";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };
   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "57 5";
      extent = "26 18";
      minExtent = "8 2";
      visible = "1";
      text = "Label";
      maxLength = "255";
   }


becomes

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "57 5";
      extent = "26 18";
      minExtent = "8 2";
      visible = "1";
      text = "Label";
      maxLength = "255";
   };
   new GuiSliderCtrl() {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "2 19";
      extent = "174 45";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };


ok so lets position the text control

we want it to be out some but we it can also start at the top of the limits of the parent (remember since we set the parent control to be "20" down the y, now all of its child controls "0" is really a global "20"...

so we can set its poisition to
position = "75 0";

that way its 75 units out from the x axis so it is more centered over where the slider will be and right at the top of its parent control at "0" (we're going to need to keep as much room for all the sliders as we can)

also change the extents to this
extent = "35 18";
(note: you can modify your extents to what you want, this seemingly works well for mine - again this can be done in the GUI editor, what helps is setting sizes like this and basic positions in the GUI Editor, then doing copy and paste actions here)


ok now what about the slider...

we want the slider to start all the way against the left border (to keep as much out of the main screen as possible), but want it just a little bit down so the text doesnt overlap it... so set its position to

position = "0 10";

this way the text nicely titles it without getting in the way (keeps everything tight and compact as well) - this is just the way I do it, feel free to change your own layout :)

set its extents to this as well

extent = "205 40";


ok, well now we have the button, except in the Physics Demo I only have 2 buttons and all the way at the button, so for now we can forget about the button for now, so click in front of it (right before "new GuiButtonCtrl() {") and hit enter a couple times to keep it out of the way, then set its visible property to "0", that way we won't see it for now. Now you should have this

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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 0";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Label";
      maxLength = "255";
   };
   new GuiSliderCtrl() {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 10";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };





   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "25 59";
      extent = "140 30";
      minExtent = "8 2";
      visible = "1";
      text = "Button";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---




lets name everything a bit more accurately too... first lets list all the sliders we're going to have

Friction
Restitution
Relaxation
Density
Damping
Max Angular Velocity
Max Linear Velocity
Constant Force Direction
Constant Force Speed
Impulse Force Direction
Impulse Force Speed

quite a bit, but don't get scared (if you are that is)... we set one up nicely and copy and paste and change the names and position and thats the layout end of it... ok lets set some better names up now

go to the text control and change
text = "Label";
to
text = "Friction";

then go to

new GuiSliderCtrl()
and change it to
new GuiSliderCtrl(guiFrictionSlider)

this does the same thing we did back in the scripting for creating blocks, by putting a name in here we can now reference this later and manipulate the settings (we will need to reference this to make it change our physics settings realtime)


ok so theres one slider... Well in the Demo we have 11 sliders (which means 11 text controls as well)... this is where copy and paste come in handy :)... now we're going to position each of these manually; however, later you can learn to do loops to position these, etc etc... this is all scripting so you can do things dynamically as well.

but for now lets to it manually, that way we get everything looking and working just right... highight the entire text control and slider control... copy it (ctrl + c)... then click after the slider control (where there should be a gap between it and the button control)... and paste ite (ctrl + v)..

now we have a new text and slider control in the same position as the old...
now all we need to do is change the position values and name values.. (since we set everything else up for now)...

change the text control position to
position = "75 40";

note: the 75 remains the same; however, the 40 is gotten by taking the position of the slider... 10... adding the extent of the slider... 40... = 50... then subtracting 10 (since the slider should have some extra space to give on the bottom) to make it "40"... you can try different distances, this is where I'd suggest firing up the GUI editor and testing out distance, then you can save it off and change the script...

make text

text = "Restitution";

change the position of the slider to

position = "0 50";

(this was gotten by simply adding 10 y to the text control position, same method we used on the first one)

and the name of the slider to

new GuiSliderCtrl(guiRestSlider)


you can notice now that we have a patern... the new text control is 40 y more than the first one and the new slider control is 40 y more than the first one... this makes it easy to set the rest up, you simply add 40 to each y... just don't forget to change the names...

now I will simply list the setting needing to change for each set, so you can copy the second set, paste it as the third set and set these setting (or do it yourself since you now know the layout):

set 3:
Text Control:
position = "75 80";
text = "Relaxation";

Slider Control:
new GuiSliderCtrl(guiRelaxSlider)
position = "0 90";


set 4:
Text Control:
position = "75 120";
text = "Density";

Slider Control:
new GuiSliderCtrl(guiDensSlider)
position = "0 130";


set 5:
Text Control:
position = "75 160";
text = "Damping";

Slider Control:
new GuiSliderCtrl(guiDampSlider)
position = "0 170";


set 6:
Text Control:
position = "75 200";
text = "Max Angular Velocity";

Slider Control:
new GuiSliderCtrl(guiMaxAngularSlider)
position = "0 210";


set 7:
Text Control:
position = "75 240";
text = "Max Linear Velocity";

Slider Control:
new GuiSliderCtrl(guiMaxLinearSlider)
position = "0 250";


set 8:
Text Control:
position = "75 280";
text = "Constant Force Direction";

Slider Control:
new GuiSliderCtrl(guiForceDirecSlider)
position = "0 290";


set 9:
Text Control:
position = "75 320";
text = "Constant Force Speed";

Slider Control:
new GuiSliderCtrl(guiForceSpeedSlider)
position = "0 330";


set 10:
Text Control:
position = "75 360";
text = "Impulse Force Direction";

Slider Control:
new GuiSliderCtrl(guiImpulseDirectionSlider)
position = "0 370";


set 11:
Text Control:
position = "75 400";
text = "Impulse Force Speed";

Slider Control:
new GuiSliderCtrl(guiImpulseSpeedSlider)
position = "0 410";


ok, as you can see its a very distinct pattern,

lets make a couple modifcations so we can test this...

before we can access this in the game engine we need to have it executed somewhere... this means basically we have to tell it to load this .gui script somehwere... open your "client.cs" file


find

exec("./mainScreenGui.gui");


and add after
exec("./slidersGUI.gui");


now we can access it in the drop down of present Gui's in the GUI Editor... to make it automatically load up into the mainScreen (note into, not over) find this code a couple lines down



Canvas.setCursor(DefaultCursor);
and add after
mainScreenGui.add(slidersGUI);


pretty simple! Now it will be loaded as a part of it (that way we can still use the buttons in the main GUI...


ok now save the client.cs file (and make sure the slidersGUI.gui file is saved also - on a side note, its a good idea to save frequently- I know I know- "duh" your probably saying lol)..

now fire up T2D.exe and you should see this




if not compare your code (for slidersGUI.gui to this, this is where you should be at

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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 200";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 240";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 280";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceDirecSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 290";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 320";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 330";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 360";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 400";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };








   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "25 59";
      extent = "140 30";
      minExtent = "8 2";
      visible = "0";
      text = "Button";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---


remember if you load the game and nothing has changed its always a good idea to hit the "~" tilde key and scroll through the console looking for red text... that means theres a syntax error and it will usually place you around the error


Ok, so we have our sliders... however they are all at the same limits... they all go from 0 - 1... lets look at what we need for each slider

Friction:
should be set to

0 - 0.5

(how do we do this...?)

change the
range = "0.000000 1.000000";

under guiFrictionSlider to

range = "0.000000 0.500000";


Restitution:
this is fine at 0 - 1


Relaxation:
this is fine at 0 - 1


Density:
this is fine at 0 - 1


Damping:
this I have set to 0 - 5
so
range = "0.000000 5.000000";


Max Angular Velocity:
this should be much higher, I'm using

0 - 5000

range = "0.000000 5000.000000";


Max Linear Velocity:
this should be higher also, I'm using

0 - 2000

range = "0.000000 2000.000000";


Constant Force Direction:
this should be 0 - 360 degrees

range = "0.000000 360.000000";


Constant Force Speed:
I have this set to 0 - 5000

range = "0.000000 5000.000000";


Impulse Force Direction:
this should be 0 - 360 degrees

range = "0.000000 360.000000";


Impulse Force Speed:
I have this set to 0 - 5000

range = "0.000000 5000.000000";



ok now your code should look like this


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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 200";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 240";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 2000.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 280";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceDirecSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 290";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0.5";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 320";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 330";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0.5";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 360";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 400";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0.5";
   };








   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "25 59";
      extent = "140 30";
      minExtent = "8 2";
      visible = "0";
      text = "Button";
      groupNum = "-1";
      buttonType = "PushButton";
   };
};
//--- OBJECT WRITE END ---


and when you fire up T2D.exe it should look like this



so now the sliders can slide through the range we set... now they all still have the starting value of 0.5... this can be bad later on, especially with linear velocity bieng at .5, so if we were to send a block off now it would not work too well (the block would hardly move)... so set these starting values by changing the "value" property of each

Friction
value = "0";

Restitution
value = "1";

Relaxation
value = "0.5";

Density
value = "0.01";

Damping
value = "0";

Max Angular Velocity
value = "0";

Max Linear Velocity
value = "400";

Constant Force Direction
value = "0";

Constant Force Speed
value = "0";

Impulse Force Direction
value = "0";

Impulse Force Speed
value = "0";


now when you fire T2D.exe up it should look like this



so now we have all of our sliders... all we need is to finish the button we have and then create a second button, one for sending the impulse force, the other for creating a block on the fly

change the existing button settings to match these

   new GuiButtonCtrl() {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 440";
      extent = "80 15";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force!";
      groupNum = "-1";
      buttonType = "PushButton";
   };


nothing fancy here, we change the position so its below all the sliders, change the name to "Impluse Force!" and then set it visible...

add this button below the existing button (but still inside that last bracket "}")

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


it should now look like this




if not then check your code against this

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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "1";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.1";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 200";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 240";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 2000.000000";
      ticks = "10";
      value = "400";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 280";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceDirecSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 290";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 320";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 330";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 360";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 400";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "205 40";
      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";
      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";
      text = "Add a Bouncy Block";
      groupNum = "-1";
      buttonType = "PushButton";
   };

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




ok well if all looks well then your gui layout is done!... not bad, really isnt that much work, considering we have a pretty hefty gui interface, 11 sliders, 11 text controls, and 2 buttons !

ok now on to the scripting end of the GUI... we can add this right after the "//--- OBJECT WRITE END ---"
just enter down a couple times to create some space (at the moment we shouldn't have to touch the gui, at least for now)


---------------------------------------------------------
Step 5: Creating the Script for the GUI - back
---------------------------------------------------------

ok now its time to get our hands dirty with some script... I know at first it gets intimidating working with script, especially working with handling data... so I'll try and take it step by step and hopefully you cannot only get a Physics demo, but some good scripting techniques as well as data handling in TorqueScript.


ok lets think things out a bit first...

we want to be able to continually set certain values when we move the sliders... that means we need a function to call, we can pass it the value to set...

now one way to go about this is to create a function for each parameter

something like this
function setDensity(%val)
{
	object.setDensity(%val);
}

function setFriction(%val)
{
	object.setFriction(%val);
}

function setDamping(%val)
{
	object.setDamping(%val);
}

(note this is very much not funciton script, just conceptual psuedo code)

well thats one way to do it, then we would have a good 8-9 functions though... if we look at the syntax for the setting of these values they are very similar... "setDensity"..."setFriction"... all starting with "set" then just adding the parameter... so what if we did something like
function set(%type, %val)
{
	object.set(%type)(%val);
}

(again not function code, just conceptual)

ok, now that helps cut down on things, makes it much more efficient (also helps us make more clever code)...

now as you might have guessed, thats not acceptable syntax; however that can be done... let me show you how

ok this part is fine
function set(%type, %val)
{
	eval("object.set" @ %type @ "(%val);");
}

ok now your introduced to the very powerful "eval()" function

what this does is take a string and execute it like a command or function...

so you could do
eval("echo(test)");

would echo "test" to the console... now combined with the "@" you can combine things not only into what you pass the functions (which you can already) but into the syntax of the function call itself

so

if the set() function was called like this
set(Friciton, 0.5);

then
eval("object.set" @ %type @ "(%val);");

would really be
eval("object.setFriction(0.5);");

as you can see this is extremely useful... can be used to save much time (in this case cutting at least 5-6 simliar function calls down to one)...

now
function set(%type, %val)
{
	eval("object.set" @ %type @ "(%val);");
}


doesn't quite work for us... for one "object" doesnt really exist... and two we are not setting just one objects parameters, we're setting all of the boxes... now this goes back to Part 1 of this tutorial... where I had you do some things to prepare for this...

if you can remember I had you create these variables
$blocks::names[]
$blocks::ammount

(if you can't remember then open your "bounce.cs" and refresh your memory :)

$blocks::names[] is an array of all the names of the blocks we created and
$blocks::ammount is the ammount of them (though we have it incremented one ahead)

so in our set function we really need a loop rather than just a single line

lets start our loop

for(%i=0;%i<$blocks::ammount;%i++)

ok for those who know what a for loop is this probably makes sense... for those that don't (or are still unsure) I'll explain

we start with

for(%i=0


thats just setting a new local variable called %i = 0... then

for(%i=0;%i<$blocks::ammount


this is now saying, %i = 0... and ... do this loop while %i is less than $blocks::ammount (which we already know is the count of blocks we create)

finally we have

for(%i=0;%i<$blocks::ammount;%i++)


the %i++ means that it will increment %i each time it looks... that way it starts at 0... then cycles through until we hit the last block... now since $blocks::names[] is an array from 0 to however many blocks we have, this is very useful, since we can use this loop to cycle through all the blocks in existance... fairly nifty

so we do this
for(%i=0;%i<$blocks::ammount;%i++)
{
	eval($blocks::names[%i] @ ".set" @ %type @ "(%val);");
}

lets see how this cycles through... lets say $blocks::ammount = 5;... %type = Friction... lets say %val = 0.5... and lets say $blocks::names[0] = Block0.... $blocks::names[1] = Blocks1 etc etc... up to $blocks::names[4]... (being the fifth one from 0-4)

first loop
	eval($blocks::names[0] @ ".set" @ Friction @ "(0.5);");

which is the same as
	eval(Block0 @ ".setFriction(0.5);");

which is the same as
	Block0.setFriction(0.5);

now on the next loop it would be
	Block1.setFriction(0.5);

and so on until %i = 5... which then %i would no longer be less than 5 ($blocks::ammount) and the loop would end...

so as you can see this is quite an effective way to set the value of all the blocks we have created...

ok... now we're almost done with this function

so right now we have this

function set(%type, %val)
{
	
	for(%i=0;%i<$blocks::ammount;%i++)
	{
		eval($blocks::names[%i] @ ".set" @ %type @ "(%val);");	
	}
	
}



Now this would work fine... however we want to be as efficient as possible... so we wont leave this as a universal function, we will make a namespace function... the only difference is it becomes this

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


instead of
function set()

it becomes

function slidersGUI::set()

we're making it a part of the GUI object... also you might notice we pass the first variable of %this...

when we make a namespace function it always passes itself as the first object, in this case it passes "slidersGUI"... this can be very helpful if we want the function to do things to effect the GUI control itself, or even if we want it to call another namespace function... to call this function now we would do

slidersGUI.set(Friction, 0.5);


say we created another function like this

function slidersGUI::test(%this)
{
	echo("test");	
}


to call that function in the slidersGUI::set() function we would just do

%this.test();

since %this is equal to slidersGUI... you can see how this can be powerful, it helps when you change function names too, you don't have to reaplace everything before the dots... since it uses "%this"...


so now that should be it... well it could be, but we're going to add a debuging message as well... as we all know its always good to have a sure way to make sure the function runs correctly...

so we add this line after the eval line, the result is this whole function

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);
	}
}




ok, if your not familiar with the "echo" command already let me give you a quick run down... echo is a way to display text to the console (you bring up the console in game by pressing the "~" tilde key, or by checking the console.log file after you run the application - this file is in the same directy as T2D.exe)... This is a great way for debuging since you can have it echo variable values as well...

the syntax is this
echo("test");

this would echo the word "test"...

you can combine strings as well... with @

echo("test" @ "test");

this would echo the words "testtest"

now say we wanted a space and we didnt want to manually add one to the strings... we could do this

echo("test" SPC "test");

this would echo the words "test test"

we can also echo variables

%var = 10;
echo(%var);

this would echo "10"

we can combine strings and variables as well...

echo("test" SPC %var @ "test");

this would echo "test 10test"

as you can see this can be very helpful in debuging... ok back to the code.....


so we have this run each time it loops
echo("Setting the" SPC %type SPC "to" SPC %val);

which would echo "Setting the Friction to 0.5" in our present examples...
theres one final thing we should do before testing it... what we're doing right now is setting all of the existing blocks property (the nifty loop and eval thing)... though what about the new blocks, they get their settings off of the datablock (as explained in step 1)... so lets add one more line to change the datablock settings so all the new blocks will get the same - add this line after the loop since we only want it to set once and not each loop

eval("bouncyMaterial." @ %type @ "=" @ %val @ ";");


this is basically calling this function in this example

bouncyMaterial.Friction = 0.5;

fairly simple, just setting the bouncyMaterials friction to 0.5


ok so we've seen a lot of code, now its time to test it...

go to your client.cs and uncomment the line I had you comment before... the

pongBounce();


fire up the T2D.exe...

bring up the console with the tilde "~" key... and type this in the console...

createBlock();


press the Up arrow (it should bring the "createBlock();" command up again) press enter, repeat this a couple times to get a few more blocks in there and make it more interesting

like before this shoot create a block that bounces around... now lets test our new function

type this in the console

slidersGUI.set(Friction, 0.5);


you should see this



if you get red text that says "syntax error" or something else, check your code to this... (note this is how the entire file, including the GUI we havent touched in a while, should look)

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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "1";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.1";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 200";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 240";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 2000.000000";
      ticks = "10";
      value = "400";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 280";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceDirecSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 290";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 320";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Constant Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiForceSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 330";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
   };	

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 360";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 400";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "205 40";
      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";
      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";
      text = "Add a Bouncy Block";
      groupNum = "-1";
      buttonType = "PushButton";
   };

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




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 @ ";");
	
}




ok so we have this working, this will work for most of the function calls, however setting constant forces and impulse forces require two paramaters being set, not just a value, but a direction... so right now the best way to do this would be to create a new function, since I explained the last function I'll just show you this one...

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);
	}
}


nothing too new... same loop, the only different is its passing %direc and %speed... and calls
.setConstantForcePolar(%direc, %speed);

the debug echo statement is basically the same too, nothing unique... you can add this function right after the set function...

save it and fire up T2D.exe

inside the game bring up the console with tilde "~" and type in the command

createBlock();

press enter

press the Up arrow (it should bring the "createBlock();" command up again) press enter, repeat this a couple times to get a few more blocks in there and make it more interesting

then type the command
slidersGUI.setForce(180, 400);


you should see the following result in the console



now we only have one more function, the impulse force function

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);
	}
}



save it and fire up T2D.exe

inside the game bring up the console with tilde "~" and type in the command

createBlock();

press enter

press the Up arrow (it should bring the "createBlock();" command up again) press enter, repeat this a couple times to get a few more blocks in there and make it more interesting

then type the command
slidersGUI.setImpulse(180, 400);


you should see the following result in the console



(note I ran the function three times)


ok good so far... so now that we have this function, what about linking it to the GUI? That would be a good next step, we have the GUI, the layout, and the functions, now we just need to make the GUI call these functions... how do we do that ?

surprisingly its quite simple... we can add a nifty little property to the slider and button controls called "command"...

let me show you... go to the friction gui... it should look like this right now

   new GuiSliderCtrl(guiFrictionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 10";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
   };


now lets add

command = "slidersGUI.set(Friction, guiFrictionSlider.value);";

so it should be

   new GuiSliderCtrl(guiFrictionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 10";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
      command = "slidersGUI.set(Friction, guiFrictionSlider.value);";
   };


save it and fire up T2D.exe

inside the game bring up the console with tilde "~" and type in the command

createBlock();

press enter

press the Up arrow (it should bring the "createBlock();" command up again) press enter, repeat this a couple times to get a few more blocks in there and make it more interesting

now close the console with the "~" tilde key and slide the Friciton slider a couple of times... now bring the console up again, you should see the echo messages, something like this



ok were going good... now lets add the command property to the other sliders...

I'll simply list them then show the resulting GUI file...

command = "slidersGUI.set(Restitution, guiRestSlider.value);";

command = "slidersGUI.set(Relaxation, guiRelaxSlider.value);";

command = "slidersGUI.set(Density, guiDensSlider.value);";

command = "slidersGUI.set(Damping, guiDampSlider.value);";

command = "slidersGUI.set(MaxAngularVelocity, guiMaxAngularSlider.value);";

command = "slidersGUI.set(MaxLinearVelocity, guiMaxLinearSlider.value);";

now we get to the forces, the commands will be a bit different though the same in nature (we've already tested these manually anyways) we're now calling the .setForce command we made and pass it the value of the degree slider, then the value of the speed slider, we have the same function for the direction and speed sliders so it updates when we move either slider

command = "slidersGUI.setForce(guiForceDirecSlider.value, guiForceSpeedSlider.value);";
(this is the same command for both the direc and speed sliders)...

ok we don't need to put anything for the impulse ones since we want it to happen when we click the impulse button... so lets go down to the impulse button and add a command the exact same thing.

command = "slidersGUI.setImpulse( guiImpulseDirectionSlider.value, guiImpulseForceSlider.value );";

very similar to the constant force slider call...

now we're finally down to the last button... the create block button... fortunately this is the easiest of all... simply add

command = "createBlock();";


now your GUI should look like this

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 = "640 480";
   minExtent = "8 2";
   visible = "1";

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 0.500000";
      ticks = "10";
      value = "0";
      command = "slidersGUI.set(Friction, guiFrictionSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "1";
      command = "slidersGUI.set(Restitution, guiRestSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.5";
      command = "slidersGUI.set(Relaxation, guiRelaxSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 1.000000";
      ticks = "10";
      value = "0.1";
      command = "slidersGUI.set(Density, guiDensSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5.000000";
      ticks = "10";
      value = "0";
      command = "slidersGUI.set(Damping, guiDampSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 200";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 5000.000000";
      ticks = "10";
      value = "0";
      command = "slidersGUI.set(MaxAngularVelocity, guiMaxAngularSlider.value);";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 240";
      extent = "35 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 = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 2000.000000";
      ticks = "10";
      value = "400";
      command = "slidersGUI.set(MaxLinearVelocity, guiMaxLinearSlider.value);";
   };

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

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

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 360";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Direction";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseDirectionSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 370";
      extent = "205 40";
      minExtent = "8 2";
      visible = "1";
      range = "0.000000 360.000000";
      ticks = "10";
      value = "0";
   };

   new GuiTextCtrl() {
      profile = "GuiPhysicsTextProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "75 400";
      extent = "35 18";
      minExtent = "8 2";
      visible = "1";
      text = "Impulse Force Speed";
      maxLength = "255";
   };
   new GuiSliderCtrl(guiImpulseSpeedSlider) {
      profile = "GuiSliderProfile";
      horizSizing = "right";
      vertSizing = "bottom";
      position = "0 410";
      extent = "205 40";
      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";
      text = "Impulse Force!";
      groupNum = "-1";
      buttonType = "PushButton";
      command = "slidersGUI.setImpulse( guiImpulseDirectionSlider.value, guiImpulseSpeedSlider.value );";
   };

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

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




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::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::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 save... fire up T2D.exe and create a bunch of blocks... test out each of the sliders as well, make sure they all work... I'd recommend first setting some impulse speed, then firing an impulse at 0 degrees (straight up)... then try increasing the constant force, they should all float up... then increase the damping, it should cause them to slow down some


well you got yourself a full Physics Demo that you now know how to create :) I hope you enjoy Torque 2D!!!

- Matthew "King BoB" Langleyd