Torque3D
  • General
    • Welcome!
    • Features
    • Release Notes
      • Version 4.0.3
      • Version 4.0.2
      • Version 4.0.1
      • Version 4.0
      • Version 3.10.1
      • Version 3.10
      • Version 3.9
      • Version 3.8
      • Version 3.7
      • Version 3.6.2
      • Version 3.6.1
      • Version 3.6
  • Getting Started
    • Introduction
      • What's the Torque3D Engine?
    • Getting Familiar
      • Getting a Copy
        • Torque Project Manager
        • Downloading it Yourself
      • Getting Ready for Launch
        • Running Pre-Built Binaries
        • Building the Engine Yourself
      • Launching the Game
        • Opening the Example Level
        • Launching the Editors
      • Your First Game
        • Introduction To The Engine
        • The Module System
        • Creating an empty gamemode
        • Adding a Player
        • Adding a Coin
        • Adding a win-condition
        • Custom coin asset
        • Counting coins
        • Adding some effects
        • Supporting multiplayer
        • Adding a Scoreboard GUI
        • Keeping the scoreboard up-to-date
      • Deep Dive: BaseGame Directory Structure
    • Best Practices
    • Porting a Legacy Project
  • For Artists
    • Assets
      • What are Assets?
      • How to Create a New Asset
      • Working With Assets
      • Deep Dive: Creating a New Asset Type
    • Art
      • File Formats
      • 3D Art
        • Shape Specifications
        • Coordinates System
        • Mounting Shapes
        • Animation
        • Player Setup
        • Blender -> Torque3D Pipeline
      • 2D Art
        • Working with Adobe Substance
    • Animation
    • GUI
      • Loading and Initializing a GUI
      • Expanding a GUI via Script
      • How to Network GUIs
    • Materials
      • Material Mapping
      • Material Animation
    • Terrain
    • Shaders
    • Lighting
    • Audio
  • For Designers
    • Base Classes
      • SimObject
      • SimGroup
      • SceneObject
      • Scene
      • Datablocks
    • Game Classes
      • Creating an Object
      • Destroying an Object
      • Gameplay Scripting
        • Spawning an Object from Gameplay Code
    • Modules
      • What are Modules?
      • How to Create a New Module?
      • Making a Module do Things
      • Installing Existing Modules
        • Where to Get More Modules
    • Scenes and Levels
      • How to Create a New Level
      • How to Load a Level
        • Deep Dive: Level Loading Scripts
      • How to Edit Levels
        • Opening a Level in the Editor
        • Spawning Objects from the Asset Browser
        • Working with Scenes
        • Using SimGroups
        • Changing a Level's PostEffects
        • Deep Dive: LevelAsset Companion Files
    • Game Modes
      • Creating a New GameMode
      • Making a Level Use Your GameMode
      • Adding Gameplay Code to Your GameMode
    • AI
      • Navmesh
      • Objects
      • Scripting
    • Inputs
      • Inputs and Keybinds
        • ActionMap
        • Bind Functions
        • ActionMap Stack
    • Localization
    • Editors
      • Changing Editor Settings
      • World Editor
        • Scene Editor
        • ConvexShape Editor
        • Terrain Editor
        • Terrain Painter
        • Material Editor
        • Spline-Based Tools
          • Mesh Road Editor
          • River Editor
          • Decal Road Editor
        • Datablock Editor
        • Particle Editor
        • Decal Editor
        • Forest Editor
        • Navmesh Editor
        • Deep Dive: Creating Your Own Editor
        • Shape Editor
      • GUI Editor
        • Interface Details
  • For Programmers
    • Compiling the Engine
      • Setup Development Environment
        • SDK and Library Installation
        • Git
        • Cmake
        • Creating a Fork on Github
      • Create a Project
        • Creating a Project With CMake
        • Creating a Project With the Project Manager
      • Compiling
        • Compiling in Windows
        • Compiling in Linux
        • Compiling in MacOS
      • Building the Project Manager
    • Introduction
    • Code Style Guidelines
    • Expanding the Engine
      • Creating a New Object Class
      • Exposing Object Classes to Script
        • addProtectedField
      • Adding a New Library to the Engine
    • Major Components of the Engine
      • Core
        • Console
        • Platform
      • Audio
        • SFX
      • Rendering
        • GFX
        • Render Bins
      • Physics
        • Stock T3D Physics
        • Physics Wrapper
          • PhysX
          • Bullet
        • Classes
    • Rendering
    • Math
    • Networking
      • Client and Server Commands
    • Physics
    • Collision
    • Scripting
      • TorqueScript
        • What is TorqueScript?
        • Basic Syntax
        • Variables
        • Types
        • Operators
        • Control Structures
        • Functions
        • Objects
        • Module Interop
          • QueueExec
          • RegisterDatablock
          • CallOnModules
          • ModuleExec
        • API Reference
      • Other Languages
        • C-Interface
    • File Inputs/Outputs(I/O)
    • API Reference
Powered by GitBook
On this page
  • Objects and child objects
  • The Scoreboard GUI
  • A centered container
  • Headers for the scores
  • The scrollbars
  • The final structure
  • Styling the GUI
  • Showing the scoreboard
  • Adding an ActionMap
