lim jia sheng,

.Experiential Design

project[2]: Prototype


  • Create a prototype of the proposal



World to grid

This was the main algorithmic challenge brought up by Mr. Razif when discussing my proposal. My stubborn headass instead took it as a challenge. With game on, I took what I knew I could use for tokenisation from traditional compilers, & started my base — CardNode. Uniquely to Buddies’ One-of-a-kind Walking Language (BOWL), card tokens can actually appear in 2 dimensions. This means a simple doubly-linked node can't cut it — it's a job for the quadruply-linked node, linking top-bottom & left-right.

Actually constructing a grid from the nodes was the real meat of the challenge though. For this, after some silent thought, I came up with probably one of the worst algorithms for it. This is a simplified implementation:

  1. For each nodes as node
    1. For each edges as edge
      1. Let nearestDistance be Infinity
      2. Let nearestNode be None
      3. Let prevDistances be all the distances of the surrounding nodes to this one, before the node moved
      4. Move node locally towards the edge
      5. Let currDistances be all the distances of the surrounding nodes to this one, after the node moved
      6. For each [currDistances, prevDistances] as [currDistance, prevDistance]
        1. If currDistance is less than prevDistance & currDistance is less than nearestDistance
          1. Set nearestDistance to currDistance
          2. Set nearestNode to node that is currDistance away from node
      7. Link nearestNode at edge

The above implementation makes a few assumptions:
1. nearestNode will only ever appear once, & when linking, it's not present at other edges 2. The distance node moves locally is the minimum distance between every node
For the full implementation, see Assets/Core/Card/CardGrid.cs

It's kind of, so stupid, that it wraps around to being elegant!


After a lump of qudruply-linked card nodes, a proper data structure, more easily traversable, is required. Despite the heading, the card grid construction is definitely part of the overall tokenisation process... & I totally could've combined this with process with it. Whatever, I'm stupid, sue me.

Besides mapping over the card nodes' kinds into a jagged array, deduplication is also done if the tokeniser finds two of the same kinds stuck to each other, forming one card.

Yeah, that's a bug. If a player places two same top cards, the tokeniser will dedupe it into one card, & thus collapsing the two actions into one. Too bad, this a prototype & the repo is public, fix it yourself.


No ASTs or IRs, because that would be stupid for a card game; the tokens are all simply interpreted.

The interpretation itself is pretty straight forward as the cards map over to pretty simple logic in C# land. I used a few compiler-esque seeking functions here too like Eat & Until, not sure what they're supposed to be called thought, but I learnt them by combing through svelte's compiler. Why am I telling you this? Dunno.

There is one big thing of note here, which is the algorithm that detects when there is an infinite loop. The only reason the Turing Halting problem doesn't apply here is the simple assumption that if buddies' positions loop, they cannot ever reach the end. A simplified implementation of the algorithm can be described with a simple sentence — if the end of a set of sequential positions intersect with the start of the another set of sequential positions with the same combination, in a list of every single outputted position, then terminate. Elegant right?? Some little sh*t have probably written a whitepaper on this in the 60s, but I came up with it again alone in my bedroom, & I feel pretty proud of it.

Another notable implementation detail is also how parse errors are handled. They are thrown in the innards of the interpreter & caught from the public #Interpret* methods, which then bubble up to be displayed by whatever should handle it.



Every image target imported into Unity from the Vuforia database will have this TargetBehaviour component on it. It assigns them a kind & also propagates the events triggered by Vuforia into grid updates in TargetController.

Subset of targets in the project, 9/7/2022

Figure 1.1.1, Subset of targets in the project, 9/7/2022


The controller, implemented as TargetController is the central brain managing the targets. It keeps track of every target that is found & lost, updating the card grid as they change. A perpetual, per second tick is also fired from the controller to update the card grid.



The field holds the actual state of the level, & is the context object used by the interpreter. This includes the success states, events, & buddies positions.


The tiles shown in the game are programmatically generated based on pre-defined levels.

Level tiles, 9/7/2022

Figure 1.1.2, Level tiles, 9/7/2022


The main brain controlling the level, constructing the objects as the game Awakens, spawning toasts as the game Starts, centre the level tiles on the card grids as the game Updates. The main grunt of the logic its responsible lies in OnGridUpdate which is invoked, when the grid updates (duh). It tokenises the level field, & runs the interpreter on it, handling any errors with a floating toast, & successes with an animation (using my own Bezier & Tween implementation!) + toast.



The "First time user experience" (StrictPascalCase gang) houses the initial experience of a new player, with UIs that spawns each other using ReplaceSelfHook#ReplaceSelf().

FtueScene in Unity editor, 9/7/2022

Figure 1.1.3, FtueScene in Unity editor, 9/7/2022


The main scene with the AR shenanigans. It contains all the potential targets objects, a canvas for the help & the programmatically generated minimap, & as well as all the required dummy objects which housed the controllers & toast canvas.

MainScene in Unity editor, 9/7/2022

Figure 1.1.4, MainScene in Unity editor, 9/7/2022


Sxxov/walking-buddies, 9/7/2022

Figure 1.2.1, Sxxov/walking-buddies, 9/7/2022

Figure 1.2.2, Proposal video walkthrough, 6/7/2022


The experience overall was, pretty fun. Was not expecting things to be pleasant at all, but I guess both C# & Unity's API are battle-tested enough to facilitate dummies! As I proceeded through setting scenes up & scripting them out, whilst there were bumpy spurts of road & high hilltop terrain, the ratio of easy to hard is quite baffling; great productivity is facilitated.

The main things I learnt here was definitely the ability to utilise Unity to create game-like prototypes that functioned with AR. The AR concept whilst still quite foreign & abstracted away via Vuforia, really does open up doors to potential new ways of game design & creation. I also learnt how much I surprisingly liked C#. Whilst it is very unfortunate Unity's runtime lags behind the bleeding edge of C# language features, like multiline strings & perhaps even the required keyword, it still provides a broad set of language features that put Java to pure-OOP shame.

At the end of the day, I know whatever I've learnt from this project will be used by me the future for game prototypes & even jams or jellies. Again, was a very challenging & taxing experience, but not one I would prefer to be without.