Tag Archives: c2

Slidewalk TMX and C2 system

The Slidewalk system, taken from 2400AD is implemented by using several components in Tiled, and hooking them up in C2.

Tiled/TMX Component

The Slidewalk is comprised of several objects which are the children of an ObjectGroup; the ObjectGroup, in effect, is a single Slidewalk entity.

Components of a Slidewalk

What identifies an existence of Slidewalk is not the ObjectGroup, but the individual Objects which must be named starting with the prefix sw. Each Object component of the Slidewalk contains the name of the Slidewalk it belongs to. The name of the Slidewalk is the name of the ObjectGroup.

A Slidewalk must always have a path. A path is a Tiled polyline. It must be named swpath. The path will later define the waypoints of the Slidewalk. The swpath Object must also contain an attribute called speed. This is the speed value of this Slidewalk.

A Slidewalk must have at least one entry-only point. This point is defined by using an Object (parented under the Slidewalk in question). It must be named swin.

A Slidewalk must have at least one end-only point. This point must be named swend.

A Slidewalk may optionally have an exit point. This exit point may also be a potential entry point. Every point, whether it is an entry, exit, or end point, must begin with sw. Then use the keyword in to indicate this is an entry point, and the keyword out to indicate it is an exit point; these keywords may be used in the same point, such as swinout.

The exit and the end points must also contain a custom property called exitdir. This is a GridMove direction that specifies which direction the player will move towards when deciding the exit, in order to get off the movement effect of the Slidewalk.

C2 Implementation

In C2 the first step is to get the swpathObject to mark the waypoints of the MTiles. In the same procedure, they are marked with the name of the Slidewalk they belong to. The waypoint sequence index is internally based on how Tiled writes it, which is sequential anyway, so the C2 loop iterator does this conveniently.

As the MTiles are being tagged as waypoints, they are being added into the InstGroup with a group named after the Slidewalk’s name, which uniquely identifies these series of MTiles for SLG and GridMove. They are added in the order they are looped, so the sequence is still preserved at this point.

MTiles are then further marked with their entry/exit/end values, as well as the custom properties as inputted in Tiled.

When the player moves on top of the Slidewalk, the On GridMove reach target trigger will check whether the player is on an entry point. If it is, a function called CreatePathFromIG is called whereby it takes the Slidewalk InstGroup waypoints and transfers those waypoints to the player’s own InstGroup moving path. CreatePathFromIG does something more, though: it considers the possibility of multiple entry points; it finds the MTile that the player has entered from, and starts retrieving MTile waypoints from that point until the end.

 

 

Advertisements

Why C2?

For the past many weeks, I’ve been focusing a lot on the development of the animation sheets. But because of this, I hadn’t touched the former aspects of the game for some time, and when I got back to it, there were some issues that were brought to the fore, such as the Beltway being broken. To be honest, I was utterly surprised at this, since I had no recollection, or notes, that say that it had been broken when I left it to develop the other parts. There were also other things that I noticed that needed changing as I tested the implementation of the animation sheets along with overall player movement.

I found myself a bit overwhelmed and a bit tired, as I sometimes do, from having to debug C2 events. For all the user-friendliness it has, it can still be be quite opaque especially if you’re trying anything abstractly complex. It’s not totally the fault of C2, but because of its lack of modularisation, or object-oriented framework within the event system, picking apart why something doesn’t work requires a bit of jumping around, trying to sort out which are workarounds to some weird behaviour, and which ones are meant to do something actually functional.

Anyway, for several minutes I stared at the monitor, and I was seriously debating why I’m developing this game in C2, and not in Unity, where I have some experience in, and the fact that I’m actually good at coding (at least good enough not to doubt my ability to see the project through). Not only do I code, but I’ve been in the CG industry as a 3D artist and TD for 15 years now; on that alone, Unity is more of a familiar programme than C2. But I had a discussion with my wife who takes these technical diatribes with calmness and puts out good arguments, and the result is my rethinking of my situation.

So the question is: why C2?

It began with the fact that C2 made things simple. But what I’m doing with CITIZEN is not so simple. And that reason seemed to be not good enough.

