π by NMcCoy
An odd little adventure made entirely of emoji. I don't just mean the UI; the game engine itself is made out of emoji.
The game is built around a simple rewriting system for emoji, each operation replacing some collection of emoji with others, with the player and the game together making choices of which legal operations to perform based on the symbols available. As such systems are Turing-complete, I was able to implement a game engine out of these rewrite rules, featuring exploration, turn-based combat, and leveling up. I made things easier for myself by creating shorthand codes for commonly useful operations (for example, "π₯ππ£" means "replace π₯ with π£ as many times as possible"). I also made something like an event system whereby rules can be grouped with a tag: "βΆπ" means "perform all currently-legal operations tagged with π". As an example, the "damage" emoji is π, and it's associated with the rule "π:πβ€β‘π€", meaning "immediately after creating a π, perform the substitution 'replace πβ€ with π€' once."
| Youtube | http://nmccoy.net/ldjam45.html |
| Original URL | https://ldjam.com/events/ludum-dare/45/emoji-dragon |
Ratings
| Given | 0π³οΈ | 0π¨οΈ |
The core of the game consists of a dictionary serving as the "emoji pool", tracking the count of each emoji in play, and a dictionary mapping emoji->the "rules" associated with the emoji. Each rule is structured as "event:operation", the operation usually being a substitution effect (indicated with β‘) but sometimes a shorthand (e.g., bare emoji without one of my specially handled "verb" emoji is a shorthand for "replace nothing with these"). Hovering over an emoji lists all the rules that could currently be executed if the appropriate event were triggered (or all the rules if hints are enabled); clicking on an emoji fires the π event on that emoji, executing all the π rules on it. π and π are the only events explicitly invoked by the Javascript framework, all others are triggered "in-engine" by the βΆ verb-emoji. When this happens, the framework iterates over all non-zero-count emoji in the pool and executes the appropriate rules on each of them, a number of times equal to the count for that emoji.
In terms of presentation, I set it up so that there's a couple divs in the page that "request" specific emojis from the pool in a given order using a data-value in their tag; the "render" function first checks for the requests made by the page, grabbing those emoji from a temporary copy of the pool and allocating them, then puts all the remaining non-requested emoji in the main centered div. (There were a lot of visual bugs in testing, like when I forgot to add π₯Ύ to the inventory requests so they hung around in the main pool div instead.) Usable buttons (those with at least one π event that could legally be executed) are given an extra class when being written to the html of the page, which the CSS then gives an eye-catching rainbow-animated background to.
Figuring out how to have the emoji game engine track if the player was in combat/had defeated all foes was tricky; I didn't implement a categorization system, so all the combatant emoji had to have a rule where they responded to an event to indicate that they were still alive, and a rule that removed them when the player fled combat. Halfway through development, I made a helper function that I could give a list of "these emoji are combatants" and it would append those two rules to the dictionary's rules for that emoji, saving me a lot of further repetitive emoji-typing. The β emoji signifies that the player is in combat; the β :β rule that the combatants all have means "when the β event fires, add a β emoji to the pool" as an indicator of "hey, I'm still alive". The defeat rule for each combatant looks like "π:π₯π₯π₯π¦β‘βββ" -- when clicked, trade 3 damage emojis and a shark for 2 experience points and a check mark, if such a trade is possible. The β has a π event that removes all β , fires the β event to ask if anyone's still around, makes a πΊ if there aren't any β in the pool after that, then replaces itself with nothing. In hindsight there may have been a cleaner way to do it, but I think that it's a good solution for not exposing too much unintelligible "system guts" to the player, since *all* of the game state is stored/represented by visible emoji! In the end, I was able to disguise most of the mechanical state as UI - unlike in most games where the health bar on the HUD is a visual depiction of the internal number that tracks the player's HP, in this game the health bar literally IS the player's HP! Kind of a wild concept, if you're used to the model/view/controller paradigm of game architecture; here the model and view are one and the same, and the controller mostly consists of things taped onto the modelview elements.