Smokitten – two apps to help prevent and treat nicotine addiction

App links and official info :

DOWiNO‘s official website for Smokitten
Smokitten iOS Android
Smokitten Park iOS Android

Smokitten and SmokittenPark are two sides of the same coin. A  Willingness for the creators of this serious game, DOWiNO, to help people who are smoking to stop and younger non smokers to never start. The former will get informed about their habit, track their progress, get notified, and the latter will be informed about this addiction and help the cat caracter to stop smoking.

Along with health professionals specialized in addiction, DOWiNO has devised a number of fun and addictive clicker-like minigames so that Smokitten players (smokers) can get through their craving period, and SmokittenPark players (non-smokers) can have fun playing the game, helping the smoking cat to get rid of his addiction.

Mini-games are represented by physical activies all around the cat’s 3D floating island. As time goes by, the Island is also progressively transforming from a dry and dirty island to a lush, green tropical island. Collecting coins by playing activites also lets you buy additional decorative elements for your island. Mini-games or “activities” unlock progressively.

The game’s progress is based on statistical analysis of nicotine withdrawal. The Island has a physical “day” counter which changes as days go by. The counter starts at 222 days and counts down.

Smokitten is a game you come in voluntarily and the implicit rule is that you should report every time you feel the need to smoke in the game’s menu so that the SmokittenPark players – notably your friends – can send you a little message to cheer you up, and a bonus coin multiplier can be applied for your craving period so that you can basically farm more coins during that period and not get your cigarettes out.

So both Smokitten and Smokitten Park , on top of the game have a small social aspect where a Smokitten player can add Smokitten Park friends to get some helpful messages via push messages during a craving period.

Smokitten Park’s cat, a smoker, has some regular craving periods during the game’s period and will notify a player via local notifications of him wanting to smoke, at that point you have just a couple of minutes to open the game and “save” the cat and advance the game’s time counter to get a bit closer to the end and make the island a bit nicer.

Mini-games have levels of difficulty which can be time based and/or be bought by in game coins (no in-apps).

This quick presentation does not completely show the similarities and differences between both games, but to discuss the technical stuff we worked on, we just needed to get the context right, and get a feel for the game.

You can grab yourself a SmokittenPark install (the game is free, check out the links at the top of the post) to get a feel for the gameplay and the mini games which are essentially similar on both games.

A Custom Build System :

Since Smokitten and Smokitten Park share mini games for different purposes, the core code is the same. We decided at the time, to use a single Unity project and have a custom build system which would automatically swap app ids, game variables (Serialized Object) and custom android manifest or Xcode project post processing.

The game is all in a single scene (though there’s a startup scene, developers and game designers would work on the main scene) so the custom build process is accessible on a GameObject’s Script with a custom inspector view.

Here’s the manual page of Unity that explains how to build a Unity project by script. Before running the build process, we parse one of the main Android Manifests (if the build target is android) to change some value with regex as the plugins for Facebook and Twitter sharing needed custom api keys or values to be changed based on the game (Smokitten / SmokittenPark). After the build process, on iOS, some modifications are made to the Xcode project using a static function with the PostProcessBuild Attribute.

Essentially, Xcode projects needed additional plist values and the UnityEditor.iOS.Xcode namespace contains classes such as PlistDocument that can help in editing the plist file.

Here’s a static function to automatically add the “remote-notification” background mode  :

using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using UnityEditor;
using System.IO;

    public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)

        if (buildTarget == BuildTarget.iOS)
            string plistPath = pathToBuiltProject + "/Info.plist";
            PlistDocument plist = new PlistDocument();

            PlistElementDict rootDict = plist.root;

            var buildKey = "UIBackgroundModes";

            File.WriteAllText(plistPath, plist.WriteToString());

The custom build system automatically loads (Resources.Load) a SerializedObject with game variables specific to Smokitten or SmokittenPark, and applies them to the main GameObject that manages the entire game right before building.

Note that we could have gone with custom compiler flags and make sure that Smokitten or SmokittenPark specific menu panels, game play mecanics etc, were properly seperated. But in most cases it was not the most pratical during the prototyping phase, and we kept things as they are now.

Obviously, if you were to create two apps with a similar code base, you should consider how much of the code base are shared – are there only a few classes of difference as we have, or is the core something you should be sharing via a git submodule for example.

Serious Games, iteration and working with a medical team :

Most of the educative information such as information popups or game achievements that also deliver information but are reactive to player values reaching a certain goals, were designed with a medical reality in mind and as such, all the data for achievements, time based information (for example , seven days in, you could get a popup telling you that after seven days your starting to get taste back), or even time or date based rewards (after a number of weeks, or at a certain time of year where you could be at risk, the game could give you a bonus coin multiplier to encourage play) were provided through a simple Excel document that the medical team could fill in.

