Charcoaled in the Oven: A Post-mortem of My GGJ-2022 Experience

This year is my 5th year participating in the Global Game Jam, and my 8th game jam. In the past, I was mostly a programmer, a sound designer once. This year, I am privileged to play as the game designer for our team, and nothing else. This is a moment where I can put my knowledge to the test, and I looked very forward to it.

But of course, our game didn’t bake — it died in the oven, or else I wouldn’t be here thinking on our journey in retrospect. As depressing as it may sound, this year has given me a lot of new insight regarding ideation, game design and production.

Well, let’s jump right in.

Continue reading Charcoaled in the Oven: A Post-mortem of My GGJ-2022 Experience

[TRANSLATION] “Arena of Valor” Engineer Exposes Questionable Lootbox Rate Mechanic

This is a translation of the original article:

I am a QA engineer of a certain game company. I’d like to share a dream I had the other day in which my friend, who is also an engineer at this company, told me a story. This is a dream! So any event described that happens in the real world is purely coincidental.

[The author attaches a snippet of modified code for proof]

Regarding an issue that everyone has been curious about — is every “Arena of Valor” (AoV) account’s lootbox rate different?

Short answer: Yes, every account has a different lootbox rate. But how could this have happened? This might not be what one would expect, so allow me to elaborate.

Spending Goal

Firstly, why do AoV accounts have different lootbox rates? This is because the company has set a series of “spending goals” for every account, and the first step to this is 1065 vouchers (the premium currency unit in the game). To achieve this first goal (every account has purchased 1065 vouchers), the company will try “all sorts of tricks” to lure players into spending real money. These tricks include “first-time purchases”, “bundles”, and many more.

BUT! Here’s where things get interesting. If you didn’t fall for these tricks and never achieved the spending goal, your lootbox rate will become 5x than it was. That’s right, 5x.

For example, if you wanted a certain hero skin, which would drops at a chance of 2.29%, then you would have a chance of 11.45% of getting it.

Now you must be thinking: doesn’t this mean I can just keep spending all my free vouchers while infinitely enjoying the benefit of the multiplier?

You wish. Game designers aren’t that stupid. Your 5x multiplier will be cancelled after you succeed until you buy 50 vouchers and spend them. The amount of vouchers required to purchase increases every time.

So, a general flow before achieving our first spending goal (T1):

Free -> 11.45% -> Succeeds -> 2.29% -> buys 50v -> 11.45% -> succeeds -> 2.29% -> buys 100v -> 11.45% -> succeeds -> 2.29% -> buys 150v -> 11.45%…..

If you’ve reached T1 (1065v) during this process, your 5x multiplier is cancelled.

But wait — if there’s T1, is there T2? T3? Or even further?

Yes. T2’s spending goal is 3375, T3’s 4440, T4’s 6490 and T5 is 9795. T6 and above do not exist. Furthermore, starting from T2, the multiplier is no longer the usual 5x. For T2, it’s 3.37x; T3’s 2.63 and T4 is 1.58. T5 has no multiplier — just plain 1x.

Last but not least, the system will reset your account’s charge history, but after that T1 is no longer 5x, but 4.16x.


Here I will attempt to answer two questions:

  1. Why do players that pay less always enjoy better luck than the big-spenders?
  2. Why are unlucky players always unlucky and lucky players always lucky?

Say for example, A is a big spender, and B is a player who only spends a little on the game. At the beginning of their account lives, A charges their account with a lot of vouchers and bought bundles and packs. They achieved T1, even T2, during this time, and therefore has lost their privilege to the 5x multiplier; Conversely, B still has access to it by spending extremely conservatively.

Now, suppose a no-guarantee (a high-quality item will be awarded after x tries) lootbox event has arrived. Having spent a lot already, A enjoys no multiplier and achieves T5 before hitting the jackbot; on the other hand, since B still has their 5x, B might get the ultimate prize before hitting T2.

After some time, another no-guarantee lootbox event has surfaced. Since A is already at T5, they must participate with a lower chance. B is still at T2, so he still enjoys a multiplier (albeit less than 5x).

Suppose that charge history has been reset during this period. A, as they always have been, manages to get the grand prize not before spending a lot and hitting T5. But B got their prize with a T2 multiplier before the reset; now they enjoy T1’s multiplier again and hits the jackbot by just getting to T2.

And so on, so forth, an infinite loop is formed — A continues to spend loads of cash into the game, with a lootbox rate worse than a small-spending player as B.

