GuiStatusCtrl - *Updated* Display Field Name, Values, Status Bar for any field or method on any named object. TGEA and (new! TGE 1.52)
by Jaimi McEntire · 02/04/2009 (2:15 pm) · 44 comments
GuiStatusCtrl
Displays Field Name and/or value and/or bar graph for any field or method of any named object, using TorqueML for customization.The GuiStatusCtrl is a control that will monitor a field or method on any named object. This makes it easy to make status screens, etc. Also included is a GuiStatusController - a container that controls GuiStatusCtrls (more later on why this is useful).
The control can display the field name, value and the percentage of value as a progress bar. The field name and value can use TorqueML to customize the font, size, shadows, alignment, etc.
To use the GuiStatusCtrl, add the following files to your TGEA 1.7+ project, and recompile:
For TGEA 1.7+
Download Source Files for TGEA 1.7+
for TGE 1.5.2
Download Source Files for TGE 1.5.2
The GuiStatusCtrl has the following fields:
ObjectName: This is the name of the object that you want to monitor FieldName: This is the field that you want to monitor. New: Can also be a method on the class MaxFieldName: If displaying a status bar, this is the field (or method) that holds the maximum value IgnoreController: If set, this control will be ignored by any GuiStatusController objects FieldNameMLFormat: The TorqueML that is used to display the Field's Name FieldValueMLFormat: The TorqueML that is used to display the Field's Value DisplayFieldName: If true, then the field name is displayed to the left DisplayFieldValue: If true, then the field value is displayed. DisplayBar: If true, then a bar is displayed. The size is proportional to field/maxfield BarColor: The color of the status bar. Label: New: An alternate label to use instead of the FieldName.
The GuiStatusController is a container that is used to control any child GuiStatusCtrl objects. Lets say you have 25 GuiStatusCtrl controls all pointing to "PlayerBob", and you want them to show "PlayerJane" instead. Instead of manually coding the change to all 25 child controls, you instead just set the GuiStatusController ObjectName field, and it will update the child controls for you.
The GuiStatusController has all the fields that a GuiContainer has, with the addition of:
ObjectName: The name of the object to monitor.
If you do not wish for a child control to be changed by the controller, then set the "IgnoreController" field on the child.
Example: Lets create three named objects for our fictional RPG "Supergalactic Megawars" - put this in a test.cs file, and then execute it:
new SimObject("MainPlayer");
new SimObject("PartyPlayer");
new SimObject("GameData");
GameData.GameName = "Supergalactic Megawars";
GameData.LevelName = "Orion Quadrant";
MainPlayer.PlayerName = "Big Bob";
MainPlayer.Strength = 18;
MainPlayer.Vitality = 20;
MainPlayer.Intellect = 30;
MainPlayer.Health = 50;
MainPlayer.MaxHealth = 65;
PartyPlayer.PlayerName = "Sue (female)"; // differentiate from any boys named Sue
PartyPlayer.Strength = 22;
PartyPlayer.Vitality = 18;
PartyPlayer.Intellect = 24;
PartyPlayer.Health = 20;
PartyPlayer.MaxHealth = 65;Now, create a new gui, and put a GuiStatusController on it. Size it to hold 8 GuiStatusCtrl objects, and create and place the status controls in the controller.
Set the ObjectName on the top 2 to "GameData", and the field on the first one to "GameName" and the field on the second one to "LevelName". You should see the status control display the field names and values by default. Set "IgnoreController" to true for both controls. (you can also set the ML properties to apply formatting to the field name and value).
For the remainders, set the ObjectName to "MainPlayer", and the fieldnames to "PlayerName","Strength", "Vitality", "intellect", and "Health". On the Health Control, set "DisplayBar" to true, and set the MaxFieldName to "MaxHealth". You should now see all of the values displayed, and a proportional bar for health. (You can disable the field name and value on health if you don't want them printed).
To see how the controller works, set the Controller.ObjectName parameter to "PartyPlayer". now you are viewing her stats instead.
What's New
You can now use methods as well as field names. For example, to display "Health" on a player, you can add the following method to the Player.cs:
function Player::GetHealth(%this)
{
return %this.dataBlock.MaxDamage - (%this.dataBlock.MaxDamage * %this.getDamagePercent());
}
function Player::GetMaxHealth(%this)
{
return %this.dataBlock.MaxDamage;
}Now, instead of Field Names, use "GetHealth" for the Value and "GetMaxHealth" for the Max Value. Use the new "Label field" to override the display for the field name. (note: your Target object needs to be a "Player" for this to work. Or actually, any ShapeBase descended object)
Update
Here's a slightly more complicated version of the GetHealth function above, that shows how you can manipulate the control as part of the status function - we update the color and label that display based on how hurt the player is:
function Player::GetHealth(%this)
{
%perc = %this.getDamagePercent();
if (%perc < 0.25)
{
%newlabel = "Invincible";
%BarColor = "128 0 0 192";
}
else if (%perc < 0.50)
{
%newlabel = "But a scratch";
%BarColor = "160 0 0 192";
}
else if (%perc < 0.75)
{
%newlabel = "Just a flesh wound";
%BarColor = "192 0 0 192";
}
else
{
// Careful, he'll bite your legs off.
%newlabel = "Calling it a draw";
%BarColor = "255 0 0 192";
}
MyHealthStatus.Label = %newlabel;
MyHealthStatus.BarColor = %BarColor;
return mFloor(0.99 + (%this.dataBlock.MaxDamage - (%this.dataBlock.MaxDamage * %this.getDamagePercent())));
}Sample Pic:

#2
02/04/2009 (3:01 pm)
This is great and I have an immediate need/use for this type of control. thanks a bunch.
#3
If really -- this is a perfect example of how to use "the power of torque"!
Great use of Torque's build-in functionality, clear code and smart implementation.
Voting this to be included in upcoming Torque 3D! ;)
Thanks Jaimi, really useful!
02/04/2009 (3:02 pm)
"this blows"! :)If really -- this is a perfect example of how to use "the power of torque"!
Great use of Torque's build-in functionality, clear code and smart implementation.
Voting this to be included in upcoming Torque 3D! ;)
Thanks Jaimi, really useful!
#4
02/04/2009 (4:24 pm)
Awesome! This will be very helpful to me. Question: Will this work with AFX for TGEA?
#5
@Michael, Bank: Thanks for posting! I hope this helps out. It made it a breeze to make all my status screens!
02/04/2009 (4:33 pm)
@Zuero - Yes, it sure will!@Michael, Bank: Thanks for posting! I hope this helps out. It made it a breeze to make all my status screens!
#6
This is a nice one Jaimi, thanks, may be the best GUI control ever.
02/04/2009 (4:55 pm)
This blows!! Blows other controls away. This is a nice one Jaimi, thanks, may be the best GUI control ever.
#7
02/05/2009 (1:19 am)
Brilliant! This will be my favorite control for sure! Jaimi, these changes to the GUI are very useful! Thank you for them.
#8
02/05/2009 (5:06 am)
Looks very nice! Thanks for publishing all these resources!
#9
Also... any idea about portability to TGE? I might have a look at it and try to get it into 1.5.2.
02/05/2009 (7:51 am)
Nice idea! Does this onnly work for script-side SimObject parameters? Could I use it on, for example, a Player's health and energy levels? (Yes, I know we already have health and energy GUIs - just an example.)Also... any idea about portability to TGE? I might have a look at it and try to get it into 1.5.2.
#10
Unfortunately, there isn't a health field - this is calculated from a field named "MaxDamage" (on the shapebase) and an internal variable named "mDamage" that is not exposed as a field.
Note: it would be easy to expose mDamage to script, just go into ShapeBase, and in InitPersistFields, add the field:
void ShapeBase::initPersistFields()
{
Parent::initPersistFields();
addField("Damage", TypeF32, Offset(mDamage, ShapeBase)); // add this line
}
If you don't already have an initPersistFields, then you'll need to add the whole function, and the declaration in the class itself. You can do the same to mEnergy to expose it as well.
02/05/2009 (9:12 am)
@Daniel - this will work on any field that is exposed to script, whether it is dynamic or not. Unfortunately, there isn't a health field - this is calculated from a field named "MaxDamage" (on the shapebase) and an internal variable named "mDamage" that is not exposed as a field.
Note: it would be easy to expose mDamage to script, just go into ShapeBase, and in InitPersistFields, add the field:
void ShapeBase::initPersistFields()
{
Parent::initPersistFields();
addField("Damage", TypeF32, Offset(mDamage, ShapeBase)); // add this line
}
If you don't already have an initPersistFields, then you'll need to add the whole function, and the declaration in the class itself. You can do the same to mEnergy to expose it as well.
#11
02/05/2009 (9:15 am)
Hmm. Now that I think about it, I think I can make it where it executes a script to get a value to display - that would give us the ability to get to things like the MaxDamage and Damage without having to change any base classes. Is anyone interested in that?
#12
I've updated the control so it can use Method names as well as field names. Now you can display the health (see the example above).
It should be mostly portable to TGE 1.5.2, however there will be some work. (it uses some GFX calls to draw the borders and bars).
02/05/2009 (12:16 pm)
@Daniel - I've updated the control so it can use Method names as well as field names. Now you can display the health (see the example above).
It should be mostly portable to TGE 1.5.2, however there will be some work. (it uses some GFX calls to draw the borders and bars).
#13
02/06/2009 (12:12 pm)
Wow, seems like my questions have been answered. Thanks! When I get around to implementing this, I'll have to check how existing GUI controls render to replace the GFX control. This looks lovely - thanks again for the brilliant resource!
#14
02/06/2009 (2:13 pm)
For a little performance boost, you can insert this at the top of GuiStatusCtrl::onStaticModified. This will allow it to bypass reflowing the ML when your setting the label, and it hasn't actually changed.if(!dStricmp(slotName, "label"))
{
// Don't rebuild if the label hasn't actually
// changed
if (!dStricmp(newValue,mLabel))
return;
}
#15
02/06/2009 (6:39 pm)
@Daniel - I went ahead and did the conversion to 1.5.2. You can get it in the main resource above.
#16
02/06/2009 (11:19 pm)
Jaimi, you're making the rest of us look slow! I just came back and noticed the changes -- awesome is the word for this resource!
#17
02/07/2009 (6:18 am)
Heh, you're right there, Michael! Thanks, Jaimi, for the awesome response.
#18
Compiled fine after a drag and drop.
A must for anybody making an RPG.
5 stars dude.
Ari
02/07/2009 (6:35 pm)
Wrenched into TGEA 1.8.Compiled fine after a drag and drop.
A must for anybody making an RPG.
5 stars dude.
Ari
#19
VERY nice stuff, works like a charm, thanks again!
Ari
02/09/2009 (12:34 pm)
I've been sending Control Objects to this GUI with ghostID resolving almost exactly like AFX sends the spellbook.VERY nice stuff, works like a charm, thanks again!
Ari
#20
<var:$Player.Name>
<method:$Player.GetStatus();>
Note that the GuiStatusCtrl is a descendent of GuiMLTextCtrl, so you will actually get the new functionality in the status control also...
02/09/2009 (1:22 pm)
@Everybody - Thanks for the encouragement! My next resource is also aimed at RPG's (though of course it can be used for anything) and is going up soon. It's a GuiMLTextCtrl that can do that can resolve variables/methods at runtime:<var:$Player.Name>
<method:$Player.GetStatus();>
Note that the GuiStatusCtrl is a descendent of GuiMLTextCtrl, so you will actually get the new functionality in the status control also...

Associate Jaimi McEntire
King of Flapjacks
PS - This is one of my favorite controls. Please post any questions, changes, additions, or just plain comments (even: "this blows", if you think that)