Edit on GitHub
Export as PDF
  1. Getting Started
  2. Getting Familiar
  3. Your First Game

Adding a Scoreboard GUI

Objects and child objects

When creating objects we are able to define an initialiser. This initialiser has an interesting feature. If you were to create an object like a SimGroup, which contains more objects you could do this:

%obj = new SimGroup(){};
%obj.addObject(new SimObject(){});
%obj.addObject(new SimObject(){});
//etc..

But the constructor allows us to instantiate the child objects inside the constructor:

%obj = new SimGroup(theGroup){
   new SimObject(){};
   new SimObject(){};
};

We often utilize this feature when writing new .gui files:

%guiContent = new GuiControl(ScoreBoardGui){
   new GuiBitmapBorderControl(){
      new GuiBitmapControl(){
      };
   };
};

This code will create a new control with a bitmap border inside, and a bitmap inside the border.

The Scoreboard GUI

I prefer writing GUIs in script because the editor feels a bit clumsy to me. Let's start by creating the baseline GUI file in data/CoinCollection/client/gui/scoreBoard.gui:

new GuiControl(ScoreBoardGUI) {
    position = "0 0";
    extent = "1024 768";
    profile = "GuiModelessDialogProfile";
    tooltipProfile = "GuiToolTipProfile";
    isContainer = "1";
    canSaveDynamicFields = "1";
    enabled = "1";
    noCursor = "1";
};

This is a simple control that basically fills the whole screen (starts at top left corner, scales down to the top right corner and it is anchored to the right and bottom sides).

Now we'll add the content inside of it piece by piece.

A centered container

