For anyone who works in and around super small indie video game studios, you'll have noticed that individuals often have multiple roles in the project. People wear many hats. So many hats. More hats than a birthday party, fancy wedding and a day at the races combined. Maelstroms of hats. Hats everywhere. Hatters gonna hat, after all. So for a project like our upcoming game Orbitect, which is an ambitious physics-based construction roguelite with a complex tapestry of configuration, it was super important that we utilised our time in a sensible, efficient way in order to stay as focused and efficient as possible so that we could realise our vision without spending decades in the process and tying ourselves in a myriad of nebulous (albeit rewarding!) knots.
This post is about an example of how our small but mighty team have used some spreadsheet-based automation to streamline selections of our production in order to iterate and refine our gameplay balancing at speed and scale. We'll be writing more in the future about exactly how we tackled the balancing itself, as well as how Orbitect is utilising configuration on the programming side, but for now - feel free to treat yourself to a little insight into how we've joined the two together in data-driven harmony.
What's our problem?
In Orbitect, the player uses blocks and stat-based panels to craft a space station capable of destroying waves of space debris. Destroying that space trash earns the player money and resources to repair, upgrade and expand their station, so on and so forth, ad infinitum (well, until the end of the campaign at least). We have designed many levers of configuration in order to control the flow and feel of gameplay. For example:
Panels: How much does one cost? What's it's health? Strength? Defence? Speed? Efficiency? How much to upgrade or repair? How much damage can it do? What description does the player see?
Debris: How massive, or metallic, or explosive are they? How much money is earned from destroying it? What's the probability of reward if the debris is destroyed? What reward does the player get if they destroy it?
Waves of debris: When and how does debris appear? How much debris appears in a given wave? How long does the wave last? What does the play get for clearing a wave?
Wave Patterns: What type of ways can debris appear in a wave? Which direction? How often? How fast? Does it target a specific part of your station?
Bosses: When in the campaign do they appear? How difficult are they? What do you get for defeating them?
Stat Rewards: What rewards are available and for which stats? Are all panels affected from a reward? How much is rewarded?
Gameplay boosts: How much does each one cost? How much do they affect gameplay?
Other player values: How much money does the player start with? You get the picture…
All in we have just over 70 configurable attributes to work with, each with dozens (or more) entries comprising the overall configuration of the game. Can you imagine if we had to keep track of this manually in-engine? Tweaking the configuration to refine the game's campaign experience would be a time consuming, miserable, communicative monstrosity and would most likely fail before it began. Thankfully, we are making use of a data interchange format called JSON to store attributes and their values across various files.
When it comes to refining the game design itself - updating multiple values quickly and accurately directly in the JSON is still a challenge. It'd still require us to manually scroll through and edit various attributes. And if we had multiple waves, debris, panels etc in the game (which we do), then we'd have to do this multiple times.
So what did we do about it?
Enter: The Spreadsheet. That's right. We've employed the old reliable stalwart that holds the entire knowledge working world together - a spreadsheet. We used one to lay out the various configurations across multiple tabs. For example:
These are placeholder values! Don't go getting all excited.
Not only is this useful because of the use of rows, columns, and formatting that we all know and love, but because we can make use of formulas to create feux-JSON configurations in the spreadsheet itself. For example:
We specify a row and column from our easy to understand spreadsheet that corresponds to a cell containing an attribute name. We do the same for that attribute's value.
We hardcode in some curly brackets that will be needed in the JSON no matter the configuration values.
We add a Y/N column to flag whether the value is a string (because if so we need speech marks for a string).
We use the "indirect" function and Char(34) with the above to create a formula that acts as a concatenation and pre-populates the feux-JSON with spreadsheet values where they are needed. Some logic is also needed here to remove a comma from the last value in an encased sequence.
We can scale the JSON for all entries by adding 1 to our row reference (or a letter along for our column reference) in the next row down so that all rows from the spreadsheet are captured in the JSON file.
Thanks to the excellent JSONLint for providing an excellent validator!
Here's a snippet of one to illustrate what it looks like:
Making the feux-JSON.Great! That's already saved us some time trawling through JSONs. However, we were still maybe spending around five minutes copying, pasting, zipping up and sending to one another every time we wanted to tweak a few parameters and test out the gameplay implications. Given we are iterating repetedly during our development, we had an opportunity to further help ourselves. So we utilised a google apps script (with thanks to this thread and this thread) to automatically copy and paste our feux-JSONs into (real life) JSON files, and store them onto a specific folder in our shared google drive, for anyone in our team to pick up and play in their local build (and eventually use in the main development build). We even made a little button to run the apps script and export them!
Not the best looking button in the world, but I'm a spreadsheet geek, not an artist. What do you want from me?Behold! Exported JSONs hot off the press (of the button).
Now at the click of a button we have fresh Orbitect gameplay configurations ready to use the next time we run the campaign in-game. The couple of hours invested in making these little innovations (can I be so bold as to call them innovations? Probably! If you've read this far down then you must like this approach too, right?) has saved us exponentially more time in the run up to release. It has paid for itself within a couple of development days.
So there we have it. Is it rocket science? Hardly. Just a good old spit-and-sawdust approach to saving us a little bit of time, hundreds of times. Little friction-busting steps like this along the way help our team to release a game that reaches for the stars, and takes out the trash along the way.
September 22 global service S108 officially opened! After joining the community, please contact customer service directly to receive various gift codes. There are new player gift codes, screenshot gift codes, review gift codes, holiday gift codes and more. Discord: https://discord.gg/favQR3wdA7
So I fixed one thing but it was also broken on the next day. Now it should be smooth sailing into the rest of the game. I really thought I had tested out that area thoroughly but I guess not. I appreciate the person who pointed out the issue. I really can't thank you enough.
Today is full of great news! This weekend, when replenishing their account, each player will be able to receive not only GXP and a bonus to them, but also pleasant gifts in Karos!
Click the “Top up your account” button on our website from 09.22.2023 (17.00) to 09.24.2023 (23.59) inclusive and select the required amount of GXP with the most attractive gift!
The more GXP, the better the gift!
Each gift can be received no more than once per account.
The promotion will last until the end of the day on September 24 - hurry up to purchase GXP and receive your gift!
Had to rush this update instead of bundling it up with the leaderboard fix due to how game breaking it was. Leaderboard fix coming soon within the next hour hopefully.
Creating costumes for characters is more than draping a shirt over a back, putting on tattered pants, and affixing anything you can get your hands on to a jacket and calling them "decorations." Sometimes there is a whole philosophy behind such actions!
Take Sashko for example. In one of the previous reports we described his outfit: the sporty appearance of a parkour competitor, which consists of a light, airy shirt and a light mask suitable for free breathing, Cossack-patriotic elements (hairstyle, embroidered coat of arms of Ukraine on t-shirt) and ropes used for swinging in the Zone. It took us a lot of time to select clothes and accessories, not to mention finding the right materials and scanning them into the game. All this to emphasize his nature as a freelancer.
However, the real challenge was the Black Stalker. It's not visible at first glance, but if you look closely, you can see how many elements his outfit consists of.
The basic outfit of the Black Stalker mostly consists of the simplest elements that we had in our resources, such as a camouflage jacket and trousers and trekking shoes. The mask, on the other hand, was our own creation. We didn't want to give Stalker a regular gas mask because he would lose that dark vibe. That's why we decided to create our own version of the Black Stalker mask. We used a hockey mask with attached elements of an old gas mask and... washing machine parts.
The effect exceeded our wildest expectations. The design of the costume was so good that we used it many times during the photo session in the Zone.
But that's not the end of the work. Thanks to our graphic designer's concept sketches, we were able to plan further elements of the Black Stalker's outfit and even slightly modify it. For example, the hood has been extended to cover most of the Stalker's head; the mask itself looks more realistic and coherent, unlike its actual DIY model, and its colors refer to chernobylite crystals. Numerous patches, scarves, stitches, dirt and scratches have been added to the jacket and trousers, giving a heavily worn effect, and the shoes have been replaced with a more military model. We also added some other pieces of equipment, such as a knife sheath attached to the backpack strap and an additional bag attached on the right leg. We also took care of a small detail: instead of regular gloves, the Black Stalker has gloves with cut off fingers. Stalker's fingers themselves are black, indicating frostbite.
Someone might say that it was enough to just scan the model in the Black Stalker outfit. However, only thanks to the computer refinement of this character, we managed to achieve the desired effect, which is realism - here is a man who has been living in the Zone for years, so he cannot look as if he just came out of a clothes store.
Anyway, it's not our place to judge. We'll ask you what you think about it: do you like the character of Black Stalker as we presented him in the game? Let us know in the comments!