Pride and Accomplishment
Introduction
The gaming industry is one of constant evolution. Looking at what was available to us 20 years ago and comparing that to what we have now is proof enough of how fast things move in the gaming sphere. Alongside the evolution of the games themselves, the monetization of these games has also changed a lot. In recent years, a newer tactic known as microtransactions took the industry by storm. As the name implies, microtransactions involve spending smaller amounts of money, typically under $10, to get something within a video game. The types of microtransactions vary based on the game, from “skins” to boosts, to the main topic of today: loot boxes.
Loot boxes are like reward packages that give you random items. They were first popularized in the Blizzard arena shooter game Overwatch released in 2016 where they rewarded players with cosmetic items. These loot boxes could be earned through gameplay, but they could also be bought with real-world money. These loot boxes were met with mixed reception, especially since they were in a game that already costs $60. Despite that, the financial success of the system led to it being adopted across the industry in various titles. As time went on, developers and publishers found more and more ways to get money out of their players using these loot boxes. Games like Call of Duty adopted a system where you could get new guns from loot boxes that had exceptionally low drop rates. First introduced in Black Ops III, there were reports of players spending tens of thousands of dollars on these loot boxes just to get all the guns. As someone who played this game myself when I was younger, it was pretty much impossible to get one of these weapons unless you spent money on the boxes, even though you could earn them in-game. This is where loot boxes began to cross the line from questionable inclusions to borderline predatory.
Another infamous example comes from the FIFA and Madden series of games from publisher Electronic Arts. In these games, you can obtain card packs that have various players from the FIFA and NFL sports leagues respectively. There are horror stories of people spending millions of dollars year after year to create the best team they can. What makes these systems even more egregious is that not only are paying players at a huge advantage, creating a pay-to-win economy around the product, but these loot boxes are also advertised to children. Research has shown that presenting children with an opportunity to gamble creates within them an unnaturally high likelihood that they will develop a gambling addiction in adulthood. While children do not make up the vast majority of the income of these microtransactions, they do make up the largest proportion of players by a good mile, and there is evidence that some players of these games can grow up to be “whales” who throw an unhealthy amount of money at these games, often at the detriment of the rest of their finances.
Pride and Accomplishment
“The intent is to provide players with a sense of pride and accomplishment for unlocking different heroes.”
— u/EACommunityTeam on Reddit
The quote above is an infamous statement from an EA community manager on Reddit regarding the microtransactions seen in the game Star Wars Battlefront II (2017). In the game, unlocking fan-favorite characters like Darth Vadar used to take up to 40 hours to unlock, even if you bought the deluxe edition of the game for $80. This prompted users on Reddit to comment on this outrageous system that was built purely to drive sales towards the premium currency featured in the game. This response by EA ended up becoming the most downvoted post in Reddit history with over 650k downvotes. The phrase “pride and accomplishment” has become sort of a satirical rallying cry for people against the idea of over-monetization in video games, and it works as a perfect title for what I have made: a video game about loot boxes.
Pride and Accomplishment focuses on re-creating the loot box experience in a sandboxed environment. Players do what they do best and open the chest for prizes, except in this game, the prizes are a little different. What you get will be accurate to the real-world loot box experience: vapid rewards that are not worth the price of admission.
The Process
The engine I chose to create this game in was Unity. Unity is a very versatile engine that allows you to build and run games quickly on a variety of platforms. Unity uses the C# coding language for most of what a game requires, so that is the language I adopted as well. I used Microsoft Visual Studio 2019 as my IDE (integrated development environment) where I wrote most of the code for this game. Photoshop was used to make some of the 2D assets like the background and textures. I also needed to make some 3D models for the project, and since I was going for a very simple style, I decided to use the program Blockbench, which is actually a 3D modeling software created for making models for Minecraft mods and animations, however, I took advantage of its OBJ export feature to port these models over to Unity with no real issue. All these tools were used on the Windows 11 operating system.
The first order of business was to create a working prototype of the game. I did this by setting up a simple scene in Unity that only had the background and some text boxes. I then began to write some code that will allow for basic functionality like selecting a random item from a list and writing its name to the text box. Once I got that working, I began to make all the necessary models in Blockbench and texture them in Photoshop. I then wrote more complex logic for the chest opening process and created some animations within Unity to make the whole process more presentable. From here on out it was just about fixing bugs and trying to add as many items as I could before the deadline. Below is one of the final iterations of the code for the game. This file, in particular, handles the main logic of the project.
GameManager.cs, just one of the files I wrote for the games
1using System.Collections;
2using System.Collections.Generic;
3using UnityEngine;
4using UnityEngine.UI;
5
6// This class creates the new "Item" data type used for item info
7public class Item
8{
9 public int ItemID;
10 public string Name;
11 public string Description;
12 public double Value;
13 public GameObject ItemPrefab;
14}
15
16public class GameManager : MonoBehaviour
17{
18 // Script References
19 UIManager UI;
20 ButtonInteractions BI;
21
22 // Object References
23 [SerializeField] GameObject chestPrefab; // The chest object
24 Animator currentChestAnimator;
25 GameObject currentChest;
26 [SerializeField] Text accountValueText;
27 [SerializeField] GameObject resultTextParent;
28
29 // Global & File-Wide Variables
30 bool chestSummonAllowed = true;
31 bool chestOpenAllowed = false;
32 double chestOpenPrice = 5.00; // Cost of opening a loot box
33 int randomItemID;
34 GameObject lastItem = null;
35 bool buttonClicked = false;
36
37 public int accountValue = 1000; // Total value of the player's account
38 public int currentItemID;
39 public string currentItemName;
40 public string currentItemDesc;
41 public double currentItemValue;
42 public GameObject currentItemPrefab;
43
44 // Item Prefabs
45 List<Item> itemDetails;
46
47 [SerializeField] GameObject itemZeroPrefab;
48 [SerializeField] GameObject itemOnePrefab;
49 [SerializeField] GameObject itemTwoPrefab;
50 [SerializeField] GameObject itemThreePrefab;
51 [SerializeField] GameObject itemFourPrefab;
52 [SerializeField] GameObject itemFivePrefab;
53 [SerializeField] GameObject itemSixPrefab;
54
55 // Start is called before the first frame update
56 void Start()
57 {
58 // Script Connections
59 UI = GameObject.Find("Canvas").GetComponent<UIManager>();
60 BI = gameObject.GetComponent<ButtonInteractions>();
61
62 // PlayerPerf Retrievals
63 accountValue = PlayerPrefs.GetInt("Account Value", 1000);
64
65 // Item List and Details
66 itemDetails = new List<Item> { new Item { ItemID = 0, Name = "Absolutely Nothing", Description = "...", Value = 0.00, ItemPrefab = itemZeroPrefab },
67 new Item { ItemID = 1, Name = "A Single White Pixel", Description = "Technically not nothing...", Value = 0.01, ItemPrefab = itemOnePrefab },
68 new Item { ItemID = 2, Name = "Pride and Accomplishment", Description = "No no no, you see, it's not gambling, it's fun!", Value = 1.00, ItemPrefab = itemTwoPrefab },
69 new Item { ItemID = 3, Name = "Hot Air", Description = "Our speciality", Value = 0.01, ItemPrefab = itemThreePrefab },
70 new Item { ItemID = 4, Name = "Legally-Distinct Diamond Sword", Description = "This would be useful for slaying monsters...if there were any in this game", Value = 5.00, ItemPrefab = itemFourPrefab },
71 new Item { ItemID = 5, Name = "A Post-Ironic Meme", Description = "We do a little trollng", Value = 1.00, ItemPrefab = itemFivePrefab },
72 new Item { ItemID = 6, Name = "A Mini Loot Box", Description = "Now that's meta", Value = 2.50, ItemPrefab = itemSixPrefab },
73 };
74 }
75
76 // Update is called once per frame
77 void Update()
78 {
79 // Adjacent Functions
80 SummonChest();
81 UIUpdates();
82 }
83
84 void SummonChest() // This function controls the spawning and destruction of the chest and its associated animations
85 {
86 // Local Declarations
87 IEnumerator coroutine;
88
89 Animation chestOpenAnimation;
90
91 /* ONLY ENABLE AFTER IMPLEMENTING ALL ITEMS //
92 int numberOfItems = itemDetails.Count();
93 randomItemID = Random.Range(0, numberOfItems);*/
94
95 randomItemID = Random.Range(0, 5); // DELETE AFTER IMPLEMENTING ALL ITEMS //
96
97 currentItemID = itemDetails[randomItemID].ItemID;
98 currentItemName = itemDetails[currentItemID].Name;
99 currentItemDesc = itemDetails[currentItemID].Description;
100 currentItemValue = itemDetails[currentItemID].Value;
101 currentItemPrefab = itemDetails[currentItemID].ItemPrefab;
102
103 // Spawn and Animation Control
104 if (Input.GetKeyUp(KeyCode.Mouse0) || Input.GetKeyUp(KeyCode.Space))
105 {
106 if (chestSummonAllowed && buttonClicked == true && accountValue >= chestOpenPrice) // Press left mouse or spacebar
107 {
108 // DEBUG //
109 Debug.Log("Chest spawn successful");
110
111 chestSummonAllowed = false;
112 buttonClicked = false;
113
114 Destroy(lastItem);
115 resultTextParent.SetActive(false);
116
117 currentChest = Instantiate(chestPrefab, new Vector3(13, -2.43f, -3), Quaternion.Euler(0, 90, -10)); // Spawns Chest out of bound to the left
118
119 PlayerPrefs.SetInt("Account Value", accountValue); // Write accountValue to PlayerPref key
120
121 currentChestAnimator = currentChest.GetComponent<Animator>();
122 currentChestAnimator.SetTrigger("slideInTrigger");
123
124 coroutine = ChestInteractionCooldown("PreventEarlyOpen");
125 StartCoroutine(coroutine);
126 }
127 else if (chestOpenAllowed && currentChest != null)
128 {
129 // DEBUG //
130 Debug.Log("Chest opened successfully");
131
132 chestOpenAnimation = currentChest.GetComponent<Animation>();
133 chestOpenAnimation.Play("ChestAnim");
134
135 chestOpenAllowed = false;
136 currentChest = null;
137
138 coroutine = ChestInteractionCooldown("DelayChestDestruction");
139 StartCoroutine(coroutine);
140 }
141 else if (chestSummonAllowed && buttonClicked == true && accountValue < chestOpenPrice)
142 {
143 accountValueText.text = "Congrats, you're bankrupt!";
144 }
145 else
146 {
147 Debug.LogWarning("SummonChest() didn't run any Spawn and Animation Control function. Is the cooldown active?");
148 }
149 }
150
151 // Interaction Cooldowns
152 IEnumerator ChestInteractionCooldown(string goal)
153 {
154 if(goal == "PreventEarlyOpen")
155 {
156 yield return new WaitForSeconds(2);
157 chestOpenAllowed = true;
158 }
159 else if (goal == "DelayChestDestruction")
160 {
161 yield return new WaitForSeconds(3);
162 currentChestAnimator.SetTrigger("slideOutTrigger");
163 lastItem = Instantiate(currentItemPrefab);
164 UI.UpdateItemText(currentItemID);
165 resultTextParent.SetActive(true);
166
167 yield return new WaitForSeconds(4);
168 chestSummonAllowed = true;
169 currentChestAnimator = null;
170 Destroy(currentChest);
171 BI.openChestButton.SetActive(true);
172
173 // DEBUG //
174 Debug.Log("Chest destroyed!");
175 }
176
177 }
178 }
179
180 void UIUpdates()
181 {
182 accountValueText.text = "$" + string.Format("{0:n0}", accountValue);
183 }
184
185 public void ButtonClicked()
186 {
187 buttonClicked = true;
188 }
189}
Reception
After creating an acceptable build of the game, I shared the product with some of my peers, friends, and family. Below are just some of their reactions to what they played:
“Truly an unrivaled cinematic masterpiece.”
— Kevin G., a Miami University Junior
“This is definitely something only you would make.”
— My girlfriend, an Ohio Wesleyan University Sophomore
“What the heck is a loot box?”
— My mother
Just like a trailer looking at a low-quality game journalism site, I have cherry-picked the best quotes. On a more serious note, I had conversations with all of the seven people I had play this game. These people all had different perspectives on the gaming industry. People like Kevin are hardcore gamers and play games every day. He is pretty acutely aware of the nuances of the industry and the problems it has. Then there are people like Chloe, who are casual gamers and are only partially aware of thing things affecting the industry. And finally, there are people like my mother, who have absolutely no clue what is going on in that sphere at all. These diverse perspectives give a lot of insight into the general reception of monetization methods like loot boxes.
The general consensus amongst the players was that my game sucked. In my eyes, I consider that a win. I asked each player why they thought that game wasn't fun, and it mostly came down to one thing: loot boxes do not improve (or create) worthwhile experiences for a player. Talking further, I wondered how this game changed the perspective of loot boxes in general for the players. While it didn't leave much of an impact on the less experienced players, people already familiar with the industry noted how it gave them a new perspective on the absurdity of loot boxes. I pointed out how games like Overwatch, Call of Duty, Battlefront, and more have already tied big chunks of their progression systems in with loot boxes, creating little micro-games like mine within them, all while you still have to spend $60 on the base game. Needless to say, they did not appreciate that idea. Unfortunately, that is the reality we live in.
Conclusion
Reflecting back on this project, it was pretty tough. I only had about two-and-a-half weeks to finish up the game itself to have enough time to get people's reactions in a timely manner. There was more I would've liked to do with the game, namely adding more items and creating more interesting systems that really drive the point I'm trying to make home, but unfortunately, those got left on the cutting room floor. However, I still think my game was able to make a compelling argument as to how silly it is that loot boxes have prevailed in the gaming industry as much as they have. No longer does paying for something mean you'll actually receive anything of note, but rather something small and ultimitely meaningless to your enjoyment (and likely something you didn't want at all).
The gaming industry is going in an interesting direction. Now more than ever it seems that the creativity of countless developers is being sacrificed for the sake of profit. Loot boxes are something that actively hurt the quality of the games they're included in, and as someone who desires to pursue a career in the industry, it is a little disheartening seeing the medium turn into a cash cow for multi-billion dollar companies. I hope that one day people can see what things like loot boxes are doing to the quality of the game they play and the harmful effects they can potentially have on some players.
Download
Pride and Accomplishment is free and available to anyone using a browser. The online version is powered by WebGL and thus must be run on an actual computer (not a phone).