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
Edit on GitHub
Export as PDF
  1. Getting Started
  2. Getting Familiar
  3. Your First Game

Supporting multiplayer

In this tutorial, I have deliberately made some pit-falls that I have seen new developers falling in which prevents multiplayer gameplay from working.

So let's clean up in this mess, the first thing we want to address is the $CoinsFound global variable. We set it in the callback in data/CoinCollection/server/coin.tscript so how can we just use it directly in data/CoinCollection/client/commands.tscript? When we play in single-player mode the player and the host is the same process, this means we can use the global variable $CoinsFound in both client and server simultaneous. However this is an anti-pattern because this won't work for other clients in a multi-player scenario.

We can fix this using dynamic variables. TorqueScript has something called dynamic variables which is a very simple but very smart concept. Basically you can define any variable on any object by assigning it a value.

%obj.somedynVar = 2;
echo(%obj.somedynVar); //outputs "2"
%obj.TSisSpecial = "Is it now?";
echo(%obj.TSisSpecial); //outputs "Is it now?"
echo(%obj.tsisspecial); //outputs "Is it now?"
//(TorqueScript is not case sensitive either by default..)

We can use this to keep track on how many coins each client has picked up!

Remove the $CoinsFound global, and change the onCollision callback by adding %col.client.coinsFound++; instead in data/CoinCollection/server/coin.tscript so it looks like this:

function Coin::onCollision(%this, %obj, %col, %vec, %len) {
    %emitterNode =  new ParticleEmitterNode(){
        datablock = CoinNode;
        emitter = CoinEmitter;
        position = %obj.getPosition();
    };
    %obj.delete();

    %col.client.coinsFound++; // Automatically starts at 0
    if (Coins.getCount() <= 0) {
        commandToClient(%col.client, 'ShowVictory', %col.client.coinsFound);
    }
}

However, there is still an issue here. We are currently showing the player that picks up the last coin that they won. We should show the one with most coins that they won and all others should be told they've lost. We can solve that by looping over the ClientGroup SimGroup. The ClientGroup is a collection of all the clients who have joined the game.

So change the onCollision callback to the following:

function Coin::onCollision(%this, %obj, %col, %vec, %len) {
    %emitterNode =  new ParticleEmitterNode(){
        datablock = CoinNode;
        emitter = CoinEmitter;
        position = %obj.getPosition();
    };
    %emitterNode.schedule(200, "delete");
    %obj.delete();

    %col.client.coinsFound++; // Automatically starts at 0
    if(Coins.getCount() <= 0)
    {
        %winnerClient = %col.client;
        foreach(%idxClient in ClientGroup)
        {
            // If we are looking at the current winner, skip forward
            if (%idxClient == %winnerClient) {
                continue;
            }
            
            // If the current client has more coins than the current winner
            if(%idxClient.coinsfound > %winnerClient.coinsfound) {
                // The current winner has lost
                commandToClient(%winnerClient, 'ShowDefeat', %winnerClient.coinsfound);
                // All hail the new winnner
                %winnerClient = %idxClient;
            } else {
                // Current client has lost, winner stays the same
                commandToClient(%idxClient, 'ShowDefeat', %idxClient.coinsfound);
            }
        }
        
        // %winnerClient has the highest number of coins!
        commandToClient(%winnerClient,
                'ShowVictory', %winnerClient.coinsFound);
    }
}

Now the last thing we need to do is to change the data/CoinCollection/client/commands.tscript file, first of all we want to add a %score parameter to the clientCmdShowVictory function:

function clientCmdShowVictory(%score) {
    MessageBoxOK("You Win!",
            "Congratulation you found" SPC %score SPC "coins!",
            "disconnect();" );
}

And then we need to add another function for when we lose:

function clientCmdShowDefeat(%score)
{
    MessageBoxOK("You Lost!",
            "You lost with" SPC %score SPC "coins",
            "disconnect();" );
}

Now your first multiplayer game should actually be working! Try opening two instances of Torque, in one of the instances you press “play” then you tick the “host” check box to the left of the Go button. In the other instance you press join, "Query LAN" select the server that comes forth and join the game. Now you can compete with yourself about collecting most coins! Even better, you can host a LAN and let all your friends play your coin collection game with you! Give it a cool name and brag about it a little!

PreviousAdding some effectsNextAdding a Scoreboard GUI

Last updated 2 years ago