Question 2 is somewhat an end-effect of question 1. Since big spenders are essentially opening lootboxes with worse “luck”, they will naturally feel like they’ve been unlucky every time; Likewise, players that pay less are opening lootboxes with better “luck”, they will feel like they’ve been lucky every time.


English version



Continue reading 往返陰陽之間

Life Being Positive


This will be a post different from regular game design-related content. It’s merely a tale that spans over the course of a few weeks, but I hope anyone who’s reading this can find a little bit of inspiration, or even a little bit of hope and light into your life.

Also, this post is originally written in a mixture of English and Chinese. That’s just how I speak I guess.

Continue reading Life Being Positive

Implementing Swappable Key-Function Mapping in Unity

“MARS: Mayhem-Assured Rover Simulator” is a game I made in 48 hours for the GMTK Jam 2020. With this year’s theme being “Out of Control”, I decided to make a game that either makes players physically run out of fingers to control, or make controls a “limited resource” so that they eventually run out.

It didn’t take long for me to associate these features with a robot, and it was almost immediately apparent to me that I’m going to make a game about a “unfortunately poorly-designed” robot. Basically, the interaction are as follows:

  1. There should be enough functions for almost each finger.
    For example: movement / weapon controls / robotic arm / radar
  2. Each function should be intentionally separated from each other to make players busy.
    For example, movement can be separated into “gas”, “reverse”, “turn left” and “turn right”; weapon controls can be separated into “rotate cannon left”, “rotate cannon right”, and “fire”.
  3. All functions should be “hold” instead of “switch”.
    The robot arm only picks up/drops down items, but players have to hold down the key for the arm to keep the item in hand.
  4. Each key must expire after a number of uses.
    So that controls become a limited resource.
  5. Because of 4, keys to each function should be swappable.

So let’s get to some designing.

My terrible handwriting on an iPad

Figuring out the interactions

What we’re talking about here is a system in which “robustness” is a necessity. The game must react to different keys when they’re pressed; each key must function differently when assigned different features. Basically, the interaction map looks a bit like this:

No description available.

Many of the decisions that’ll be made in game are known only in run-time, which means excessive hard-wiring is not a good answer. So, we need to address this design task with flexible components.

Listening to 45 keys

In MARS, players can input using 26 + 19 keys (symbols mostly) on the keyboard. The rover itself has around 7-8 functions. Naturally, each key is a prefab, and each prefab should know what key it stands for. I could tackle this problem by including this script on every key prefab:

if Input.GetKey(KeyCode.A) {/*...*/}
else if Input.GetKey(KeyCode.B) {/*...*/}
else if Input.GetKye(KeyCode.C) {/*...*/}

But not only is this approach inefficient (and inelegant), statements in each brackets must perform another check on which function it is assigned to, and then call their corresponding methods. I sense a high probability of not abiding with reusable code, and I need to find another way.

Fortunately, Input.GetKeyDown() takes in not only KeyCode as arguments, but also strings. Using this, I can designate the key each prefab is representing with a public property, and use that with the Input.GetKeyDown() condition check.

Beware: using public in the beginning is a bad habit. Games written for game jams normally wouldn't encounter serious security concerns, but if you're writing for working projects, establishing a property with the public keyword is a bad idea.
[SerializeField] private string key;

private void Update()
    if(Input.GetKey(key)) {/*Do something!*/}

When each key is placed into a slot, it needs to know which exact method in the Controls Hub to call. A Listener pattern will probably suffice to implement this feature; additionally, Unity has their own Listener Event system out of the box, so I decided to take advantage of that.

I enjoy the moment when the “bridge is connected”; that is why I decided to set aside this task first, and work on completing the Controls Hub and the individual components first. The structure looks a bit like below:

public class ControlsHub
    public static ControlsHub Instance;
    [SerializeField] private MovementController movementControls;
    [SerializeField] private WeaponsController weaponsControls;
    /** Basically components of the rover **/

    private void Awake() { // implement singleton code here // }

    public void Gas()
    public void TurnLeft()
    /** Each component's individual methods **/

public enum RobotFunctions
public class MovementController
    /** This is where you set up individual parameters 
        for your component.
    [SerializeField] private Rigidbody rb;
    [SerializeField] private MaxSpeed;
    [SerializeField] private MaxAcceleration;

    private acceleration;
    private speed;

    private void FixedUpdate()
        speed = speed + acceleration;
        rb.MovePosition(rb.position + YOUR_FORWARD_VECTOR * speed * Time.fixedDeltaTime);

    public void Gas
        acceleration = MaxAcceleration;
    // so on so forth 

You may have noticed that the implementation of these methods don’t really work with how Input.GetKey() works — GetKey() is fired every frame the key is being pressed, but if that’s the case then the MovementController.Gas() method would be repeatedly called, resulting in a robot moving in impossible speeds.

This is because we need to consider other functions of the robot and how they operate as well. An immediate example would be the robotic arm that picks up items when the key is pressed down. It is not a continuous action like speeding up a car, but rather one with 2 states (pick/loose). While Input.GetKey() detects if a key is pressed down, but it doesn’t detect when a key is let go.

This is why we need to refactor our methods to work with the Input.GetKeyDown() / Input.GetKeyUp() pair, which leads to the eventual implementation of our key controller:

public class KeyController
    public string Key;
    private UnityEvent enterEvent;
    private UnityEvent exitEvent;

    private void Update()
        else if(Input.GetKeyUp(Key))
    // Invoked when key is placed in slot
    public SubscribeToComponent(RobotFunction component)
        switch (component)
            case RobotFunction.FORWARD:


So, how did we solve our problems?

  1. There should be enough functions for almost each finger.
  2. Each function should be intentionally separated from each other to make players busy.
    These design questions are achievable through our robust implementation.
  3. All functions should be “hold” instead of “switch”.
    We used Input.GetKeyDown() and Input.GetKeyUp() to achieve similar effects of Input.GetKey(). This implementation allows state-and-stateless functions to operate through the same interface.
  4. Each key must expire after a number of uses.
  5. Because of 4, keys to each function should be swappable.
    To achieve expirable keys, we just need to add in a few statements in KeyController that ignores input if the key has expired; for swappable keys, we avoided hard-wiring keys to each function through using the overload of Input.GetKeyDown().


You can play the game here!

Note: the implementation here is most likely not the optimal way; after all, it is a jam game!

This game jam has deeply educated me of my physical age — I’m 25. When I was 20, I could stay up all night and hack through the entire game without rest. Now I feel dizzy already at 1AM.

Moreover, I started this game alone, but it could never be completed without the help of Joey Yeo and her awesome pixel art. Thank you!

ETC 2020 Museum — Diving Deep Into A VR Graduation Event

Over the past few days I have been working on the ETC 2020 Museum, a Virtual World for my grad school’s (unofficial) virtual commencement. The world was built on the VRChat platform, and had a maximum attendance of around 32 people. Before we dive into the details, here’s a little digest video I made:

Looks pretty simple, but a lot of work has been done in the background to ensure a satisfying experience and technically optimal execution. Here’s a little write-up to detail these features.

Continue reading ETC 2020 Museum — Diving Deep Into A VR Graduation Event

Taking Bell Investments To the Next Level: Brainstorming Financial Products in Animal Crossing

First, there was a stalk market — a simple system that allows Animal Crossing players to benefit from buying and selling turnips. To put simply, it’s a form of investment;

Then, there is Warren Turnip, a Discord bot I wrote that helps me and my friends keep track of our selling prices every day so we can benefit the most from each other.

My Warren Turnip in action.

At perhaps the same time (even earlier), came, a website that lets everyone on the internet post about their islands and set queues for investors to wait in. It is a beautiful system!

Finally, someone was smart enough to make priority queues for those who joined their Discord servers…

Continue reading Taking Bell Investments To the Next Level: Brainstorming Financial Products in Animal Crossing

Camera Controls while Parachuting in Unity (Rotating Around a Sphere)


This article takes record of my attempt into creating a camera controllers suitable for free-looking when parachuting. A practical use of this controller is recreating the free-looking camera during the dropping phase in typical Battle Royale games. This controller takes the camera motions in Apex Legends as reference.

Continue reading Camera Controls while Parachuting in Unity (Rotating Around a Sphere)

Little Talks: Diablo, Dungeon-crawling and Open-world Design

When we look at Diablo, we don’t really see it as a game under the open-world genre. Rather, it is has its own genre (although scarcely defined on Wikipedia as dungeon-crawler). Why is that?

Note: While this article may reference other material, it mainly focuses on the Diablo series, and especially Diablo 3. Also, I’m just a casual player, so my experience with the game may largely differ from others.

Attempts and Obstacles

I want to start by attacking straight on point: the world.

The world is basically how the game’s levels are structured. Wikipedia crowns the world of Grand Theft Auto III as the prime example of modern open-world games. If we look at the game, plus a few other titles that are more often regarded as open-world games (such as Breath Of the Wild, Skyrim, Red Dead Redemption), we’ll easily notice that all these games share a common feat: it’s main level is a seamless map. I used the term “main” for players spend the majority of their time on it. Meanwhile Diablo, Path of Exile and other dungeon crawling games, the loading in between levels are simply obvious.

But seamless map design is not the criterion here, or at least it doesn’t stand as a deciding factor alone. I’d argue Super Mario 64 (and Odysssey) are open-world games; the key factor here, I think, is what exists in the “unimportant” areas. These areas can include space that has been visited already, or in a large open world, space that has absolutely no reason to visit (i.e. no quests) in order to finish the game. In Breath of the Wild, you visit different locations to get Korok seeds, which has been proven not required to save Hyrule; similarly, you don’t need to deliver pizzas to protect New York City in Spider-man 2. When compared to the main objective (saving Hyrule, protecting NYC), these content are additional and irrelevant to the main plot, but adds flavor and breadth to the experience.

I don’t think many people realize that the pizza meme song came from this video game.

If games are “voluntary attempts to overcome unnecessary obstacles“, then I argue that open-world games are collections of “voluntary attempts to overcome unnecessary obstacles and attractions“.

Looking back at Diablo and Path of Exile, one will immediately understand that these two games (and perhaps the genre itself) stands at the opposite end of the spectrum. In both of these games, each act is a series of maps of similar aesthetics and minions, and these maps all serve to convey a single plot, which translates into a single objective. When the plot in the area is completed, the game prompts you to move on to the next act, and there is no reason for you to revisit the area anymore. In other words, there are no attractions. While this allows writers to develop stories easier, it also results in a lot of the map’s potential to go into waste.

That being said, I must add that Path of Exile actually has unnecessary attractions, namely the Blight and Vaal Chambers. The blight is especially interesting since it adds an additional layer of tower-defender on top of the core dungeon-crawling gameplay.

Image result for poe blight
You must build towers that deal different types of damage to fend off enemies in the Blight in Path of Exile.

This also reminds me of one particular game: Sonic Adventure (1998). It features open areas where players can explore, but there’s hardly anything else that could be recognized as unnecessary attempts (except Chao Garden and Twinkle Circuit). It may have a large map, but I wouldn’t call it an open-world game.

「Chao garden sa1」的圖片搜尋結果
At the time of playing I was 4. I didn’t really care about chao(s) and I thought tossing them around was a fun thing. You can call this open-world; you can also call me a horrible person.

One may argue that players must travel around the city to gain certain key upgrades, such as the keystones to Windy Valley or the Light-speed Shoes upgrade (required to enter Casinopolis); while it is true that players have to traverse the map, they are all necessary effort as you need these items to proceed / clear the next stage. Once these items are obtained, most of the map goes to waste.

You will need the light-speed shoes to proceed to Casinopolis.

Now I must ask myself: how do I make a dungeon-crawling experience more open-world-like (pardon the word chains)? The problem here is that if we were to take out the world structure of Diablo, then it loses its signature; so, we must consider keeping the structure as a design restriction.

I wonder if any games can provide inspiration?

Daily Quests in MMOs: Reusing Space As An Additional Advantage

In my experience with open-world MMORPGs: Blade and Soul, Black Desert Online, World of Warcraft and such, daily quests are mainly tools to keep the players in the game, but they are also great opportunities for players to revisit areas.

Image result for blade and soul 殭屍 轉盤
In Blade and Soul, if you complete enough daily quests, you’ll have enough tokens to play this gigantic roulette, which grants you better gear or items.

The problem here is that daily quests feel pretty much the same, and can easily drain players’ interests. I like to play MMORPGs because I can explore the world and try out different subsystems in the game (like cooking and such), but I never bothered grinding on daily quests; that being said, I believe the success of such design largely depends on how the game (including maps, combat, encounters) are designed to handle daily quests, but that’s a branch of story for another time.

If Diablo decides to implement such quest system, I would consider it as a “direct approach” to add attractions to the playground.

NieR: Automata and Undertale: Reusing Space as Instrument of Narrative

The title pretty much says it all — both of these games re-use their levels to tell a different story. In NieR: Automata, you revisit the abandoned cities as you unravel the cruel fact behind humanity’s disappearance; in Undertale, you revisit the world with a different approach in order to navigate yourself into a different branch of story.

Image result for Undertale 999999
I’m just going to put this here. Go play the game.

This may sound interesting, but writing great stories just for the sake of using levels in a new way is unsustainable, especially for a live-service game. I would argue that if a team were to implement this strategy, they would need an infinite amount of Toby Fox’s to pull it off, for obvious reasons.

But what if the world in which Diablo takes place works in a particular way that requires players to find things?

The Flowering Nose in Slugland: Mechanisms That Maximizes Use of Maps

The Flowering Nose is a 2004 browser game by Seth Fisher and Omar Waly. It features a similar level layout to Diablo, especially the use of isometric projection.

The fun thing about this game, however, is how the world defines the process of going to another level: players must put an object on a receiver tile; the portal then opens a gateway to a corresponding level. This means that players will go to levels like “strawberry level” or “cake level”.

On we go to the Cherry Level!

If you fall down a hole, you don’t die — instead, you go to level hell.

Then, the story requires you to go to all these different levels, and figure out a way to open the locked door seen on the first level you enter. Here, the objective is clear, but the world itself is a huge attraction for players to explore and experience.

Image result for the flowering nose in slugland
The locked door presented to you at the beginning.

What if Diablo takes a similar approach?

I Am Legend: Diablo

Here’s an idea I think Diablo (or any other suitable game) can work on. This idea is first seen, by me, in a long-forgotten game called I Am Legend: Survival.

I Am Legend: Survival is a 2007 online multiplayer game hosted on Second Life, presumably used as a marketing boost for the actual movie. Players pick one of the two factions (humans and zombies). While the goal of the zombie faction is obvious — eliminate humans — humans must work through the entire city and find the ultimate cure.

What’s special about this cure is that it’s the combination of several unknown objects in the world. It can be anything. To validate the results, labs are established scarcely across the huge map, and zombies can temporarily take down these locations. The key point here is that players must travel the world, collect items, combine them, and validate the results to win the game. The world, again, is an attraction. Additionally, players had competed against each other to be the first to the cure, even if the game did not specify such rule.

In other and short words, this is a great competitive multiplayer idea that incorporates map usage and attractions. It is also a competitive multiplayer that requires more of the players’ uptime than their skills.

Here’s my imagination if Diablo III draws from this design (note that these are just concepts and thus doesn’t attempt to align with the Diablo Lore):

  1. Each season marks a new beginning of the hunt for a “key” — forged to open a door, which leads to victory.
  2. The recipe for the key is unknown, but a device is created to vaguely verify the results. Imagine Bulls and Cows, especially where the Bs only tell you that there is a correct number in the wrong position.
  3. Each player who decides to enter the game must pay a LOW entrance fee. This entrance fee builds up in the end and becomes the prize for whoever enters the door first.

Of course, this would possibly prompt for a total redesign of the item system in Diablo (in which the only items are equipment). Nevertheless, this may transform the Diablo game into a more open-world experience, without hurting the main game loop and story much.

Anyways, thanks for reading all this babble! Let me know what you think.

Trying to Design for Overwatch

I love Overwatch. I am fascinated by how took the role-playing shooting genre to the next level with so many different heroes and abilities to choose from; I’m also amazed by how they did so well in telling background stories of the roster with so little effort. In a role-playing competitive game, stories are clearly not the most important, but yet I find myself deeply invested into the universe.

As a game designer and a fan, I often think about the current state of Overwatch, and how to improve the experience and bring more fun to the players. So in January 2019, I’ve started a little project called “Notice me Papa Jeff”. I gathered a few of my friends, who are also game designers, and started brainstorming ideas on a new hero. We had a few meetings, and came up with a list of abilities that we’d like to mix-n-match.

Unfortunately, as we all attend the Entertainment Technology Center, our schedules were swiftly populated by project meetings, assignments and work deadlines, and so we had to put this project aside from our queues; nevertheless, I really liked what we were doing, and especially what I was doing: designing for a game that I love.

So I kept working on it as a side-project on my own, using all the spare time that I have; and now, as the basic have been established, I feel like it is a good time to open it up to the public and receive some feedback.

So here it is! Ranyatta, or, at least for now. 

From the name you could tell that the character is a derivative from Zenyatta. He is a support class, like his twin, but does not focus on healing or individual assists; he is focused on toppling teamfights and reversing the odds at clutch situations. Ranyatta is a hero that requires extensive knowledge and observations to play with, but is very rewarding for the whole team once his abilities are executed correctly.

You can read the document by clicking me! Let me know what you think.