Tag Archives: scripting

Workflow: Interaction triggers

In the RND test project one of the most important systems I developed was the interaction trigger system.

This system is simply a method of binding an action (ie “Interact”) and a specifier, and then wrapped to make a ‘broadcast signal’.

This broadcast signal is then sent. Because the broadcast signal can optionally contain a ‘target’, only those matching the target description can be made to respond to the signal.

The importance of a system like this is the ability to make level-specific scripts. I’ll give a test case from the RND project.

  • In Tiled, a marker is created with a name. This is the trigger name, which can be anything as long as it can be uniquely identified.
  • In C2, a ‘On GridMove reach target’ action is bound so that it wraps the reaching of the tile with the trigger name of the marker it has reached.
  • On reach target, the trigger is sent to a BroadcastTrigger function, which accepts the trigger name, and the intended target of the trigger, if any. The target is comma-delimited, so multiple targets can be specified.
  • The BroadcastTrigger function looks at the targets, tokenises them, and then applies the ‘receivedtrigger’ variable of each of the instances that are able to accept triggers. It applies them only to the targets specified, or all instances if no target was specified.
  • Note that a family called f_trigger_receiver was made and the receivedtrigger variable is called ‘f_receivedtrigger’ in order that BroadcastTrigger can efficiently send it to those concerned.
  • In the level-specific script, the intended target is waiting for its specific f_receivedtrigger to change. BroadcastTrigger would have changed it.
  • When it does, it fires off the events there.

In addition to the trigger, level-specific behaviours are specified, and can override the default AI of any object. This is why this is important, because the scripting is done in a separate event sheet (ie logic) and not predefined in the main logic.

Now, other actions are bound, as needed, to the BroadcastTrigger. For example, in the RND project, the On reach target trigger condition was the first one I implemented. But quickly afterwards, it was easy enough to bind the TalkToNPC function, or the InteractWithNPC function to the broadcast.

Of course, the trigger name changed. In the TalkToNPC trigger, the trigger name was "talk "&cmover.name in which the ‘talk’ keyword was appended by the actual variable name of the NPC that was talked to. The name of the NPC talked to was embedded in the signal and no target was specified because the logic was that either the player or the game world was the receiver. But, it is also possible, or even more beneficial if indeed the recipient of the ‘talk’ action was put in to the trigger target, as I did with the next implementation.

I implemented an ‘InteractWithNPC’ action in the same way, but included the recipient of the ‘interact’ action as the target. In the level script it was intended to add to the accomps to keep track who had been interacted with.

The BroadcastTrigger concept is just a concept, but seems to be a very flexible one, as I am using it currently to design a generic kind of interaction behaviour between a single ‘Useitem’ action to a host of different possible objects, each with their varying results. It’s this reason why BroadcastTrigger is useful, because behaviours are defined in the event sheet, and can be contextual as well as part of the main logic.

 

Advertisements

C2 Sprite Manager

2017-02-23-08_02_32-c2-sprite-manager-b1-_-r__game_projects_citizen_demo_b_c2_c2-caproj

Overview

The C2 Sprite Manager (C2SpriteMan) was written by me, Lernie, and is a Python (exe wrapped) that views and modifies image files and their corresponding data as it relates in a .caproj (C2 project) file.

This project was originally done for LW (called LWC2), and for speed and flexibility, I migrated the code to Python and turned it to a Windows-based utility.

This tool revolves around a specific pipeline which involves mass creation of sprite assets from LW (or any 3D prog) and then conforms those renders to something that can be plugged into C2.

The tools works upon existing Sprites as they are defined in the .caproj file. This is due to the fact that ‘sid’ attributes in C2 might be better of be maintained by the host prog, so new objects are created only within C2, not externally.

The tool organises sprite graphics into ‘units’ (left panel) From ‘units,’ the individual sprites are displayed (right panel) where the name, its version number, frame duration, image-point file and crop-file and crop-image-point file validation, speed, looping and such parameters as found in C2 itself.

First, the frame number is determined by the actual number of frames found in the unit’s folder, and is used to debug if more or less frames were rendered than expected. There is an option to preview the unit animation using djv (hard-coded, so it djv must be installed). The frame rate is fed as an argument in djv so it mimicks what you would expect to see in C2.

The image-point, crop, crop-image-point files are another thing. First, the image-point is a special file generated in LW which contain normalised X and Y coordinates of the hotspot, and/or an image-point for a particular frame of the animation. It is formatted thus:

_IP_hotspot 0.1 0.2
_IP_gunpoint 0.5 0.12

Again, each frame of animation has a corresponding image-point file, and are named in a specific convention that makes their relationship apparent.

NULL.0001.png # rendered frame
NULL.0001.png.imagepoint # ascii imagepoint file

Note the use of the ‘NULL’ name. This is a constant name. Remember that these files are contained under the unit animation folder, so they are unique; there is no need to make them unique from other units as C2SpriteMan identifies the image based on the folder they are in, very much the same way C2 does it.

