Scripting Tags and Tag Classes#
Notice
This page is still work in progress and may contain inaccurate information.
Now that you've become comfortable manipulating object information with scripts, let's say you want to get more involved. For a real project, you'll likely wish to have scripts that are reused across a variety of object types. Continuing from the previous tutorials, we will cover the following:
- Creating a new tag class
- Attaching a default script to the new tag class
- Creating several tags using this tag class
- Creating a custom script for a specific tag using this tag class
Creating a New Tag Class#
To keep things simple for this example, we're going to create a tag class which will drive a rotating object in the world.
First, in Guerilla, create a new Tag Class using File > New > Tag Class...
. From there, give your new tag class a long and short name. For our example, we'll be calling it rotator [rotr]
. Before continuing, ensure your tag class inherits from the object [obje]
tag class - as this is what will allow this tag to be placeable in the world as an object.
Now, add the following fields for us to use in our script:
- rotation amount : Vector3
- rotation speed : Real/Float
Attaching a Default Script#
Save your tag class, then switch to Visual Studio. Create a new class to serve as your default script for this tag class, the same way you did for your scenario script. Ensure your class inherits from BlamTagObjectScript
, as this is necessary in order to allow access to any tag's data, as well as the associated object in the world. Override the Tick()
or Update()
methods, leaving their bodies empty for now, then save. Build your script project.
Return to Guerilla, and click the 'Attach Default Script' button. Select your newly created script in the dialog, then click 'Attach'. Save your tag class. Close the document.
Providing Easy Tag Access#
In many cases, you may wish to implement a method in your script to more easily access your tag data. Let's implement this, which will guide you through accessing the tag manually - and from there, you can decide which approach you'd like to use. In future tutorials, we'll assume that you're using this method.
Add a new method to your script called GetTag()
, which should return a pointer to your tag class (in our case, the return type should be rotator*
). The most simple implementation of the method would look something like this:
rotator* RotatorScript::GetTag()
{
return (rotator*)tag_data->address;
}
You can (and should!) do some additional error checking here, such as ensuring that tag_data
is not nullptr
. However, this basic implementation is sufficient for most purposes.
Creating the Script#
Similar to what you did with the scenario script, let's populate either the Tick()
or Update()
methods. Within the method, you'll need to first access the current world object using world_object
, and then read the rotation value. You'll then want to increase the rotation amount by the rotation_amount
field in the tag, factoring in rotation speed (ensuring to calculate using delta time or tickrate). Then, set the object rotation to the updated value. When finished, your method should look something like one of the following:
// Update method example
void RotatorScript::Update(float delta)
{
rotator* tag = GetTag();
BlamVector3 rotation = world_object->GetRotation();
BlamVector3 rotation_increment = tag->rotation_amount * (tag->rotation_speed * delta);
rotation += rotation_increment;
world_object->SetRotation(rotation);
}
// Tickrate method example
void ExampleScenarioScript::Tick(int tick)
{
rotator* tag = GetTag();
BlamVector3 rotation = world_object->GetRotation();
BlamVector3 rotation_increment = tag->rotation_amount * (tag->rotation_speed / 60);
rotation += rotation_increment;
world_object->SetRotation(rotation);
}
Next, returning to Guerilla, create a new rotator
tag, set a renderable object, specify your rotation amount and speed, then save. The last step before testing is to place the tag in Sapien, which requires adding it to our scenario's object palette.
Placing the Object#
In Sapien, click the 'Edit Types' button in the Hierarchy View. In the dialog, you'll see a dropdown menu for various tag classes. Choose the 'object' item, as this is what we'll use for our custom tag - since it derives from object
. Then, click the 'Add' button, and select the tag you created earlier in Guerilla, then click Select. Close the Edit Types dialog.
Now, using the Tool Window, select the object
palette, then select your tag name in the list. Just like the cube, select a folder in the Hierarchy View, then right-click in the viewport to place the object. Position it as desired.
Note that, in the editor, any script code will not run - as this code is only compiled and run when debugging the game executable itself - so if you don't see your object rotating, don't worry! To finish up, save your scenario, and finally, debug your game. You should see your newly placed object rotating - all on its own!
This is a small and simple example of how tag classes and scripts can be combined to create data-driven game content efficiently and quickly.
Scripting Global/Non-Object Tags#
In some cases, you may wish to attach scripts to tags which do not have any direct association with an object in the world, similar to globals
. In this case, much of the basic process is the same - with the only distinction being that your script should inherit from BlamTagScript
rather than BlamTagObjectScript
. This provides access to the tag data, but will not provide any world object information - as none exists.
Global/single-instance tags (tags where there will only ever be one tag within a project) may also wish to have no explicit script attached at all, and instead call plain functions from C++. To do so, you must include the script
macro at the beginning of the function definition or declaration, as follows:
script void ScriptableFunction()
{
// ...
}
Afterwards, this function will be visible in Guerilla in function fields - along with any methods that are found within the attached script. If no script is attached to a tag, then only these plain functions will be displayed.