Scripting 101: How to get started

Scripting 101: How to get started

This tutorial is aimed at people who have coded before but don’t feel comfortable yet to dive straight into the API. It’s good to have some JavaScript knowledge, but not required.

Where do I put my script files?

Scripts have to be created outside of the Tabletop Playground Editor with your favourite editor. We recommend Visual Studio Code, a lightweight editor with code completion for all platforms. After you have created a new package in Tabletop Playground, simply navigate to your package folder and put your script files into the Scripts folder:

[Tabletop Playground Folder]\TabletopPlayground\PersistentDownloadDir\[Name of your package]\Scripts

Any .js script files in this folder can be selected in Tabletop Playground. You can also go to the package folder by clicking the folder icon in the top left when you have your package opened in the editor.

Global vs. object scripts

There are two way to include script files in your project. One global script and objects scripts which are directly associated with individual objects. Note that the following controls and the scripting console are by default only available when starting a preview from the editor. In order to use them in a regular game, go to the Settings, click “Game” and then “Show advanced interface settigns”. Then activate the first option “Scripting UI in Game”.

Global script

The global script can be added through the session options when editing a state for your project.

You can find the session options in the right click menu

It is executed once, as soon as the corresponding state is loaded. It is loaded after all objects have been spawned, so it’s a good place to set up all your game related variables and logic.

Object scripts

An object script is directly attached to an object. It can be added either through a template or directly attached to an individual model when editing a state.

When an object is loaded into the world, any attached object script is executed (once). This happens after everything in the world is loaded (so all objects are there and after the global script has been run. If there is both a directly attached script as well as a template script, only the directly attached script gets executed.

Making stuff happen

As mentioned above, scripts are only executed once. So what you do in your script file is to set up any data and methods that you need and then tell Tabletop Playground when to call which of your functions (registering callbacks).

Don’t put any infinite loops inside the script! This will cause the script to hang and potentially crash Tabletop Playground.

For example for an object you can register an onGrab function which gets called by Tabletop Playground, whenever that object gets grabbed. Let’s look at some example code:

// include the api
const { refObject } = require('@tabletop-playground/api');


// add a new function to be called by Tabletop Playground when
// this object gets grabbed by any player
refObject.onGrab.add(
    function(obj, player)
    {
        console.log("I got grabbed by", player.getName());
    }
);

You can also define the function separately, but you won’t get auto completion for parameters this way. It can help making your code more readable though if you’re writing a long complicated function, or if you want to use the same function in multiple places.

// include the api
const { refObject } = require('@tabletop-playground/api');

// define our function
grabCallBack = function(obj, player)
{
    console.log("I got grabbed by", player.getName());
}

// add a new function to be called by Tabletop Playground when
// this object gets grabbed by any player
refObject.onGrab.add(grabCallBack);

If you add this script file to an object, whenever any player picks it up, it will put the defined message into the script console:

Console output after the chess piece got grabbed by the player Zorfmorf

You probably already noticed the usage of the variable refObject. It’s provided by Tabletop Playground and is the GameObject representation of your object, in the above example the chess piece. We can therefore make use of all the functionality outlined in the API. It’s only available when you attach a script directly to an object.

If you look at the definition of the onGrab function that we used to register our function, the function takes a GameObject (the object being grabbed) and a Player (the player grabbing the object) as parameter, which is why we have to add these parameters to our callback function grabCallBack.

So as a next step, let’s try to add a callback for onTick, which is called on every game tick, many times per second. Be careful what you do inside this method. If you put any complicated computations or queries in here, this can have a bad performance impact!

// include the api
const { refObject } = require('@tabletop-playground/api');

// add a callback for on-tick
refObject.onTick.add(function(object, deltaTime) {
    // let's launch the object slowly upwards like a rocket
    object.applyForce(new Vector(0, 0, 1000));
});

This should launch whatever piece you attach this to slowly upwards. Note that we omitted the second parameter for applyForce (useMass) since it defaults to false which is what we wanted in this situation. If your callback doesn’t seem to work, make sure that you provided all the required parameters.

Global Events

Next we are going to take a look the global script. In generally you want to put all code and callbacks here that is independent of individual objects. Let’s add some global events and try them out!

const { globalEvents } = require('@tabletop-playground/api');

// called whenever a chat message is sent
globalEvents.onChatMessage.add(function(player, message) {
    // show a message on screen of the player who wrote the message
    player.showMessage("Should you really say something like \"" + message + "\"");
});

// called whenever one ore more dice are rolled and sets all dice to six
globalEvents.onDiceRolled.add(function(player, dice) {
    dice.forEach(
        function(d, index) {
            // set the dice to 6 (faces 0 to 5)
            d.setCurrentFace(5);
        }
    );
});
It just works!

The world object

The world object allows you to interact with the world, which is a representation of the currently loaded level and everything that is included in it. It’s especially useful to find all or specific objects and players:

  • Load in new objects
  • Get a reference for a specific objects or a list of all existing objects
  • Draw debug lines
  • Line traces or sphere traces
Table of Contents