At first, the excel file was imported, parsed, and a ScriptableObject created. Due to frequent update, this wasn’t practical, and we almost went for systems that would synchronize google sheets with the game. In the end, for a number of reasons, the data is still kept as a ScriptableObject yet it is udpated from a server that holds all the data and also manages communication between players.

Anyway, the important thing here is that we as developers, not knowing in advance all the possible conditions for a game success or informative popup to appear, needed to decide on a system to allow game designers and the medical team to write they’re own date, time or game variable conditions for such an event to pop up in game. This would be basically deciding on a set of possible condition types, and allowing an expression interpreter to decide on whether or not the conditions are actually met.

To not reveal everything of the system as it’s quite complex under the hood, people would write an expression such as this fake one :

00:00:00:00:00 > 00:10:00:00:00 && ( d01 || d02 ) && player_age >= 36

The first part of this condition is a format we decided on to describe date periods AFTER the start of the game. So this first part means “between 0 and 10 days after the start of the game” , the second part after the && operator, means “if today is either monday or tuesday” and the last combined condition is a simple “player age is greater than or equals to 36” .

That’s a pretty complex set of conditions we don’t know in advance. But is “quite” readable by a human.

A complex regex formula later, and the condition is reduced to :

di0 && ( d01 || d02 ) && player_age >= 36

Where di0 is replacing the “date interval” and stored as values. di0 is now a variable than can be replaced, as are d01, d02, player_age, such that this would be a valid math expression (using bitwise operators of course).

So with an expression parser like mxParser the end result is evaluated, with each argument replaced to number values, and we get either 0 (for false) or >=1 when its true.

We still have fixed logic inside the game as to set the value of di0 we need to test if the current date is inside the defined interval. player_age is known if the player has defined a birthdate… and d01 or d02 here to decide if we’re monday or tuesday are predetermined arguments people could write in and are set to true/false based on what day it is.

So even though you couldn’t do everything because argument values needed to be replaced at runtime to match the player, the date and other game parameters, the possibility of defining and combining conditions allowed for the team to create achievements and information popups and rewards for a large number of different persons , based on a lot of different parameters, and also during the entire game without the developer having to write additional condition and leaving the inital excel sheet as readable as possible.

As of now, the Excel sheet is read, parsed, and the regex system is no longer done in the app , the app is receiving the translated expressions directly (the second version) so it has less to process.

Visuals :

It’s been more than a year now that we’ve been thinking and working on this game.
There were a lot of hurdles to overcome. The first one was : how do we make a floating island evolve visually for 222+ days, and with a huge number of possible decoration elements either than can be bought or pop up on themselves.

The first tests were made in 2D. But the number of assets to produce for a 2D version + the technical challenge to have a lot of textures for the grass to grow progressively and plants to appear… was too much. We thought we’d push DOWiNO to go 3D on this one.

This is not our first game together, and “A Blind Legend” was in 3D but with nothing to show, so we can say this is our first “real” 3D game together and this, was to solve the issues with making the island evolve visually. instead of patching up with textures of grass, the reveal of the beautiful healthy island is done by interpolating two textures of the island together, not linearly but based on a mask that makes patches of grass, snow, dirt, appear progressively as the interpolation nears its end. And the waterfall of green disgusting water progressively gets shiny blue.

Those are in fact easy effects to achieve, and from one day to the next, you might not see the difference, like you don’t see your hair grow in real time (well you know what I mean) but this was perfect to make it evolve gently. Of course you do have a reminder, every day that passes, with the giant counter on the island, that you are making it. that you are progressing. But you’ll be more amazed of realizing how terrible the island looked when you started and how pretty it will be then. A nice surprise that I’m not sure we could achieve, at least not that easily, in 2D.

Plus, in 3D, we all had much more fun with some custom shaders and techniques to achieve DOWiNO’s visual goals !

Other technicalities :

The project was quite long and we had the opportunity to work with a couple of artists with which we would share on texture atlasing, or changing the skins of the plants. A lot of tools were created to help artists in that regard… some simple and some complex, a lot were just temporary tools, as always though, we love to create custom editor windows, inspectors , to help with the design process or make some processes go faster such as reapplying textures.

I can’t recall all the small little problems that were solved faster with a script than taking hours doing it by hand – although doing it by hand is sometimes much better.

Localization was setup with the i2Loc unity plugin which synchronizes a google sheet with the app and let’s us eventually add more languages over time without necessarily updating the app, although it is preferable to so an offline cache is present for everyone that will never connect to the internet or have a bad connection. i2Loc was very interesting to setup, although all the game data (game events) can change at any time (if we decide to add an event or information for a specific event) the synchronization of string keys and values were a bit of a pain to handle but that’s really specific to this project and I have no specific tips to share on that , the plugin itself is great to work with and you can deliver other data through it instead of just localized strings since one key could deliver a string data value instead of just a translation for a play button.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.