C2 is fun because of the event sheets. But though the event sheets are effective, they are effective as procedures. They are less fun, and less effective when you want some object-orientation or inheritance, which is so useful when when I started delving into certain gameplay concepts that I wanted to implement for the game.

But I think one of the strongest reasons is one of a balance between a simplistic framework, and the relatively blackbox type of plugin filtered into the C2 editor which results in less bugs during development. This is both a pro and con. Taking Rex’s GridMove/Board/SLG/InstGroup system. These are separate systems working together as one. But it has some learning curve to understand how it all of them work. In fact, some components actually need the other, so they’re really necessary modules in order to come up with something like an isometric grid framework. But once this framework is up, the input and output (eg On reach target, On move accept) is unambiguous, and can interact naturally with any other event/behaviour in C2. Why unambiguous? Well, first, the C2 editor registers the event, so it’s part of the choices. Unity, on the other hand, can be quite confusing in this respect; what event handler is being called?; a search through the documentation is necessary.

In Unity, it is possible to get a well-written framework, but you’re going to have to try it out first before you know what you’re going to get. Sure, that’s the same with C2 plugins, but the C2 plugin framework shields you from some the randomness of 3rd-party scripting. C2 plugins follow C2’s rules in order to play nicely with C2. You’ll spot a lemon faster.

But I think the most important aspect to plugin frameworks is simply that they can be added in without messing things up. I don’t have syntax errors in C2 compared to Unity, so if something doesn’t work, syntax doesn’t necessarily some into the picture. Even data types are managed.

I think the best example I can think of is trying to implement Unity’s 3rd-person controller setup to your own game. There’s so much going on in that package that if you try to fix it to behave how you want it, you’re going to mess it up so much that you might as well write your own to begin with. Unity is so flexible, but unless something is so well written, with open-ended framework development in mind (like, for example, PlayMaker), the Unity environment is pretty much like a sandbox.

C2, on the other hand, is more like a playground. You can’t move the playground that’s there, but you can add other stuff into it, transforming it into something new.

At the end of the day, this is just a hobby so it’s important to have fun. Fun is a major motivator. It’s obviously not fun when I have to deal with the awkwardness of C2, or when I have to refactor my events. It’s not fun when I accidentally change the image-point on one of my images and having no undo option for that. But nevertheless, it’s fun to figure out how implement features on an engine that offers a good starting framework.

Without a doubt (in my opinion, at any rate), it is primitive tool when you consider other production engines out there, open-source or otherwise. I think it is easy to outgrow the tools due to the ever-expanding ideas for a game. That’s partly why I had to limit the ideas that I was coming up with. Is that a bad thing? No, but I think I should like a separate post about that. 🙂

I think, however, in the future, after I complete CITIZEN in C2, I will more seriously consider using Unity for other projects that may require a more expansive toolset, especially one that may yield a better game by going 3D.

Workflow: Tiled’s tile IDs not to be referenced in C2

Tiled’s tile IDs are quite volatile. Ordinarily, each tileset’s first tile should be 0-index, but unfortunately, this doesn’t seem to be guaranteed and I’m not sure if it should.

In this forum post Bjorn himself suggested not to use tile IDs as a reference, and instead use tile properties to make a harder connection, which is what I’ve done: created an ‘id’ parameter and and just retrieved it from there.

The only issue here is that each tile ID must be manually entered, but this better than figuring out how to make tile IDs behave.


To make it solid, write a tool that reads the C2 caproj, reads the Sprite object, stores the image source for each frame of a Sprite: a text lookup to associate a filename with an ID.

For example, the lookup can read:

proto_walls walls_block.0000.png 0
proto_walls walls_block_cross.0000.png 1
proto_walls walls_block_ne.0000.png 2

Where the first token is the tileset name, followed by the image filename, followed by the animation frame, which is the ID.

Then the tool is run again on the Tiled-side. Going through each line of the lookup, searches for the tileset name, locates the filename (maybe ignores the relative path), then sets the ‘id’ property to the stored value.

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.