Now we will need to center the content inside the ScoreBoardGUI so it is centered on the screen. Add this to the GuiControl ScoreBoardGUI, (Remember how we did it? Read “Objects and childobjects again.").

new GuiPanel() {
    docking = "None";
    position = "370 271";
    extent = "283 226";
    horizSizing = "center";
    vertSizing = "height";
    profile = "ScoreBoardProfile";
    tooltipProfile = "GuiToolTipProfile";
};

This creates a new panel in the center of the screen. Extent means the size of the panel. This panel is 283px wide and 226px tall.

We make sure it is centered by letting position be (screenwidth/2)-(extent/2). In this case it is (1024/2)-(283/2), (Likewise for height).

We set vertSizing to height, which means that it will follow the height of the screen and thus scale vertically.

We set horizSizing to center, so that it wont scale horizontally. This is because a horizontal scaling would corrupt the design of the scoreboard.

Headers for the scores

We will be using a GuiTextListCtrl to list the players. We can consider it like a table. Since every new Text in the list is a row, and we can specify columns by tabs.

Therefore we need some headers for the values “Coins, Kills, Deaths” (yes we will add in some ‘kill each other’ feature in a later tutorial).

So put this inside the GuiPanel you just created:

new GuiTextCtrl() {
    text = "Coins";
    maxLength = "255";
    position = "104 2";
    extent = "33 18";
    profile = "ScoreBoardTextBoldProfile";
    tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl() {
    text = "Kills";
    maxLength = "255";
    position = "158 2";
    extent = "30 18";
    profile = "ScoreBoardTextBoldProfile";
    tooltipProfile = "GuiToolTipProfile";
};
new GuiTextCtrl() {
    text = "Deaths";
    maxLength = "255";
    position = "206 2";
    extent = "37 18";
    profile = "ScoreBoardTextBoldProfile";
    tooltipProfile = "GuiToolTipProfile";
};

As you can see the position value is not very high on these elements, that’s because their parent is the GuiPanel so their position is relative to the panel!

The scrollbars

If alot of players is joining, we will need some scrollbars. For this we need a GuiScrollCtrl placed inside of the GuiPanel.

new GuiScrollCtrl() {
    willFirstRespond = "1";
    hScrollBar = "alwaysOff";
    vScrollBar = "dynamic";
    lockHorizScroll = "1";
    lockVertScroll = "0";
    constantThumbHeight = "0";
    childMargin = "0 0";
    mouseWheelScrollSpeed = "-1";
    position = "0 24";
    extent = "228 202";
    horizSizing = "width";
    vertSizing = "height";
    profile = "ScoreBoardScrollProfile";
    tooltipProfile = "GuiToolTipProfile";
    isContainer = "1";
};

As you might be able to see, we don’t want a horizontal scrollbar so it is always off (hScrollBar = "alwaysOff") and the vertical scrollbar only shows if it is necessary (vScrollBar = "dynamic") beside from that, all these settings should be fairly straight forward.

Now last but not least we need the aforementioned GuiTextListCtrl placed inside the GuiScrollCtrl:

new GuiTextListCtrl(ScoreBoardGUIList) {
    columns = "0 98 153 200";
    fitParentWidth = "1";
    clipColumnText = "0";
    position = "0 0";
    extent = "228 8";
    horizSizing = "width";
    vertSizing = "height";
    profile = "ScoreBoardTextNormalProfile";
    tooltipProfile = "GuiToolTipProfile";
    isContainer = "1";
};

The important things to note here is the columns attribute, the fitParentWidth attribute and the clipColumnText attribute.

  • columns specifies where the columns will be (on the x-axis relative to the GuiTextListCtrl). As you might have noticed this matches the positions of the GuiText controls!

  • fitParentWidth this makes the TextListCtrl fill the scroll horizontally.

  • clipColumnText this makes sure that the columns don’t break or overwrite each other. If the string in this column is longer than the column it will be cut out.

The final structure

When you are done your structure for the GUI should look something like this:

  • GuiControl “ScoreboardGUI”

    • GuiPanel

      • GuiTextCtrl “Coins”

      • GuiTextCtrl “Kills”

      • GuiTextCtrl “Deaths”

      • GuiScrollCtrl

        • GuiTextListCtrl “ScoreBoardGUIList”

Styling the GUI

Here is one thing that you may have noticed and that I haven’t explained!

The profiles! The profile is to GUI objects what CSS is to HTML. They define the style of the GUI’s

I wont spend a lot of time with the profiles even tho they are quite important. Therefore we will use alot of the stock profiles and only create a single custom one.

In data/CoinCollection/client/gui/customProfiles.cs add the following snippet:

singleton GuiControlProfile(ScoreBoardProfile : GuiDefaultProfile) {
    opaque = "1";
    fillColor = "0 0 0 200";
    fillColorHL = "0 0 0 200";
    borderColor = "0 0 0 255";
    borderThickness = "5";
    border = "1";
};

singleton GuiControlProfile(ScoreBoardTextBoldProfile : GuiDefaultProfile) {
    fontType = "Arial Bold";
    fontColor = "255 255 255 255";
};

singleton GuiControlProfile(ScoreBoardTextNormalProfile : GuiDefaultProfile) {
    fontType = "Arial";
    fontColor = "255 255 255 255";
};

singleton GuiControlProfile(ScoreBoardScrollProfile : GuiDefaultProfile) {
    fontType = "Arial Bold";
    fontColor = "255 255 255 255";
};

This should be pretty easy to understand. All controls using the "ScoreBoardProfile" has a black background which is transparent and the border is 5 px wide, black and not transparent.

There is alot more settings that can be played with, for setting text color bevel etc.. This is not within the scope of this tutorial unfortunately!

Showing the scoreboard

Now we need to add some functionality to the scoreboard!

First we should be able to see it shouldn’t we?

At the bottom of data/CoinCollection/client/gui/scoreBoard.tscript add the following code:

//-----------------------------------------------------------------------------
// ScoreBoardGUI utility methods
//-----------------------------------------------------------------------------
function ScoreBoardGUI::toggle(%this)
{
    if (%this.isAwake())
        Canvas.popDialog(%this);
    else
        Canvas.pushDialog(%this);
}

function ScoreBoardGUI::clear(%this)
{
    // Override to clear the list.
    ScoreBoardGUIList.clear();
}

This toggles the ScoreBoardGUI so a call to ScoreBoardGUI.toggle() will make it pop up on the screen. If we then call toggle() again it will hide itself.

Now, this is just a function we need a way to call it. And calling it through the console is quite.. Clumsy.. So lets add a keybinding!

Adding an ActionMap

An ActionMap is a way to bind actions to inputs. We can push ActionMaps so that we can change keybindings temporarily and then pop them so we revert to whatever the bindings were previously.

In data/CoinCollection/client/actionMap.tscript add the following:

if (isObject( CoinCollectionMoveMap ))
    CoinCollectionMoveMap.delete();

new ActionMap(CoinCollectionMoveMap);
CoinCollectionMoveMap.humanReadableName = "Coin Collection Move Map";

CoinCollectionMoveMap.bind(keyboard, f, showScoreBoard);

And then add another file in data/CoinCollection/client/inputCommands.tscript with the showScoreBoard function:

function showScoreBoard(%val) {
    // %val == 1 on key down and 0 on key up
    if (%val) {
        ScoreBoardGUI.toggle();
    }
}

Now, we need to push this ActionMap on top of what keybinds we already have. We can do that in data/CoinCollection/CoinCollection.tscript, whenever a client connects or disconnects to a server:

function CoinCollection::onCreateClientConnection(%this) {
    CoinCollectionMoveMap.push();
}

function CoinCollection::onDestroyClientConnection(%this) {
    CoinCollectionMoveMap.pop();
}

Now the final thing is we need to execute all of these scripts we added if you haven't already, in data/CoinCollection/CoinCollection.tscript:

function CoinCollection::initClient(%this) {
    %this.queueExec("./client/gui/customProfiles.tscript");
    %this.queueExec("./client/gui/scoreBoard.gui");
    %this.queueExec("./client/gui/scoreBoard.tscript");

    %this.queueExec("./client/inputCommands.tscript");
    %this.queueExec("./client/actionMap.tscript");
    %this.queueExec("./client/commands.tscript");
}
PreviousSupporting multiplayerNextKeeping the scoreboard up-to-date

Last updated 2 years ago