The next step is to crop the sprite, and ImageMagick (IM) is used as the tool for it. In this process, IM outputs a file that defines the cropping operation that it has done on the image. Since any number of sprites will most likely have a different cropping result from each other, this information is important because I can use it to modify the image-point file, which changes based on how much was cropped from its partner NULL file.

These cropped files are named as such:

CROP.0001.png
CROP.0001.png.imagepoint

These CROP files are used by C2SpriteMan as the actual usable sprites that is meant to be used in C2,

After cropping, the sprites are copied over to the C2 folder, which is defined as the /c2 subdirectory under the overall project folder. (Since I use many applications, I keep a main project trunk with major areas of delineation, depending on how much relative dependencies are needed for a particular use. For instance, LW, Maya, and C2 all reference relatively. But LW and Maya reference the same things, such as texture maps, cache, other shareable data. C2 references its own assets and files. So I kept the 3D side separate from C2)

The copy procedure transfer all renders to the C2 folder in strict accordance with how C2 expects them to be: file names are stripped down, and become the ###.png format, and are put in their own sprite folder. They were managed in 3D in the same way as C2 to make this process easier.

Once copied, all data can be ‘committed’ to the .caproj file. What ‘committing’ means is that any parameter change made to the sprites (eg changing Speed) will be updated in the .caproj file. This is a write operation on the .caproj, and a backup is made every time it is done. There is a drop-down menu on the lower-right that allows for rolling back to a previous version.

From the top procedure

I’ve just explained the process, but not in the sequence that it would otherwise be done. So this could be confusing reading for my future self. So this is how it’s done from the top-down.

Note that .caproj (folder-based projects) is necessary to use, for obvious reasons.

C2: Create placeholder Sprites

In C2, Sprite objects must be create beforehand. It is important to name the Sprites accordingly because this is essentially the unit name that need to correspond with the renders in 3D.

For purposes of illustration, let’s call our unit ‘hunter’.

Save the .caproj so that these modifications are reflected in the file.

3D: Rendering to expected locations

In 3D, it’s important to render to the following location

<project_directory>/renders/units/<unit>/<animation><version>/

First note the /units subfolder under the /renders folder. This is mandatory token.

Then <unit> represents the name of the sprite unit (‘hunter’).

<animation> represents that particular animation name (‘walk’)

Though there is a <version> token, this doesn’t have to be used, though it is much better to use it because you can juggle around variations quickly.

When placed properly, you should get something like this:

2017-02-23-08_43_27-c2-sprite-manager-b1-_-r__game_projects_citizen_demo_b_c2_c2-caproj

In the Sprite list, note ‘Fr’ is 0. This means there are no frames there. In order for any frame to register as proper frames, they need to be named thus:

NULL.0001.png

Note ‘IP’ is also 0. This means that there either have been no image-points generated. The number of IP should be the same as the number of Fr.

Note ‘Crop’ is 0, which means no cropped images have been detected.. ‘CropIP’ is the same deal.

Lastly, note that the C2-related parameters like ‘Spd’, ‘Loop’, etc, are -1. -1 means that no change should be done when you hit ‘Commit caproj’. If this value is larger than -1, then that value will be set in the .caproj as your desired value.

Let’s say now that some frames were rendered from the 3D application, and move on.

C2SpriteMan: Previewing, settings attributes

This step can be done at any point even after cropping.

You can preview the animation using djv. It takes the ‘Spd’ parameter and uses that as the framerate. If ‘Spd’ is -1, then djv will play it back with whatever default it selects.

On the far-right side, an Attributes panel shows the fields which you can adjust parameters of selected sprites. Hitting the blue button ‘Apply’ will apply your changes onto the sprites. These changes are stored in their respective unit folder, so that these settings are portable and will carry over as long as you keep those files in the folders they are meant to be in.

3D: Generate imagepoint files

Generating imagepoint files in LW means getting the projected camera-view space coordinates of a particular 3D location. I’ve done this in LW using LScript but this is a 3D-specific solution. I’ve not it in Maya, and I reckon it would be a different solution.

Either way, the generation of imagepoint files must follow the rules outlined in the first section. Once the imagepoint files are done, C2SpriteMan should reflect a corresponding value in the ‘IP’ column.

C2SpriteMan: Croppping

After generating imagepoint files, the next step is to crop the sprites. This not only crops the sprites but it also ‘crops’ the imagepoint files accordingly, taking the values there and trimming them so that the cropped imagepoint files will have values that register with their corresponding cropped spirtes.

C2SpriteMan: Copying

The next step is to immediately copy the sprites over to the C2 folder.

C2SpriteMan: Commit

After copying, you can then commit.

First, select the unit animations you want to effect. Then hit ‘Commit caproj’. This function looks at all the settings of the selected animations and goes through the .caproj, parses it, and applies the XML settings.

Hotspots and image-point attributes are derived from the .imagepoint files, while the frame-related settings are derived from the other individual settings inside the 3D unit folder.

Frame duration is applied based on the number of CROP sprites detected in the 3D unit folder.

C2: Check sprites

Open up C2, and confirm the settings.