top of page

Post 11: I'm Back!

So, it has been a while, and with the world currently in a semi-suspended state of animation, and myself finishing my final year of university (finally), I am finding myself with a nice amount of free time. Recently, I took a break to work on a prototype for a bit of a fan game for a webcomic I've been following since nearly its inception (sleeplessdomain.com), as a bit of a break (I feel like Miyazaki creating On Your Mark, minus the god tier talent); but I am getting back to work on the demo for Lotus. Starting with... UNNECESSARY FEATURES!!!


Ok, I say unnecessary, but hear me out. First (or I guess second or third by this point?) off, I recently stumbled upon a webcomic, the Making of Neon (makingofneon.com, by the talented SodiumEyes twitter.com/sodiumeyes), which I would recommend to any and every indie dev for the simple but relatable characters to the interesting process of game design to the well portrayed tutorials disguised as entertaining character interaction. But this is a game dev blog, not a webcomics review blog, so I should probably get to the main point.


So, the reason I'm giving a shout out to MoN (Making of Neon) (other than the simple but strong art, good writing and ok I'll stop now) is that reading it has helped me rethink some aspects of my code. For example, information for cutscenes, maps, spells, scripted fights, etc. are all stored in .txt files and parsed when loaded or running. However, as shown in MoN is that this can be problematic in 2 ways: expandability, parse blocking, and translation. And how these can be solved with the magic of JSON!

Expandability is how a computer system is able to adapt to changes such as partial system updates and new demands or requirements.

Parse Blocking is the issue where a .txt (or other file) is being parsed sequentially and cannot parse the next line of the script without leaving the line it is currently on.

And translation is simply the ability to switch between different languages in the game (whether that be from the main/opening menu or during gameplay).


Now, none of these features are essential (or even an issue with their absence in the demo) which is why I call them unnecessary; but I know that they will be very important during later gameplay and development, which is why I feel the need to sort them out before finishing the demo, which includes building upon some of the systems I need to fix. So, to actually be a semi-technical game dev blog, I'm going to give a brief summery of how I tackled these issues.

First is Expandability. As I mentioned above, it is the ability for a system to be expanded. While I have a set format for maps, cutscenes, and spells, if I were to change my mind and wanted to add another variable into the file, i may have to change several lines of code in the program and likely every single object serialized in my support files. However, with JSON, I do not. JSON files work with JSON objects which store variables, arrays, and other JSON objects in a key value pair system.

Original text file for a spell:

New format in JSON:

As can be seen, while the JSON file requires more writing, the spells still follow the same format. However, if I want to add some sort of special feature to some spells, I don't need to rework the format of all spells. Rather, I would just add "Special feature": "random value", in with the rest of the variables. Processing allows for JSON objects to be checked for keys, so I can see if the spell even has the "Special feature" or not, and apply it according. And this works not only for spells, but also for my maps and save files, which are not parsed and store static objects. This switch to JSON files and how the objects are now loaded will take a bit more reworking in the code, but should give much greater versatility and usefulness to my spells and maps.


Onward to parsed scripts, cutscenes are in a different situation. Scripted (boss) fights are also parsed .txt files, but aren't in the same issue because they don't have to worry about blocking. As mentioned above, blocking is the issue where a parser on unable to move onto the next line without leaving the current one; makes sense, you can't look at something without looking away from what you're currently looking at. And this is a non-issue in simple systems. Make a character talk, move them, flash an image on the screen, etc. There is an order to the actions and they come at the conclusion of the previous action, so there is no blocking issue. But let's say I want to get a bit fancier (and I do, the later scenes after the demo are planned to do these things) and show simultaneous actions; characters talking over each other, walking and talking, screen effects while something is going on. These are all actions that cannot be done due to the blocking issue.

MoN also turns using JSON files to fix this issue. However, it also shows how this is... tedious, to say the least, without their resident genius programmer's tools to streamline the process. And I do not have her tools or skills, so I came up with a different solution. My parser already works on a moveOn trigger, where the moveOn trigger stays false until it is switched to true. The parser then moves onto the next line of code in the script sets itself to false, until the current action is resolved and moveOn is switched to true, which continues the cycle. The simple parser means that it is good at what it does, controlled single line parsing, but not good at reading multiple lines at a time. However, in addition to the parser, I can add cutscene objects that act like the parser is reading them, get updated each frame like normal, and allow the parser to move on.

Example: Normally, the system would have 2 commands, "move to location (X, Y)", then "speak line <A>". It would do this in that order, waiting until the desired character is in position (X, Y), then move onto the spoken line. But what if I want the character to move and the line to be spoken at the same time, I give a command "move to location (X, Y) and move on", then "speak line <A>". The parser will see the first command with the "and move on" part, and create a MoveTo object, storing the necessary information, and move onto the speaking line. This way the character may also speak while walking, an ability held by most humans, so it makes it more realistic then having to wait. (As a side detail, I can even combine them, so I can tell it to walk to a position and move on, then wait half a second and then speak, so it looks like the character starts speaking in the middle of their walk.)


Lastly is translation, the ability for the game to switch between languages. I'm not going to lie, I put very little major thought into this. While I knew the cutscenes could simply be written in a different language, I did not put much thought into how that would work or how redundant a lot of the lines would be; same for the spells and fights and enemies and in-game text and that's all my fault. Looking back, this was something I should have planned out when making my own engine for this game. However, the fix is quick simple and disappointingly short.

There are 2 parts to this solution. In Processing, all text is drawn on the screen with a text("text", position x, position y) command. But because this text() function is actually pointing to a super.text() function higher up, I can override the text() function to do this:

void text("text", position x, position y) {

translation = get translation of "text";

super.text(translation, position x, position y);

}


(told you it was disappointingly short)

The second part is the "get translation" part. Simply, every single line of text used in the game will have a translated line in a JSON file for each language, with the english line being the key and translated line being the value.

ex. (French translation file)

"New Game": "Nouveau Jeu",

There is will be a global variable tracking the language that can be switched in the settings. Of course, there will have to be a check to see if the language file has the text and what the language is, so our text function starts to look a bit longer:

void text("text", position x, position y) {

if (language == "English")

super.text("text", position x, position y);

else {

if (translation of "text" exsits) {

translation = get translation of "text";

super.text(translation, position x, position y);

}

else {

println("no translation for "text"");

error(12); // stops the game and prints "ERROR: 12"

}

}

}

(the actual JSON file for the language is loading when the language is switched and stored globally, so it is not needed to be reloaded each time)


And with that, I should be able to get a translation for any line in the game, as well as catch any line that does not have a translation.


Anyways, that's all for now. This ended up turning out to be a much longer post then I planned. I don't know when I'll be posting next, but if all goes well and I can get the art done for the maps, the demo (the WHOLE demo) should be out shortly.


Thank you for your support!

13 views0 comments

Recent Posts

See All

Post 10: Short Break

Guess who has 2 thumbs and miscounted their weeks? THIS GUY! (You can't see it, but I'm pointing to myself right now) So, sorry for the week long delay, I seriously goofed my planning and accidentally

bottom of page