Author Topic: [Tutorial] Interactive Vehicle Support and You  (Read 3724 times)

The idea behind Interactive Vehicle Support was simple: provide a way of interacting with things on vehicles. While Trigun included some documentation in the add-on, I felt that having a tutorial with examples might help to clear up some confusion on how to use it.



Example 1: Converti Hood

1. Getting Started:

Before any scripting can be done, we need to make sure we have animations to work with! In this example, we are going to see how one can update a vehicle with Interactive Vehicle Support. We will use Phydeoux's Converti, because it already has animations.

Download Phydeoux's Converti & Interactive Vehicle Support


2. Change the server.cs File:

The vehicle needs to reference the script. So, we are going to change the server.cs, which is responsible for executing the scripts when your server starts.

Here is an example of rewriting the server.cs:

Code: [Select]
// server.cs

// Handle Required Add-ons
%errorA = ForceRequiredAddOn("Vehicle_Jeep");
%errorB = ForceRequiredAddOn("Support_Interactive_Vehicle");

if(%errorA == $Error::AddOn_NotFound)
{
        error("ERROR: Vehicle_Converti - required add-on Vehicle_Jeep not found");
        %errors++;
}
// Remove Jeep from Vehicle List if Disabled
else if(%errorA == $Error::AddOn_Disabled)
        JeepVehicle.uiName = "";

if(%errorB == $Error::AddOn_NotFound)
{
        error("ERROR: Vehicle_Converti - required add-on Support_Interactive_Vehicle not found");
        %errors++;
}
if(%errors)
        return;

exec("./Converti_Explosion.cs");
exec("./Converti_FinalExplosion.cs");
exec("./Converti_Spring.cs");
exec("./Converti_Tire.cs");
exec("./Vehicle_Converti.cs");
exec("./Vehicle_ConvertiInteractive.cs");

Notice how I added "exec("./Vehicle_ConvertiInteractive.cs");". We are going to create a new datablock in a new script file, so we can focus on what needs to be done to implement the support script.


3. Create the Vehicle_ConvertiInteractive.cs File:

In a new script file, we create a datablock named "ConvertiInteractiveVehicle" that inherits from the original vehicle datablock. Make sure to redefine the uiName to distinguish it from the original!

Code: [Select]
datablock WheeledVehicleData(ConvertiInteractiveVehicle : ConvertiVehicle)
{
        uiName = "Converti - Interactive";
};

This will reference the original Converti, so we can concentrate on the changes. According to example.txt from the Interactive Vehicle Support add-on, we can define a vehicle as interactive like this:

Code: [Select]
        //- Interactive Definitions -
        isInteractive = true;
        iNumZones = 2;
        iZone[0] = "-5 -0.5 0.2 -1.4 1.2 2.5";
        iZoneScript[0] = "onLeftDoor";
        iZone[1] = "1.4 -0.5 0.2 5 1.2 2.5";
        iZoneScript[1] = "onRightDoor";

Since we only have only one animated part (the convertible roof), change 'iNumZones' to 1 and remove the definitions for the second zone. We also want to rename "onLeftDoor" to something referring to the interactive zone, so let's call it "onTop".
This is what we should have now:

Code: [Select]
        //- Interactive Definitions -
        isInteractive = true;
        iNumZones = 1;
        iZone[0] = "-5 -0.5 0.2 -1.4 1.2 2.5";
        iZoneScript[0] = "onTop";

Now, we have the definition for one interactive zone. The value of 'iZone[0]' represents the coordinates used for defining the interactive zone in the form of "minX minY minZ maxX maxY maxZ".


4. Get the Coordinates of the Interactive Zone:

There are many methods of getting the coordinates. We could use a modelling program to look up the coordinates for the bounding box of each animated object if we had the source files, but we don't, so that isn't an option here.

Another way is to use Torque ShowTool. Open the model in ShowTool and, with the help of grid seen in certain viewports (anything that is not perspective view), we can determine the coordinates fairly easy. Each little box is 0.1 Torque units.

Trigun also implemented a feature which helps us get the coordinates in-game. In order to do so, we have to do the following in the console:
Code: [Select]
$Debug::InteractiveVehicles = true;Then, if we click on the vehicle in-game, it will display the coordinates of where we clicked in the console.

Once we have the coordinates, let's add them to our code. In the end it should roughly look like this:

Code: [Select]
        //- Interactive Definitions -
        isInteractive = true;
        iNumZones = 1;
        iZone[0] = "-2 -4 1.2 2 1.4 2.5";
        iZoneScript[0] = "onTop";


5. Create the Script Callback:

We are still not done yet! We have defined the zone, but we have to make the whole thing work. According to example.txt, we can define an interactive script callback like this:

Code: [Select]
function YourVehicle::onLeftDoor(%this, %obj, %client, %offset, %position, %vector)
{
        %time = getSimTime();
        if((%time - %obj.leftDoorTime) > 1300)
        {
                %obj.leftDoorTime = %time;
                %obj.leftDoor = !%obj.leftDoor;
                %obj.playThread(0, %obj.leftDoor ? ldOpen : ldClose);
        }

        return 1;
}

We need to change a few values to suit our needs. "YourVehicle" is obviously the name of the vehicle datablock, so let's rename it to "ConvertiInteractiveVehicle". "onLeftDoor" should be changed to "onTop", and every instance of "leftDoor" should be changed to "top".

The script comes with a feature which prevents us from disrupting the animation by adding a timeout from the moment we originally activate it. The number "1300" is the length of the timeout in milliseconds. Normally, it should be adjusted to the length of our animation, but for the sake of simplicity, let's just keep that value. "ldOpen" and "ldClose" are the names of the animations we are planning to trigger. However, those must be changed to correspond with the name of the animation we want to play! Luckily for us, Phydeoux used the straightforward names of "open" and "close" for his animations, so let's use those.

If we changed everything correctly, we should have this:

Code: [Select]
function ConvertiInteractiveVehicle::onTop(%this, %obj, %client, %offset, %position, %vector)
{
        %time = getSimTime();
        if((%time - %obj.topTime) > 1300)
        {
                %obj.topTime = %time;
                %obj.top = !%obj.top;
                %obj.playThread(0, %obj.top ? open : close);
        }
   
        return 1;
}

At this point, we are pretty much done. Now, we can open and close the convertible top and use our handbrake separately! In case you are not sure if you followed this tutorial correctly, here is the complete code for reference:

Code: [Select]
datablock WheeledVehicleData(ConvertiInteractiveVehicle : ConvertiVehicle)
{
        uiName = "Converti - Interactive";
       
        //- Interactive Definitions -
        isInteractive = true;
        iNumZones = 1;
        iZone[0] = "-2 -4 1.2 2 1.4 2.5";
        iZoneScript[0] = "onTop";
};

function ConvertiInteractiveVehicle::onTop(%this, %obj, %client, %offset, %position, %vector)
{
        %time = getSimTime();
        if((%time - %obj.topTime) > 1300)
        {
                %obj.topTime = %time;
                %obj.top = !%obj.top;
                %obj.playThread(0, %obj.top ? open : close);
        }

        return 1;
}


Addendum:
       
Vehicles may store their animations is separate .dsq files. This should be no problem, as you can simply load those animations with the help of the script. Here's an example snippet taken from the Tudor:

Code: [Select]
datablock TSShapeConstructor(TudorDts)
{
        baseShape  = "./tudor.dts";
        sequence0  = "./root.dsq root";
        sequence1  = "./bootlidopen.dsq bootlidopen";
        sequence2  = "./bootlidclose.dsq bootlidclose";
        sequence3  = "./bonnetlidopen.dsq bonnetlidopen";
        sequence4  = "./bonnetlidclose.dsq bonnetlidclose";
        sequence5  = "./ldopen.dsq ldopen";
        sequence6  = "./ldclose.dsq ldclose";
        sequence7  = "./rdopen.dsq rdopen";
        sequence8  = "./rdclose.dsq rdclose";
}; 

There is a limit on how many animation threads you may have playing at any time. The current limit is 4 which means you can animate a two door car with bonnetlid and bootlid (hood and trunk). You can try getting around the problem by using AIPlayers, but be warned it is datablock intensive and should be used sparingly!


Example 2: Triggering Lights on a Police Car

Coming Soon!


Credits:
Trigun - co-author, man behind the Interactive Support Add-On
Blocktim - proofreading and being a Swede
Spation - proofreading (not well)
« Last Edit: October 13, 2012, 04:46:06 AM by Barnabas »


here's hoping this helps people implement this and make more awesome vehicles!

here's hoping this helps people implement this and make more awesome vehicles!

Yeah, but if this isn't stickied, then it'll end up like every other resource / tutorial.

No, it would have a decent amount of threads and would help out a lot of people. You can say the coding help section does this, but how many times have we seen the same topic made over and over? How many, "where can i learn Torquescript?" threads have there been?

I've written resources, greek has, truce, destiny/zacko wacko and a few others, only for them to fall deep into the abyss never to be seen again. I'm just saying it would be a nice section to have and i'm sure it would encourage more people to come up with and share some nice resources that they have written.

someone give me a very good reason why we don't/can't have a 'coding resources' subsection

I asked Badspot about it and he ignored me.

Bump. I'm planning to finish the next section by next week. Also, has anyone tried retrofitting Kaje's boxtruck with this? Perhaps Phy's Delivery van?

You should add the ability to make your own vehicles with bricks in the script >:D
Or at least being able to walk around in vehicles while it's moving & move with them.