For quite a long time, gamification has been a hot topic. If things said at tech conferences and boardrooms across the world were tweets, I’m sure #gamification
would be trending quite often.
The premise is simple: take your willingness to spend your own resources (like money, time, and effort) and drive for mastery, which we all willingly dispense while playing games and somehow harness it toward a goal more to your liking.
While people are ready to pay quite a lot of money to endlessly grind in their favorite game while weeks, months, years pass them by,
Grinding is a term used in video gaming to describe the process of engaging in repetitive tasks.
Just try telling them to place proper numbers in this thing called Excel, play with the graphs and fonts for 8 hours a day, five days a week and suddenly you’ve got "an employee" who expects "a salary, health benefits" and "time off." "Time off what," you ask, "having a sweet computer all for yourself and making these awesome 3D-accelerated graphs?" Turns out, yes.
Apparently, millions of people are willing to work on your farm without pay (or even pay you for the experience), as long as the said farm is on Facebook? What’s the difference, besides lowered proximity to actual manure?
While proximity to manure does indeed have a certain significance, it’s not the whole story.
As the preceding title (and, quite frankly, the whole article up to this point—should have had a "spoiler alert" somewhere in there) might have clued you in, the "game" part is important. People like playing games. No, scratch that: people LOVE ❤️ playing games. People love playing (with) stuff that just sort of looks like a game, without even thinking about it.
As a kid (before new-fangled inventions like cell phones or friends), have you ever tried making your trip to and from school less boring by only stepping on the pavement blocks, but not on the border separating them?
For some reason, it made time and the road go by quicker, you got to your destination not bored out of your little mind. If so, you’ve basically gamified your trip home all by yourself, without Wikipedia articles, books, APIs or even any kind of framework.
Gamification is the application of game-design elements and game principles in non-game contexts.
The key part is "in non-game context"; you don’t need to make people play "in game context", they do that on their own if the game is appealing. You do, however, want to align their efforts with your desired outcome, be it profit, more users, higher quality users, more engagement / content, higher quality engagement / content, you name it. It obviously makes the process easier if your goals are more or less aligned with the users’.
Our desired outcome was simple, although quite sinister: we wanted good stuff to happen (to our platform and our users) more often and sooner. I won’t describe the whole process as details selecting the elements we took into consideration for gamification, the procedures, copy-writing, design process, etc are out of scope for this article.
What we’re interested here is our implementation. Right away, we decided not to implement it directly as the part of the app but instead chose the micro-service route, mostly to have an opportunity to use an off-the-shelf solution. We looked around and found some interesting projects. Unfortunately, we couldn’t get any of them to work well (all written in Python, we’re a PHP shop) which deterred us from going down that path as we weren’t really comfortable pushing a technology we don’t thoroughly understand to production.
Not using an existing project does not mean we can’t steal use its documentation for inspiration.
We’re left with implementing it ourselves.
To implement a "game engine" (GE), first we need to know what "a game" means to us. In our context, it consists of two parts:
6 potatoes
1 potato
and now has 7 potatoes
, is that relevant to us?By feature, we can separate the system into two parts: event processing and game evaluation.
$potatoes++
🧑🌾Event processing is looking at what the users are doing, inspecting that data by various aspects (…) and assigning the outcome to one of GE’s predetermined variables, triggering the game evaluation.
In our example, the base system (which we’re gamifying) is inspecting every action which would lead to the change of the current number of potatoes and, when the number changes, notifies the GE on the change. GE stores the latest state.
$potatoes >= 10
? 🙌Game evaluation begins on the GE after at least one variable has been altered: we check if the change has affected the current state of the game and, if it has, we change the state (award the user with the achievement), notifying the main system of the change.
In our example, GE now knows the current state for $potatoes
has changed and begins the evaluation stage:
$potatoes
variable?$potatoes == 10
relevant?That’s really everything there is to it. With these basic features (plus minor tweaks), we can implement all sorts of games.
We’ll go through couple of key aspects of the implementation, starting with the DB schema.
As every image is said to be worth a thousand words, here’s an image of our DB schema, followed by a few thousand words explaining it.
Variables are used to define which aspects of current state we’re interested in. We have the ability to optionally set the grouping mechanism. Grouping will determine users_variables_values.group_key
which is always an integer, even for dates.
For example:
$potatoes
$potatoes_by_day
$potatoes_by_type
Achievements are used to specify the game rules, as follows:
level | $potatoes >= X |
name |
---|---|---|
1 | 10 | Potato Enthusiast |
2 | 100 | Potato Lover |
3 | 10.000 | Potato Master |
$potatoes_by_day >= 2, INTERVAL 7 DAY
The GE defines three distinct types of evaluation it can use on a variable. The type availability depends on the fact if the variable is grouped and by which property.
$potatoes >= 10
, total number of potatoes is greater than 10)$potatoes >= 10, INTERVAL 2 WEEK
, total number of potatoes in the last two weeks is greater than or equal to 10)$potatoes >= 2, INTERVAL 3 DAY
, for the last three days, number of potatoes is greater than or equal to 2 each day. If the user skips a day, it cannot be "fixed" by doing twice as much the next day, this goal will still fail)Lastly, we come to the main protagonist of our story, The User.
# increment the $potatoes variable by 1 for user 123
-v -X PATCH -H"Content-Type: application/json" https://example.com/api/users/123/variables/potatoes -d'[{"op": "replace","path": "/value","value": "+1"}]'
# decrement the $potatoes variable by 1 for user 123
-v -X PATCH -H"Content-Type: application/json" https://example.com/api/users/123/variables/potatoes -d'[{"op": "replace","path": "/value","value": "-1"}]'
# set the $potatoes variable to exactly 11 for user 123
-v -X PATCH -H"Content-Type: application/json" https://example.com/api/users/123/variables/potatoes -d'[{"op": "replace","path": "/value","value": "11"}]'
# fetch the game progress for user 123 (with complete stats & progress breakdown per achievement level)
-v -X PATCH -H"Accept: application/json" https://example.com/api/users/123/achievements
The system has been in production for quite a while, and seeing great results, there are more KPIs and FTWs than you can swing a stick at.
As we’ve implemented it, the GE does not know about the nature of events being processed, semantics of variables, etc. This means that the system playing the game has quite a bit of work to do in order for it to work. I have no idea if this concept has an official name, so I’ve called this "an unmanaged game."
The managed version means much easier to implement the game inside your own system, and we would get some sort of sanity checking, as you could recalculate all the variables from scratch and verify their current values. Also, introducing a new variable retroactively would be possible (currently, we’re using a sort of "primer script" which puts the system in the desired state before introducing a new variable).
I hope this has at least given you a few ideas for implementing this yourself if not source code to copy/paste.
Happy gaming.