project[2]
0344034.
BDCM
.Experiential Design
::project[2]
project[2]: Prototype
todo:
- Create a prototype of the proposal
implementation:
Interpreter
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:
- For each
nodes
asnode
- For each
edges
asedge
- Let
nearestDistance
be Infinity - Let
nearestNode
be None - Let
prevDistances
be all the distances of the surrounding nodes to this one, before thenode
moved - Move
node
locally towards theedge
- Let
currDistances
be all the distances of the surrounding nodes to this one, after thenode
moved - For each [
currDistances
,prevDistances
] as [currDistance
,prevDistance
]- If
currDistance
is less thanprevDistance
&currDistance
is less thannearestDistance
- Set
nearestDistance
tocurrDistance
- Set
nearestNode
to node that iscurrDistance
away fromnode
- Set
- If
- Link
nearestNode
atedge
- Let
- For each
NOTE
The above implementation makes a few assumptions:
1.nearestNode
will only ever appear once, & when linking, it's not present at otheredge
s 2. The distancenode
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!
Tokenisation
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.
TODO
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.
Interpreting
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.
Targets
Behaviour
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
.
Controller
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.
Level
Field
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.
Tiles
The tiles shown in the game are programmatically generated based on pre-defined levels.
Controller
The main brain controlling the level, constructing the objects as the game Awake
ns, spawning toasts as the game Start
s, centre the level tiles on the card grids as the game Update
s. 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.
Scenes
FtueScene
The "First time user experience" (StrictPascalCase gang) houses the initial experience of a new player, with UIs that spawns each other using ReplaceSelfHook#ReplaceSelf()
.
MainScene
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.
final:
reflection:
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.
Comments