T2D Tutorial (Part 3) Mouse Selection and Following
by Matthew Langley · 04/17/2005 (7:38 pm) · 5 comments
T2D Tutorial (Part 3) Mouse Selection and Following
Ok here is that Part 3 I was mentioning... but we already covered the simple and the complex way of Mouse Following... well this will focus on all those silly "echo" statements I had you make, we will be combining them into a nifty little Debug Gui that will help us with debuging... You need to have gone through the last tutorial before you go through this one! :) Ok ok I'm not that mean to say you can't go through this one if you haven't gone through the last one lol... here is where the last one ends... take this coede and paste it into a new .cs file called complexMouse.cs in the same folder as client.cs
now create a new .cs file (if you didn't in the last tutorial)... called "exec.cs"...
add this line to it
now add this exec statement into your client.cs (right below the other exec statements)
scroll down a little and add the function call
after
ok now you should be cot up to speed... if you fire up T2D you should be able to click the box in the middle of the screen and move it, then click again and drop it...
ok as you notice in our code we added a lot of debug echo statements... now we will use them a bit more effectively... but first we need to create a new gui... fire up T2D and hit "F10"... you should see this

now click File -> New Gui...
in GUI Name: put DebugGui
change Class to GuiWindowCtrl
it should look like this

now click "Create"
now you should see something like this

click on "New Control" in the top left

then scroll down and go to "GuiPopUpMenuCtrl"

then click it... now move the new control and stretch it to about here

now click "New Control" scroll down to GuiScrollCtrl and click it and place it about here

and finally click "New Control" and scroll down to GuiMessageVectorCtrl and click it and place it about here

don't worry about being too precise, you can modify this later
now click File -> Save GUI... look up top where you see Directory: then probably "common"... click that and scroll down and select "T2D/client" (or if your working in a different directory choose that)
like this

click save
now hit the "~" tilde key to bring up the console... type in the command
quit();
hit enter and it should exit Torque 2D...
now go to your T2D/client folder and find your "DebugGui.gui"... open it with wordpad/notepad (or your script editor of choice)...
you should see this
lets name some of these controls so we can utilize them in script
change
to
change
to
and change
to
ok now since they have names we can reference them in script
now we need to restructure this a bit... we want the messageVectorCtrl to be a child of the scroll ctrl... so we delete the "};" thats right before
new GuiMessageVectorCtrl(DebugVector) {
and then add one right before
//--- OBJECT WRITE END ---
like this
In this gui we have two new gui types we haven't approached before... (unless you've done some tinkering on you r own)... the first is
guiPopUpMenuCtrl
and the second is
guiMessageVectorCtrl
ok... first the PopUpMenuCtrl is what it seems, a pop up menu... you know that save gui that poped up when we tried to save our .gui file... thats drop down we click on to change to "T2D/client" was this same gui type...
the next is guiMessageVectorCtrl... this is a message vector that we can add text lines to and clear out... if you've played Tribes / Tribes 2, the message HUD is made up of these. The nice thing is you can create a "MessageVector" then "attach" it to the "GuiMessageVectorCtrl"... but you can detach it and re-attach it to another one... it also works well for what we're doing
ok... so what do we do now ? well first lets make sure this gui execs... so go to your exec.cs... and add this line
(this is much easier than having to continually go into the client.cs :)
ok, now that we did that (to ensure we won't forget later)... go back to your .gui file... add this function at the bottom of it
ok, one nice thing about GUIs is they have this built in callback... "onWake()" so we can tell it what to run when it starts
notice we do "DebugGui::onWake(%this)"... this will pass itself into %this if we want to refer to it
the first line
new MessageVector(DebugText){};
create a new message vector (as I mentioned you can add and clear text from these then attach and detach them from the guiMessageVectorCtrl)... we name it "DebugText".
the next line we take the guiMessageVectorCtrl and .attach the DebugText message vector to it (as I mentioned)...
then we add a few entries into the DebugList
first we add None at 0...
then callBacks at 1
and selection at 2
we also specify a count of $debugCount = 2;
you might recognize "callBacks" and "selection"... if you look at your complexMouse.cs you will notice
$debugMsg::mouse::callBacks
and
$debugMsg::mouse::selection
as you can start to tell (probably) this gui will have some sort of effect on the debug messages...
lets test what we have... open your complexMouse.cs and find the "complexMouse" function and add
to it, like this
this will add our DebugGui to the mainScreenGui when we start up
save this .gui file and fire up T2D...
you should see something like this

now click the popUp like this

and you should be able to select the options we included, though presently it doesnt do anything...
ok now close T2D down (go to console and type "quit();")
and now add this function bellow the last one
ok this function is attached to our popUp... DebugList... as you can assume this function is called when we select something out of the list, passing the id number... the 0,1, and 2 we specified
then we clear the vector
this is important so that every time we change our selection it clears out the old text
the next set of code (the for loop) might look a little confusing
it starts at 1 and loops while less than or equal to $debugCount... which is 2
and the eval function just takes a string and executes it... in this case just setting a variable...
%this.getTextById() returns the text of the ListItem by the id... so if you put 1 in there it will return "callBacks"... 2 "selection" etc...
so basically this loop works like this
loop 1
$debugMsg::mouse::callBacks = false;
loop 2
$debugMsg::mouse::selection = false;
so basically this function so far clears the messageVector then sets our two debug variables to false... (basically reseting everything)...
the next set is this
this will set whichever %id we have selected to true... so if we were to click on the "selected" text in the pop up it would do this
$debugMsg::mouse::selection = true;
which will enable the debug messages for that selection...
so basically we select a pop up, it resets them then sets the one we selected to display... nifty :)
ok save this off... now lets move back to the "complexMouse.cs"
ok, we need to create a helper fu nction, to do something with that message vector...add this to the end of the file
ok... this function we pass it something... it then compares it (string compare) and if its not equal to the last thing passed it will perform this
$lastDebug = %debug;
DebugText.pushBackLine(%debug,0);
which sets teh $lastDebug (to check for next time)
then
DebugText.pushBackLine(%debug,0);
this is how we add text to a messageVector... there are many commands... pushBackLine... pushFrontLine...clear... look in the source code for a whole list of them... it even has a special "dump()" function that saves off a file.
notice the (%debug,0);
the 0 is where you can put a special tag entry, using that you can do some special searches in the vector by tags, also its a way the game system did some pretty advanced text manipulation... for now we will just put 0 since it doesn't matter to us
ok... now this whole function will update the message vector, but we need to now change our "echo(" to "registerDebug("... a quick way is the
Edit -> Replace in wordpad... or wherever the replace tool is in your script editor
replace
echo(
with
registerDebug(
have it replace all ... now your comlexMouse.cs should look like this
before we test this we need to change our gui a bit, right now it fill up the whole screen, we can't really test the debugs for the demo if we can't see the demo lol...
find
change that to
this should position our window a lot better
ok, lets test this... save the .cs and .gui file and fire up T2D
you should see this

select the drop down and select "callBacks"
move your mouse arround (click and move the box some too) you should see the text update like this

now try changing your selection to "selection" (no pun intended lol)... this should clear the messageVector and display something like this... (be sure to click and drag the box some too)

now try changing it to none and move around

and there we go, we have a little debug gui...
if yours doesnt work compare it to this
here is the DebugGui.gui file
here is the
comlexMouse.cs
now you can see how powerful formating all of your debug statements like this is... later you can then create a full status box of all your different properties... this is great for debuging... especially since right now with "selection" you can find out what you select... and no echo statements and no switching to the console ;)... also the box can be moved and minimized.
well the only other thing I could say to add is add a
text = " Debug GUI";
to
new GuiWindowCtrl(DebugGui) {
like this
that way when you fire it up you can tell what the box is for like this

Well this is the final part of that tutorial... I felt I should include a way to keep some good debug information, especially object selection, considering I've used this numerous times while testing things, being able to move them real time etc...
hope you enjoyed them
- Matthew "King BoB" Langley
Ok here is that Part 3 I was mentioning... but we already covered the simple and the complex way of Mouse Following... well this will focus on all those silly "echo" statements I had you make, we will be combining them into a nifty little Debug Gui that will help us with debuging... You need to have gone through the last tutorial before you go through this one! :) Ok ok I'm not that mean to say you can't go through this one if you haven't gone through the last one lol... here is where the last one ends... take this coede and paste it into a new .cs file called complexMouse.cs in the same folder as client.cs
function sceneWindow2D::onMouseMove( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Moving");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDragged( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Dragging");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDown( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Down");
//check to see if we have an object already selected, if so we don't want to do anything expect set it to false so it doesn't follow anymore
if(%this.objectSelected)
{
if($debugMsg::mouse::selection)
echo("unselecting");
if($mouseObj::isObjMounted)
{
if(isObject($mouseObj::objMounted))
{
if($debugMsg::mouse::selection)
echo("dismounting object");
$mouseObj::objMounted.dismount();
$mouseObj::isObjMounted = false;
}
}
%this.objectSelected = false;
} else
{
//lets get a list of all the objects at the clicked point in the t2dSceneGraph
%objList = t2dSceneGraph.pickPoint(%worldPos);
//lets get a count of how many objects in the list
%objCount = getWordCount(%objList);
//we will start looping through the list
for(%i=0;%i<%objCount;%i++)
{
//grabing the entry corresponding to the loop
%obj = getWord(%objList, %i);
//if we find an object in the list that "isSelectable = true"
if(%obj.isSelectable)
{
//we toggle a value so we know we found an object that "isSelectable"
%selected = true;
//we kick out of the loop
%i = %objCount;
}
}
//if we found an "isSelectable" object
if(%selected)
{
//we then store that object as the selectedObj
%this.selectedObj = %obj;
if($debugMsg::mouse::selection)
echo("You have selected:" SPC %obj SPC "with the name:" SPC %obj.objectName);
%this.objectSelected = true;
if($debugMsg::mouse::selection)
echo("echo attempting to mount:" SPC %obj SPC " to mouse obj:" SPC $mouseObj::object);
%obj.mount($mouseObj::object, $mouseObj::mount::offset, $mouseObj::mount::force, $mouseObj::mount::trackRotation);
$mouseObj::isObjMounted = true;
$mouseObj::objMounted = %obj;
}
}
}
function sceneWindow2D::onMouseUp( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Up");
}
function sceneWindow2D::onMouseEnter( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Entered... Knew it would come crawling back");
}
function sceneWindow2D::onMouseLeave( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
echo("Mouse Left... Go Get It!");
}
function initMouse()
{
$mouseObj::object = new fxSceneObject2D() { scenegraph = t2dSceneGraph; };
$mouseObj::object.setSize("1 1");
$mouseObj::object.setLayer(31);
$mouseObj::follow = true;
$mouseObj::speed::max = 250;
$mouseObj::speed::default = 250;
$mouseObj::mount::force = 0;
$mouseObj::mount::offset = "0 0";
$mouseObj::mount::trackRotation = true;
}
function fxSceneGraph2D::onUpdateScene(%this)
{
if(($mouseObj::follow) && (!$mouseObj::stopped))
mouseObjCheck();
}
function mouseObjCheck()
{
// Get the position of the Mouse itself
%x = getWord($mouseObj::pos, 0);
%y = getWord($mouseObj::pos, 1);
// Get the Position of the mounted scene object
%objPos = $mouseObj::object.getPosition();
%objX = getWord(%objPos, 0);
%objY = getWord(%objPos, 1);
// calculate the distance between the two (for speed calculations)
%dist = distBetween(%objPos, $mouseObj::pos);
// Set values for easy configuration
// set speed = distance * 20, that way it slows when approach - no bobbing around
%speed = %dist * 20;
// limit speed if we want to
if(%speed > $mouseObj::speed::max)
%speed = $mouseObj::speed::default;
%space = 0.25;
if((%objX > (%x - %space)) && (%objX < (%x + %space)) && (%objY > (%y - %space)) && (%objY < (%y + %space)))
{
if($debugMsg::mouse::object)
echo("object at mouse position, halting");
$mouseObj::object.setLinearVelocityPolar(0,0);
$mouseObj::stopped = true;
} else
{
if($debugMsg::mouse::object)
echo("object seeking mouse at " @ angleBetween(%objPos, $mouseObj::pos));
//set the polar velocity towards the mouse
$mouseObj::object.setLinearVelocityPolar(angleBetween(%objPos, $mouseObj::pos),%speed);
}
}
function angleBetween(%playerPos, %mousePos)
{
// Seperate Mouse Position
%mxpos = getWord(%mousePos,0);
%mypos = getWord(%mousePos,1);
// Seperate Player Position
%px = getWord(%playerPos,0);
%py = getWord(%playerPos,1);
// Calculate Angle from player to mouse (convert to degrees).
%angle = mRadToDeg( mAtan( %mxpos-%px, %py-%mypos ) );
return %angle;
}
function distBetween(%loc1, %loc2)
{
%x1 = getWord(%loc1, 0);
%y1 = getWord(%loc1, 1);
%x2 = getWord(%loc2, 0);
%y2 = getWord(%loc2, 1);
%xd = %x2 - %x1;
%yd = %y2 - %y1;
return mSqrt((mPow(%xd,2)) + (mPow(%yd,2)));
}
function complexMouse()
{
$test = new fxStaticSprite2D() { sceneGraph = t2dSceneGraph; };
$test.setImageMap( tileMapImageMap );
$test.setSize( "5 5" );
$test.setPosition( "0 0" );
$test.isSelectable = true;
$test.objectName = "test box";
}now create a new .cs file (if you didn't in the last tutorial)... called "exec.cs"...
add this line to it
exec("./complexMouse.cs");now add this exec statement into your client.cs (right below the other exec statements)
exec("./exec.cs");scroll down a little and add the function call
initMouse(); complexMouse();
after
// ************************************************************************ // // Add your custom code here... // // ************************************************************************
ok now you should be cot up to speed... if you fire up T2D you should be able to click the box in the middle of the screen and move it, then click again and drop it...
ok as you notice in our code we added a lot of debug echo statements... now we will use them a bit more effectively... but first we need to create a new gui... fire up T2D and hit "F10"... you should see this
now click File -> New Gui...
in GUI Name: put DebugGui
change Class to GuiWindowCtrl
it should look like this
now click "Create"
now you should see something like this
click on "New Control" in the top left
then scroll down and go to "GuiPopUpMenuCtrl"
then click it... now move the new control and stretch it to about here
now click "New Control" scroll down to GuiScrollCtrl and click it and place it about here
and finally click "New Control" and scroll down to GuiMessageVectorCtrl and click it and place it about here
don't worry about being too precise, you can modify this later
now click File -> Save GUI... look up top where you see Directory: then probably "common"... click that and scroll down and select "T2D/client" (or if your working in a different directory choose that)
like this
click save
now hit the "~" tilde key to bring up the console... type in the command
quit();
hit enter and it should exit Torque 2D...
now go to your T2D/client folder and find your "DebugGui.gui"... open it with wordpad/notepad (or your script editor of choice)...
you should see this
//--- OBJECT WRITE BEGIN ---
new GuiWindowCtrl(DebugGui) {
profile = "GuiWindowProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 0";
extent = "640 480";
minExtent = "8 2";
visible = "1";
maxLength = "255";
resizeWidth = "1";
resizeHeight = "1";
canMove = "1";
canClose = "1";
canMinimize = "1";
canMaximize = "1";
minSize = "50 50";
new GuiPopUpMenuCtrl(DebugList) {
profile = "GuiPopUpMenuProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "5 24";
extent = "113 19";
minExtent = "8 2";
visible = "1";
maxLength = "255";
maxPopupHeight = "200";
};
new GuiScrollCtrl(DebugScroll) {
profile = "GuiScrollProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "5 45";
extent = "146 140";
minExtent = "8 2";
visible = "1";
willFirstRespond = "1";
hScrollBar = "alwaysOn";
vScrollBar = "alwaysOn";
constantThumbHeight = "0";
childMargin = "0 0";
};
new GuiMessageVectorCtrl(DebugVector) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "11 50";
extent = "122 118";
minExtent = "8 2";
visible = "1";
lineSpacing = "0";
lineContinuedIndex = "10";
matchColor = "0 0 255 255";
maxColorIndex = "9";
};
};
//--- OBJECT WRITE END ---lets name some of these controls so we can utilize them in script
change
new GuiPopUpMenuCtrl() {to
new GuiPopUpMenuCtrl(DebugList) {change
new GuiScrollCtrl() {to
new GuiScrollCtrl(DebugScroll) {and change
new GuiMessageVectorCtrl() {to
new GuiMessageVectorCtrl(DebugVector) {ok now since they have names we can reference them in script
now we need to restructure this a bit... we want the messageVectorCtrl to be a child of the scroll ctrl... so we delete the "};" thats right before
new GuiMessageVectorCtrl(DebugVector) {
and then add one right before
//--- OBJECT WRITE END ---
like this
new GuiScrollCtrl(DebugScroll) {
profile = "GuiScrollProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "5 45";
extent = "146 140";
minExtent = "8 2";
visible = "1";
willFirstRespond = "1";
hScrollBar = "alwaysOn";
vScrollBar = "alwaysOn";
constantThumbHeight = "0";
childMargin = "0 0";
new GuiMessageVectorCtrl(DebugVector) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "11 50";
extent = "122 118";
minExtent = "8 2";
visible = "1";
lineSpacing = "0";
lineContinuedIndex = "10";
matchColor = "0 0 255 255";
maxColorIndex = "9";
};
};
};In this gui we have two new gui types we haven't approached before... (unless you've done some tinkering on you r own)... the first is
guiPopUpMenuCtrl
and the second is
guiMessageVectorCtrl
ok... first the PopUpMenuCtrl is what it seems, a pop up menu... you know that save gui that poped up when we tried to save our .gui file... thats drop down we click on to change to "T2D/client" was this same gui type...
the next is guiMessageVectorCtrl... this is a message vector that we can add text lines to and clear out... if you've played Tribes / Tribes 2, the message HUD is made up of these. The nice thing is you can create a "MessageVector" then "attach" it to the "GuiMessageVectorCtrl"... but you can detach it and re-attach it to another one... it also works well for what we're doing
ok... so what do we do now ? well first lets make sure this gui execs... so go to your exec.cs... and add this line
exec("./DebugGui.gui");(this is much easier than having to continually go into the client.cs :)
ok, now that we did that (to ensure we won't forget later)... go back to your .gui file... add this function at the bottom of it
function DebugGui::onWake(%this)
{
new MessageVector(DebugText){};
DebugVector.attach(DebugText);
DebugList.add(None,0);
DebugList.add(callBacks,1);
DebugList.add(selection,2);
$debugCount = 2;
}ok, one nice thing about GUIs is they have this built in callback... "onWake()" so we can tell it what to run when it starts
notice we do "DebugGui::onWake(%this)"... this will pass itself into %this if we want to refer to it
the first line
new MessageVector(DebugText){};
create a new message vector (as I mentioned you can add and clear text from these then attach and detach them from the guiMessageVectorCtrl)... we name it "DebugText".
the next line we take the guiMessageVectorCtrl and .attach the DebugText message vector to it (as I mentioned)...
then we add a few entries into the DebugList
first we add None at 0...
then callBacks at 1
and selection at 2
we also specify a count of $debugCount = 2;
you might recognize "callBacks" and "selection"... if you look at your complexMouse.cs you will notice
$debugMsg::mouse::callBacks
and
$debugMsg::mouse::selection
as you can start to tell (probably) this gui will have some sort of effect on the debug messages...
lets test what we have... open your complexMouse.cs and find the "complexMouse" function and add
mainscreengui.add(debuggui);
to it, like this
function complexMouse()
{
$test = new fxStaticSprite2D() { sceneGraph = t2dSceneGraph; };
$test.setImageMap( tileMapImageMap );
$test.setSize( "5 5" );
$test.setPosition( "0 0" );
$test.isSelectable = true;
$test.objectName = "test box";
mainScreenGui.add(DebugGui);
}this will add our DebugGui to the mainScreenGui when we start up
save this .gui file and fire up T2D...
you should see something like this
now click the popUp like this
and you should be able to select the options we included, though presently it doesnt do anything...
ok now close T2D down (go to console and type "quit();")
and now add this function bellow the last one
function DebugList::onSelect(%this, %id)
{
debugText.clear();
for(%i=1;%i<=$debugCount;%i++)
eval("$debugMsg::mouse::" @ %this.getTextById(%i) @ " = false;");
eval("$debugMsg::mouse::" @ %this.getTextById(%id) @ " = true;");
}ok this function is attached to our popUp... DebugList... as you can assume this function is called when we select something out of the list, passing the id number... the 0,1, and 2 we specified
then we clear the vector
debugText.clear()
this is important so that every time we change our selection it clears out the old text
the next set of code (the for loop) might look a little confusing
for(%i=1;%i<=$debugCount;%i++)
eval("$debugMsg::mouse::" @ %this.getTextById(%id) @ " = true;");it starts at 1 and loops while less than or equal to $debugCount... which is 2
and the eval function just takes a string and executes it... in this case just setting a variable...
%this.getTextById() returns the text of the ListItem by the id... so if you put 1 in there it will return "callBacks"... 2 "selection" etc...
so basically this loop works like this
loop 1
$debugMsg::mouse::callBacks = false;
loop 2
$debugMsg::mouse::selection = false;
so basically this function so far clears the messageVector then sets our two debug variables to false... (basically reseting everything)...
the next set is this
eval("$debugMsg::mouse::" @ %this.getTextById(%id); @ " = true;");this will set whichever %id we have selected to true... so if we were to click on the "selected" text in the pop up it would do this
$debugMsg::mouse::selection = true;
which will enable the debug messages for that selection...
so basically we select a pop up, it resets them then sets the one we selected to display... nifty :)
ok save this off... now lets move back to the "complexMouse.cs"
ok, we need to create a helper fu nction, to do something with that message vector...add this to the end of the file
function registerDebug(%debug)
{
if(%debug !$= $lastDebug)
{
$lastDebug = %debug;
DebugText.pushBackLine(%debug,0);
}
}ok... this function we pass it something... it then compares it (string compare) and if its not equal to the last thing passed it will perform this
$lastDebug = %debug;
DebugText.pushBackLine(%debug,0);
which sets teh $lastDebug (to check for next time)
then
DebugText.pushBackLine(%debug,0);
this is how we add text to a messageVector... there are many commands... pushBackLine... pushFrontLine...clear... look in the source code for a whole list of them... it even has a special "dump()" function that saves off a file.
notice the (%debug,0);
the 0 is where you can put a special tag entry, using that you can do some special searches in the vector by tags, also its a way the game system did some pretty advanced text manipulation... for now we will just put 0 since it doesn't matter to us
ok... now this whole function will update the message vector, but we need to now change our "echo(" to "registerDebug("... a quick way is the
Edit -> Replace in wordpad... or wherever the replace tool is in your script editor
replace
echo(
with
registerDebug(
have it replace all ... now your comlexMouse.cs should look like this
function sceneWindow2D::onMouseMove( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Moving");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDragged( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Dragging");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDown( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Down");
//check to see if we have an object already selected, if so we don't want to do anything expect set it to false so it doesn't follow anymore
if(%this.objectSelected)
{
if($debugMsg::mouse::selection)
registerDebug("unselecting");
if($mouseObj::isObjMounted)
{
if(isObject($mouseObj::objMounted))
{
if($debugMsg::mouse::selection)
registerDebug("dismounting object");
$mouseObj::objMounted.dismount();
$mouseObj::isObjMounted = false;
}
}
%this.objectSelected = false;
} else
{
//lets get a list of all the objects at the clicked point in the t2dSceneGraph
%objList = t2dSceneGraph.pickPoint(%worldPos);
//lets get a count of how many objects in the list
%objCount = getWordCount(%objList);
//we will start looping through the list
for(%i=0;%i<%objCount;%i++)
{
//grabing the entry corresponding to the loop
%obj = getWord(%objList, %i);
//if we find an object in the list that "isSelectable = true"
if(%obj.isSelectable)
{
//we toggle a value so we know we found an object that "isSelectable"
%selected = true;
//we kick out of the loop
%i = %objCount;
}
}
//if we found an "isSelectable" object
if(%selected)
{
//we then store that object as the selectedObj
%this.selectedObj = %obj;
if($debugMsg::mouse::selection)
registerDebug("You have selected:" SPC %obj SPC "with the name:" SPC %obj.objectName);
%this.objectSelected = true;
if($debugMsg::mouse::selection)
registerDebug("echo attempting to mount:" SPC %obj SPC " to mouse obj:" SPC $mouseObj::object);
%obj.mount($mouseObj::object, $mouseObj::mount::offset, $mouseObj::mount::force, $mouseObj::mount::trackRotation);
$mouseObj::isObjMounted = true;
$mouseObj::objMounted = %obj;
}
}
}
function sceneWindow2D::onMouseUp( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Up");
}
function sceneWindow2D::onMouseEnter( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Entered... Knew it would come crawling back");
}
function sceneWindow2D::onMouseLeave( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Left... Go Get It!");
}
function initMouse()
{
$mouseObj::object = new fxSceneObject2D() { scenegraph = t2dSceneGraph; };
$mouseObj::object.setSize("1 1");
$mouseObj::object.setLayer(31);
$mouseObj::follow = true;
$mouseObj::speed::max = 250;
$mouseObj::speed::default = 250;
$mouseObj::mount::force = 0;
$mouseObj::mount::offset = "0 0";
$mouseObj::mount::trackRotation = true;
}
function fxSceneGraph2D::onUpdateScene(%this)
{
if(($mouseObj::follow) && (!$mouseObj::stopped))
mouseObjCheck();
}
function mouseObjCheck()
{
// Get the position of the Mouse itself
%x = getWord($mouseObj::pos, 0);
%y = getWord($mouseObj::pos, 1);
// Get the Position of the mounted scene object
%objPos = $mouseObj::object.getPosition();
%objX = getWord(%objPos, 0);
%objY = getWord(%objPos, 1);
// calculate the distance between the two (for speed calculations)
%dist = distBetween(%objPos, $mouseObj::pos);
// Set values for easy configuration
// set speed = distance * 20, that way it slows when approach - no bobbing around
%speed = %dist * 20;
// limit speed if we want to
if(%speed > $mouseObj::speed::max)
%speed = $mouseObj::speed::default;
%space = 0.25;
if((%objX > (%x - %space)) && (%objX < (%x + %space)) && (%objY > (%y - %space)) && (%objY < (%y + %space)))
{
if($debugMsg::mouse::object)
registerDebug("object at mouse position, halting");
$mouseObj::object.setLinearVelocityPolar(0,0);
$mouseObj::stopped = true;
} else
{
if($debugMsg::mouse::object)
registerDebug("object seeking mouse at " @ angleBetween(%objPos, $mouseObj::pos));
//set the polar velocity towards the mouse
$mouseObj::object.setLinearVelocityPolar(angleBetween(%objPos, $mouseObj::pos),%speed);
}
}
function angleBetween(%playerPos, %mousePos)
{
// Seperate Mouse Position
%mxpos = getWord(%mousePos,0);
%mypos = getWord(%mousePos,1);
// Seperate Player Position
%px = getWord(%playerPos,0);
%py = getWord(%playerPos,1);
// Calculate Angle from player to mouse (convert to degrees).
%angle = mRadToDeg( mAtan( %mxpos-%px, %py-%mypos ) );
return %angle;
}
function distBetween(%loc1, %loc2)
{
%x1 = getWord(%loc1, 0);
%y1 = getWord(%loc1, 1);
%x2 = getWord(%loc2, 0);
%y2 = getWord(%loc2, 1);
%xd = %x2 - %x1;
%yd = %y2 - %y1;
return mSqrt((mPow(%xd,2)) + (mPow(%yd,2)));
}
function complexMouse()
{
$test = new fxStaticSprite2D() { sceneGraph = t2dSceneGraph; };
$test.setImageMap( tileMapImageMap );
$test.setSize( "5 5" );
$test.setPosition( "0 0" );
$test.isSelectable = true;
$test.objectName = "test box";
mainScreenGui.add(DebugGui);
}
function registerDebug(%debug)
{
if(%debug !$= $lastDebug)
{
$lastDebug = %debug;
DebugText.pushBackLine(%debug,0);
}
}before we test this we need to change our gui a bit, right now it fill up the whole screen, we can't really test the debugs for the demo if we can't see the demo lol...
find
new GuiWindowCtrl(DebugGui) {
profile = "GuiWindowProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 0";
extent = "640 480";change that to
new GuiWindowCtrl(DebugGui) {
profile = "GuiWindowProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "400 0";
extent = "150 200";this should position our window a lot better
ok, lets test this... save the .cs and .gui file and fire up T2D
you should see this
select the drop down and select "callBacks"
move your mouse arround (click and move the box some too) you should see the text update like this
now try changing your selection to "selection" (no pun intended lol)... this should clear the messageVector and display something like this... (be sure to click and drag the box some too)
now try changing it to none and move around
and there we go, we have a little debug gui...
if yours doesnt work compare it to this
here is the DebugGui.gui file
//--- OBJECT WRITE BEGIN ---
new GuiWindowCtrl(DebugGui) {
profile = "GuiWindowProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "400 0";
extent = "150 200";
minExtent = "8 2";
visible = "1";
maxLength = "255";
resizeWidth = "1";
resizeHeight = "1";
canMove = "1";
canClose = "1";
canMinimize = "1";
canMaximize = "1";
minSize = "50 50";
text = " Debug GUI";
new GuiPopUpMenuCtrl(DebugList) {
profile = "GuiPopUpMenuProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "5 24";
extent = "113 19";
minExtent = "8 2";
visible = "1";
maxLength = "255";
maxPopupHeight = "200";
};
new GuiScrollCtrl(DebugScroll) {
profile = "GuiScrollProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "5 45";
extent = "146 140";
minExtent = "8 2";
visible = "1";
willFirstRespond = "1";
hScrollBar = "alwaysOn";
vScrollBar = "alwaysOn";
constantThumbHeight = "0";
childMargin = "0 0";
new GuiMessageVectorCtrl(DebugVector) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "11 50";
extent = "122 118";
minExtent = "8 2";
visible = "1";
lineSpacing = "0";
lineContinuedIndex = "10";
matchColor = "0 0 255 255";
maxColorIndex = "9";
};
};
};
//--- OBJECT WRITE END ---
function DebugGui::onWake(%this)
{
%c = new MessageVector(DebugText){};
DebugVector.attach(DebugText);
DebugList.add(None,0);
DebugList.add(callBacks,1);
DebugList.add(selection,2);
$debugCount = 2;
}
function DebugList::onSelect(%this, %id)
{
debugText.clear();
for(%i=1;%i<=$debugCount;%i++)
eval("$debugMsg::mouse::" @ %this.getTextById(%i) @ " = false;");
eval("$debugMsg::mouse::" @ %this.getTextById(%id) @ " = true;");
}here is the
comlexMouse.cs
function sceneWindow2D::onMouseMove( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Moving");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDragged( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Dragging");
//store the mouse position
$mouseObj::pos = %worldPos;
//reset stopped to false so it checks
$mouseObj::stopped = false;
}
function sceneWindow2D::onMouseDown( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Down");
//check to see if we have an object already selected, if so we don't want to do anything expect set it to false so it doesn't follow anymore
if(%this.objectSelected)
{
if($debugMsg::mouse::selection)
registerDebug("unselecting");
if($mouseObj::isObjMounted)
{
if(isObject($mouseObj::objMounted))
{
if($debugMsg::mouse::selection)
registerDebug("dismounting object");
$mouseObj::objMounted.dismount();
$mouseObj::isObjMounted = false;
}
}
%this.objectSelected = false;
} else
{
//lets get a list of all the objects at the clicked point in the t2dSceneGraph
%objList = t2dSceneGraph.pickPoint(%worldPos);
//lets get a count of how many objects in the list
%objCount = getWordCount(%objList);
//we will start looping through the list
for(%i=0;%i<%objCount;%i++)
{
//grabing the entry corresponding to the loop
%obj = getWord(%objList, %i);
//if we find an object in the list that "isSelectable = true"
if(%obj.isSelectable)
{
//we toggle a value so we know we found an object that "isSelectable"
%selected = true;
//we kick out of the loop
%i = %objCount;
}
}
//if we found an "isSelectable" object
if(%selected)
{
//we then store that object as the selectedObj
%this.selectedObj = %obj;
if($debugMsg::mouse::selection)
registerDebug("You have selected:" SPC %obj SPC "with the name:" SPC %obj.objectName);
%this.objectSelected = true;
if($debugMsg::mouse::selection)
registerDebug("echo attempting to mount:" SPC %obj SPC " to mouse obj:" SPC $mouseObj::object);
%obj.mount($mouseObj::object, $mouseObj::mount::offset, $mouseObj::mount::force, $mouseObj::mount::trackRotation);
$mouseObj::isObjMounted = true;
$mouseObj::objMounted = %obj;
}
}
}
function sceneWindow2D::onMouseUp( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Up");
}
function sceneWindow2D::onMouseEnter( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Entered... Knew it would come crawling back");
}
function sceneWindow2D::onMouseLeave( %this, %mod, %worldPos, %mouseClicks )
{
if($debugMsg::mouse::callBacks)
registerDebug("Mouse Left... Go Get It!");
}
function initMouse()
{
$mouseObj::object = new fxSceneObject2D() { scenegraph = t2dSceneGraph; };
$mouseObj::object.setSize("1 1");
$mouseObj::object.setLayer(31);
$mouseObj::follow = true;
$mouseObj::speed::max = 250;
$mouseObj::speed::default = 250;
$mouseObj::mount::force = 0;
$mouseObj::mount::offset = "0 0";
$mouseObj::mount::trackRotation = true;
}
function fxSceneGraph2D::onUpdateScene(%this)
{
if(($mouseObj::follow) && (!$mouseObj::stopped))
mouseObjCheck();
}
function mouseObjCheck()
{
// Get the position of the Mouse itself
%x = getWord($mouseObj::pos, 0);
%y = getWord($mouseObj::pos, 1);
// Get the Position of the mounted scene object
%objPos = $mouseObj::object.getPosition();
%objX = getWord(%objPos, 0);
%objY = getWord(%objPos, 1);
// calculate the distance between the two (for speed calculations)
%dist = distBetween(%objPos, $mouseObj::pos);
// Set values for easy configuration
// set speed = distance * 20, that way it slows when approach - no bobbing around
%speed = %dist * 20;
// limit speed if we want to
if(%speed > $mouseObj::speed::max)
%speed = $mouseObj::speed::default;
%space = 0.25;
if((%objX > (%x - %space)) && (%objX < (%x + %space)) && (%objY > (%y - %space)) && (%objY < (%y + %space)))
{
if($debugMsg::mouse::object)
registerDebug("object at mouse position, halting");
$mouseObj::object.setLinearVelocityPolar(0,0);
$mouseObj::stopped = true;
} else
{
if($debugMsg::mouse::object)
registerDebug("object seeking mouse at " @ angleBetween(%objPos, $mouseObj::pos));
//set the polar velocity towards the mouse
$mouseObj::object.setLinearVelocityPolar(angleBetween(%objPos, $mouseObj::pos),%speed);
}
}
function angleBetween(%playerPos, %mousePos)
{
// Seperate Mouse Position
%mxpos = getWord(%mousePos,0);
%mypos = getWord(%mousePos,1);
// Seperate Player Position
%px = getWord(%playerPos,0);
%py = getWord(%playerPos,1);
// Calculate Angle from player to mouse (convert to degrees).
%angle = mRadToDeg( mAtan( %mxpos-%px, %py-%mypos ) );
return %angle;
}
function distBetween(%loc1, %loc2)
{
%x1 = getWord(%loc1, 0);
%y1 = getWord(%loc1, 1);
%x2 = getWord(%loc2, 0);
%y2 = getWord(%loc2, 1);
%xd = %x2 - %x1;
%yd = %y2 - %y1;
return mSqrt((mPow(%xd,2)) + (mPow(%yd,2)));
}
function complexMouse()
{
$test = new fxStaticSprite2D() { sceneGraph = t2dSceneGraph; };
$test.setImageMap( tileMapImageMap );
$test.setSize( "5 5" );
$test.setPosition( "0 0" );
$test.isSelectable = true;
$test.objectName = "test box";
mainScreenGui.add(DebugGui);
}
function registerDebug(%debug)
{
if(%debug !$= $lastDebug)
{
$lastDebug = %debug;
DebugText.pushBackLine(%debug,0);
}
}now you can see how powerful formating all of your debug statements like this is... later you can then create a full status box of all your different properties... this is great for debuging... especially since right now with "selection" you can find out what you select... and no echo statements and no switching to the console ;)... also the box can be moved and minimized.
well the only other thing I could say to add is add a
text = " Debug GUI";
to
new GuiWindowCtrl(DebugGui) {
like this
new GuiWindowCtrl(DebugGui) {
profile = "GuiWindowProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "400 0";
extent = "150 200";
minExtent = "8 2";
visible = "1";
maxLength = "255";
resizeWidth = "1";
resizeHeight = "1";
canMove = "1";
canClose = "1";
canMinimize = "1";
canMaximize = "1";
minSize = "50 50";
text = " Debug GUI";that way when you fire it up you can tell what the box is for like this
Well this is the final part of that tutorial... I felt I should include a way to keep some good debug information, especially object selection, considering I've used this numerous times while testing things, being able to move them real time etc...
hope you enjoyed them
- Matthew "King BoB" Langley
About the author
Was a GG Associate and then joined GG in 2005. Lead tool dev for T2D and T3D. In 2011 joined mobile company ngmoco/DeNA and spent about 4 years working game and server tech. 2014 joined startup Merigo Games developing server technology.
#3
A couple of things:
The screenshot showing the 'callback' debug messages looks to be the same as the one for 'selection' ?
Also, when using the GUI editor, when you've created a scroll control, if you right click in it, it will get a green/yellow border and then any new controls will be children of it. This avoids the edit to the code for the GuiMessageVectorCtrl. This also seems to work for most other controls.
Note for Mac users: It seems to require a two button mouse for this. The Gui editor doesn't recognise the ctrl-click as an alternative. :-(
Bri
04/21/2005 (5:39 am)
Another great tutorial! I read it for examples of using the GUI stuff, but the debug GUI has inspired me to roll my own version. I'm still finding my feet with TorqueScript and T2D and it's taken a few days,but definitely getting there and havin' fun :-)A couple of things:
The screenshot showing the 'callback' debug messages looks to be the same as the one for 'selection' ?
Also, when using the GUI editor, when you've created a scroll control, if you right click in it, it will get a green/yellow border and then any new controls will be children of it. This avoids the edit to the code for the GuiMessageVectorCtrl. This also seems to work for most other controls.
Note for Mac users: It seems to require a two button mouse for this. The Gui editor doesn't recognise the ctrl-click as an alternative. :-(
Bri
#4
Your right about the screenshot... rofl... I saved over the old one =/ lol not bad considering its the first time I've done that in all the tutorials (I go through them rather quickly) though I have forgotten to crop the images before (so you can see all the windows I have open at once some times lol)
Thank you for that last bit, it seemed to ring a bell, but for a long time I didn't use the GUI editor and then hopped back on, learned a lot about it through the source code (a lot of good comments there on the different controls), thanks though, I had completely forgotten about that
04/21/2005 (7:32 pm)
Very cool, glad you liked it, looking forward to seeing what you develop :) Was just a little idea that spurred as I added all the echo statements, figured I could at least make a simple little gui to see it better... for my teams project I want to have a full tree control and maybe even some custom Gui controlsYour right about the screenshot... rofl... I saved over the old one =/ lol not bad considering its the first time I've done that in all the tutorials (I go through them rather quickly) though I have forgotten to crop the images before (so you can see all the windows I have open at once some times lol)
Thank you for that last bit, it seemed to ring a bell, but for a long time I didn't use the GUI editor and then hopped back on, learned a lot about it through the source code (a lot of good comments there on the different controls), thanks though, I had completely forgotten about that
#5
09/09/2005 (9:27 am)
You can now get this tutorial along with 9 others in a T2D "Tutorial Pack"... in this pack each tutorial is an external html file so you can use them offline :) 
Torque 3D Owner Matthew Langley
Torque