17 July 2025

Live-videogames and the risk of power creep

The internet has radically changed the world of video game development, moving away from the days when promotion relied on articles in specialized magazines that offered demo discs. Thanks to the hyperconnectivity we now have at home, access to games has become immediate, and we are constantly bombarded with announcements of new releases. For players, the challenge is no longer finding out what games are coming out, but choosing the ones they might enjoy most from an almost infinite universe of possibilities. For developers, the challenge remains reaching the player—not due to a lack of means to do so, but because of how difficult it is to stand out in a saturated market.

In such an ecosystem, many development studios prefer not to release new games continuously, but instead focus on a single title and evolve it over time, gradually gaining new players and retaining them for years. The idea is that by concentrating efforts on one game over an extended period, there’s a better chance of standing out among the competition and gaining notoriety. This evolution is usually driven by exhaustive telemetry analysis of players, allowing developers to understand how users interact with the game, which parts they enjoy most, which ones less, and what they feel is missing. With this data, developers can pivot the game toward the changing tastes of their audience, attracting new players and retaining existing ones. Often, this process of evolution leads to the game becoming unrecognizable compared to its original version.

This type of game is known as a live-game, a term mainly used in the context of video games to refer to a title that receives continuous updates, new content, and active support from developers after its release. Also known as Game as a Service (GaaS), it is characterized by maintaining a dynamic and evolving experience for players, fostering an active community over time.

Fortnite is one of the clearest examples of current live-games.
Fortnite is one of the clearest examples of current live-games.


The Business Model

This continuity of service requires maintaining servers from which the game operates and user telemetry is collected, having a team of developers who continue updating the game with new content and mechanics, as well as running constant marketing campaigns to attract new players. Therefore, these games require ongoing investment that is not sustainable with the classic model of monetizing the game through an initial sale to the player. With these games, developers must turn to continuous monetization models.

The most classic of these is the subscription model, in which Blizzard’s World of Warcraft was a pioneering title that still endures. The problem with subscriptions is that the recurring expense they entail can be a financial or psychological barrier to entry for new players—either because they cannot afford the cost or because they are unsure whether they will play the game enough to make it worthwhile.

World of Warcraft was the pioneer
World of Warcraft was the pioneer

Other development studios prefer to remove that barrier to entry by making the game completely free, with no acquisition costs or subscriptions. In these cases, monetization may come from the sale of large optional content packs, in the form of DLCs, or from much smaller content offerings, also at a reduced cost… and this brings us to microtransactions.

Microtransactions are small purchases within a video game (or app) that allow players to acquire additional digital content using real money. They are usually optional and are intended to enhance the gaming experience. Their cost is low, generally ranging from a few cents to a few euros per transaction. The most common examples of content offered through microtransactions include:

  • Cosmetic changes to the base game: skins, outfits, or visual customizations for weapons (e.g., skins in Fortnite).
  • Gameplay advantages: items that facilitate progress, such as boosters or resources (e.g., gems in Clash of Clans).
  • Additional content: extra levels, characters, or storylines.

The Business Model

For developers, microtransactions pose much less risk than DLCs. With a DLC, a lot of content must be developed, and if it fails, the losses can be significant. Microtransactions are much more granular; being so small, their cost is low and so is the risk. Combined with good telemetry that tracks their reception among players, several failed microtransactions can be used to fine-tune what users like, and from there, generate many others that hit the mark of what they want to buy. It’s much easier to reach a positive cash flow if you have a competent analytics team and creative developers and artists.

Criticism

For players, microtransactions have the appeal of being low-cost indulgences. They are “treats” that are easy to purchase because at first glance their cost seems negligible, although over time the accumulated expense can be significant. This ease of spending has led many to accuse microtransactions of fostering addiction. These accusations were especially intense with loot boxes—microtransactions where players pay (with real money or in-game currency) to obtain a virtual box containing random rewards. These rewards may include cosmetic items, characters, weapons, boosters, or other elements, but the exact content is unknown until the box is opened, introducing an element of chance similar to gambling. That similarity has led some countries (such as Belgium and the Netherlands) to restrict or ban loot boxes by classifying them as gambling. Others require that the odds of obtaining certain items be published. Ultimately, due to criticism, many developers have reduced the use of loot boxes or opted for more transparent systems, such as battle passes or direct stores where players buy exactly what they want. Some games, like Rocket League, removed loot boxes after initially including them. Another notable case is Star Wars Battlefront II (2017), where loot boxes sparked major controversy due to their impact on gameplay. This led EA to modify them after massive backlash, even though the entire monetization model revolved around them, and their removal marked the end of the game’s economic appeal for its publisher.

Loot boxes

Addiction is not the only criticism microtransactions receive. Another frequent one is that, by giving unfair advantages to those who spend more, they reduce the game to a pay-to-win model that frustrates players unwilling to spend at the same level. Pay-to-win can even deter those who could afford microtransactions, as they may lose interest in a gaming experience where money outweighs skill.

The Risk of Power Creep

Another danger of microtransactions is what is known as power creep. When a game uses microtransactions as its monetization model, it must continuously release new content—and make it more appealing than the previous one—so that players keep buying the new items instead of settling for what they already have. So far, this is standard practice, but there’s a risk that this dynamic can turn into a vicious cycle that may end up harming the game, both from the developers’ and the players’ perspectives.

Power creep refers to the phenomenon in which developers introduce new content (characters, weapons, abilities, etc.) that is significantly more powerful than previous content, rendering older elements obsolete or less competitive. Therefore, it mainly affects microtransactions that offer gameplay advantages.

When power creep continues over time, it can introduce serious issues into the game. The most notable are:

  • Impact on the game’s reputation: In competitive multiplayer games, where players who don’t spend money face clear disadvantages, the game may end up being labeled as pay-to-win.
  • Impact on gameplay mechanics: New characters, weapons, or items often have superior stats, abilities, or effects compared to existing ones, disrupting the game’s balance. Over time, this “arms race” can evolve the gameplay mechanics to the point where they no longer resemble the original design—and likely not for the better.
  • Impact on development: It’s very difficult to sustain a development cycle where each new iteration must introduce more powerful advantages without ruining the fun of the core gameplay.
  • Impact on players: The obsolescence of older content means that players who used previous items or characters may feel at a disadvantage, as these become less effective over time. Those who invested time or money in older content may feel their effort was wasted. This can lead to player dissatisfaction and eventual abandonment of the game.


Power Creep in Pokémon Cards


Power creep outside of video games

In reality, power creep isn’t exclusive to live-games. If we think back, we can find similar examples in the world of television series. If you reflect on the ones you’ve watched, you’ll notice that many follow a “defeat-the-villain-of-the-season” structure. To maintain interest, these villains become increasingly powerful, making the situations more dramatic and extreme. However, this approach isn’t sustainable. As the seasons go on, the villains from earlier ones start to seem irrelevant compared to those in the later ones. On the other hand, the escalating drama needed to defeat such powerful enemies can eventually tip into the ridiculous and unbelievable.

There are many examples of series that have suffered from this phenomenon, but perhaps one of the most obvious is Dragon Ball. Fans of Akira Toriyama will remember how the series began as a cheerful and mischievous tale, with a child protagonist and fights limited to martial arts. Over time, the "Kamehameha" technique (or "Kame Hame Ha," depending on the translation of the series you watched) appears as a legendary and ultimate energy blast.

Dragon Ball in the beginning
Dragon Ball in the beginning

But since the series didn’t stop there, neither did the combat techniques or the enemies. As the series progressed, the enemies became stronger, and it was no longer enough to just punch them to win. The “Kamehameha” (or “Kame Hame Ha,” depending on the translation you watched) became insufficient, so the protagonists grew up, learned to fly, and launched new types of energy blasts (Wikipedia identifies up to 18 different versions of the Kamehameha, each increasingly powerful). With such a display of power, the fights became so over-the-top that a single misplaced blow could split a planet in two. By this point, the series had lost its original joy and vitality, and had been reduced to a long succession of increasingly powerful villains. That’s when I lost interest and disconnected from the series, although I know it continued for a long time with numerous spin-offs.

Dragon Ball, already a victim of power creep
Dragon Ball, already a victim of power creep

Possible Solutions to Power Creep

This issue, which has long affected TV series, can also impact live-games, potentially undermining them to the point of collapse. Avoiding or mitigating power creep requires developers to design strategies that balance gameplay mechanics and maintain a fair, enjoyable, and sustainable experience over time. Common approaches include:

  • Focusing microtransactions on cosmetic content: Since these are purely visual changes (like skins or visual effects), they don’t affect gameplay mechanics, preserving balance. A good example is Fortnite, which centers most of its microtransactions on skins and emotes, ensuring that player power doesn’t depend on purchases. This reduces pressure to spend and keeps functional power creep minimal.
  • Designing lateral content (sidegrading) instead of direct upgrades: Rather than introducing new elements (characters, weapons, abilities) that are strictly more powerful, developers create content with different but balanced characteristics, offering new ways to play without surpassing existing content. For instance, in Overwatch, new heroes are designed with unique abilities that aren’t necessarily stronger, but provide different playstyles. This minimizes the obsolescence of older content, as choices are based on preference or strategy, not raw power.
  • Regular balance adjustments (buffs and nerfs): Developers monitor the game’s meta and adjust stats or abilities of both new and old elements to maintain competitive balance. For example, in League of Legends, regular patches tweak champions to prevent new ones from dominating, strengthening underused ones (buffs) or weakening overpowered ones (nerfs). This keeps older content relevant and prevents new content from becoming overwhelmingly superior.
  • Limiting the impact of progression: This involves designing the game so that power upgrades have limited impact or are restricted to certain modes (like PvE instead of PvP). In Destiny 2, new gear may be stronger, but competitive modes often have power caps to level the playing field. This reduces the perception of pay-to-win and maintains fairness in competitive environments.
  • Implementing rotation systems or shifting metas: This strategy introduces changes to game rules, modes, or events that alter which elements are most effective, without necessarily making them more powerful. For example, in Hearthstone, card rotation between standard and wild formats ensures that older cards don’t directly compete with new ones, helping control power creep.
  • Reusing and improving old content: This involves updating older characters, weapons, or items to keep them relevant, rather than replacing them with stronger new content. World of Warcraft follows this approach by modifying older classes to ensure they remain viable in new expansions. This helps players feel that their investment in older content retains its value.

Solutions to the Problem


Conclusion

In my opinion, the simplest approach is the one followed by Fortnite: limiting itself to selling cosmetic content. Since it doesn’t affect gameplay, it doesn’t require ongoing analysis and content review over time. However, it’s also true that Fortnite’s gameplay mechanics are so simple, and its scenographic framework so flat, that it can afford the wild heterogeneity of characters featured in its battles (which often feel like a scene from Ready Player One).

However, other games based on worlds with a much more defined setting—such as World of Warcraft or Star Wars—probably don’t have as much leeway to offer visual heterogeneity without descending into an aesthetic delirium that breaks the immersion of the world they aim to create.

It’s therefore a matter of studying our game and determining how far we can go with each of the strategies mentioned above. The solution doesn’t have to rely on just one strategy; we can opt for mixed approaches. The weight we assign to each strategy in our final blend will depend on the narrative framework of our game, our availability of creatives to produce visual content, and of analysts and programmers to review and adjust content that could affect gameplay mechanics.

13 July 2025

Using Timers in Unity and Godot


Timers in video game development are tools or mechanisms that allow measuring and controlling time within the game. They are used to manage events, actions, or behaviors that depend on time, whether in real-time or in game update cycles (frames).

They are a fundamental tool for controlling temporal logic in video games, from basic mechanics to complex systems, and are therefore essential in many aspects of game design and development.

There are many uses and cases for timers. Here are some of the most notable examples:

  • Control of timed events: For example, executing actions after a specific time, such as triggering an animation, spawning enemies, or displaying a message on screen.
  • Time-based game mechanics: For instance, implementing time limits to complete a mission, solve a puzzle, or survive a wave of enemies.
  • Synchronization of animations and effects: To coordinate animations to occur at the right moment, such as explosions, transitions, or visual effects.
  • Cooldown management: To control the cooldown time of abilities, special attacks, weapon reloads, or player actions.
  • System update frequency: To regulate how often certain systems (like enemy AI or item generation) update to optimize performance.
  • Cyclic or repetitive events: To create patterns that repeat at regular intervals, such as enemy waves, weather changes, or day/night cycles.
  • Multiplayer synchronization: Used to ensure that events in multiplayer games are synchronized across all clients, such as match start or state updates.
  • Delay or wait effects: Introduce intentional pauses to improve gameplay or narrative, such as waiting before showing dialogue or triggering an event.

Based on the above, we can distinguish the following types of timers:

  • Game-time based: Progresses at the same rate as game time. For example, if the game is slowed down (e.g., bullet time), the timer slows down accordingly.
  • Real-time based: Uses the system clock and progresses uniformly regardless of game time speed.
  • Countdown: Starts with a value and decreases to zero, triggering an event when finished.
  • Cyclic timers: Automatically restart for repetitive events, like automatic shooting or health regeneration.

General Implementation

All engines offer a function that executes periodically. Unreal calls it Tick(), Unity uses Update(), and Godot C# uses _Process(). These functions usually receive a value called deltaTime, which is the time elapsed since the last call.

Assuming we call this function Update(), we could use it to create a timer with the following pseudocode:

Pseudocode to implement a timer
Pseudocode to implement a timer

Many engines offer two versions of this periodic function: one that runs when a new frame is rendered (idle frame), and another that runs at fixed time intervals (physics frame). The latter is better for implementing timers, as graphics cards do not render frames at a constant rate.

Implementation in Godot

Following its "a node for each task" philosophy, Godot has a specialized timer node called Timer. This node is ideal for using timers without implementing them from scratch.

The node offers the following configuration fields:

Timer node fields
Timer node fields

  • Process Callback: Defines whether the timer progresses with idle frames or physics frames.
  • Wait Time: Duration of the timer in seconds.
  • One Shot: If checked, the timer runs once and stops. Otherwise, it restarts automatically.
  • AutoStart: If checked, the timer starts when added to the scene tree. Otherwise, it must be started manually.
  • Ignore Time Scale: If checked, the timer uses real time; otherwise, it uses game time.

The node emits the timeout() signal when the timer reaches the set Wait Time.

timeout signal
timeout signal

By configuring the Timer node in the inspector and connecting its timeout() signal to a method, most use cases are covered.

This node can also be manipulated from code. Let’s look at an example of how to use it. Imagine we want to program a cooldown, such that once a certain method is executed, it cannot be executed again until the timer has finished. Let’s suppose this method is called GetSteering() and it’s called from the _Process() method of another node.

To start the cooldown, we could call an activation function right at the end of the GetSteering() method.

Example of starting a cooldown
Example of starting a cooldown

The cooldown activation function is called StartAvoidanceTimer() in this case, and it simply starts the Timer node’s countdown and sets a flag to true:

Implementation of the cooldown start method
Implementation of the cooldown start method

If a Timer does not have the AutoStart field enabled, we’ll need to call its Start() method for it to work, as seen on line 235.

The flag set to true on line 236 can be used as a guard at the beginning of the method we want to limit execution of.

Using the flag as a guard to control whether the method executes
Using the flag as a guard to control whether the method executes

The example in the screenshot might be a bit convoluted if you’re not familiar with the development context in which the method is used, but it essentially works by calculating a path to a target (line 157). If there’s no other agent we might collide with, and no timer is active, the calculated path is followed (line 160). If, on the other hand, a timer is running, the agent continues along the escape route calculated in the previous call to GetSteering() (line 162). The method is only fully executed if a potential collision is detected and no timer is active, in which case it continues calculating an escape route to avoid the collision (from line 164 onward).

Without a cooldown, my agent would detect a possible collision ahead, calculate an escape route, and turn to avoid the collision. The problem is that in the next frame, the obstacle would no longer be in front of it, so it would see the shortest path to its target and turn to face it again, ending up right back in front of the obstacle we were trying to avoid. This cycle would repeat. To prevent this, an escape route is calculated and followed for a set time (the cooldown) so the agent moves significantly away from the obstacle, avoiding the collision; only then is the path to the target reevaluated.

The Timer configuration can be done from the _Ready() method of the node that owns the Timer.

Configuring a Timer in the _Ready method
Configuring a Timer in the _Ready method

Ignore the lines before line 83, they have nothing to do with the Timer, but I’ve left them so you can see a real example of Timer usage.

In line 83, I load a reference to the Timer node that is a child of the node executing this script. With that reference, we could configure all the fields available in the Timer’s inspector. In my case, it wasn’t necessary because I didn’t need to change the Timer’s configuration already set in the inspector, but I did manually connect a method to the Timer’s signal (line 84). In this case, the connected method is OnAvoidanceTimeout(). I could have connected it using the "Node" tab in the inspector, but I preferred to do it via code.

The OnAvoidanceTimeout() method couldn’t be simpler, as it just sets the flag to false, so that in the next frame the GetSteering() method knows there are no active timers.

Callback connected to the Timer signal
Callback connected to the Timer signal

Implementation in Unity

Unity doesn’t have a specialized component like Godot’s Timer node, but creating one is very easy using coroutines.

Let’s see how we could create a component that emulates the functionality provided by Godot’s node. We could call our component CustomTimer:

Start of our Timer class for Unity
Start of our Timer class for Unity

The fields this component could offer would be the same as those of the aforementioned node.

Class fields exposed to the inspector
Class fields exposed to the inspector

With this, what we’d see in the inspector would be the following:

Inspector view of our CustomTimer class
Inspector view of our CustomTimer class

If autoStart is set to true, the component would simply call the StartTimer() method from Awake(), as soon as the script starts.

Timer start
Timer start

The method called on line 50 of the Awake method simply starts a coroutine and stores a reference to it so it can be controlled externally (line 55).

The body of the launched coroutine is very simple:

Coroutine body of the Timer
Coroutine body of the Timer

The coroutine simply waits for the number of seconds set in waitTime. Depending on the type of time we want to use (game time or real time), it waits for game seconds (line 65) or real-time seconds (line 68).

After that time, the timeout event is triggered (line 72).

If the timer is single-use, the coroutine ends (line 74); otherwise, the cycle repeats (line 60).

What’s the purpose of the reference we stored on line 55 of the StartTimer() method? It allows us to stop the coroutine early if needed, using the StopCoroutine method.

Code for early stopping of the timer
Code for early stopping of the timer

A GameObject with a CustomTimer component like the one described could use it from another GameObject’s script by getting a reference to the component:

Getting a reference to CustomTimer
Getting a reference to CustomTimer

From that reference, using the Timer would be identical to what we saw with Godot’s node.

Using the CustomTimer component
Using the CustomTimer component

Since this example is the Unity version of what we already saw for Godot, I won’t go into more detail.

Implementation in C#

What do Godot C# and Unity have in common? Exactly, their programming language: C#. This is a general-purpose language and comes “batteries included,” meaning it has lots of modules and libraries for doing many things. One of those modules offers a timer with very similar functionality to what we’ve already seen.

If C# already offers a timer, why is it so common to see implementations like the ones above in Godot and Unity? Why not use the C# timer directly?

I think the simplest answer is for the case of Godot. Godot’s default language is GDScript, and it doesn’t come “batteries included,” or rather, its “batteries” are the thousands of nodes Godot offers. That’s why Godot C# inherits access to the Timer node thanks to its availability in GDScript code.

The Unity case is harder to answer, and I think it’s due to a lack of awareness of what C# offers on its own. Also, we’ve seen that creating a custom timer is very easy using a mechanism as familiar to Unity developers as coroutines. I think that ease of creating your own timer has led many to never explore what C# offers in this regard.

The timer C# offers is System.Timers.Timer, and its usage is very similar to what we’ve seen in Unity and Godot.

Using C#’s native timer
Using C#’s native timer

In line 103 of the screenshot, you can see that you need to pass the desired duration to its constructor.

The AutoReset field on line 105 is completely equivalent to Godot’s Autostart.

In line 106, you can see that the event this timer triggers is Elapsed (equivalent to Godot’s timeout signal). You can subscribe callbacks (like OnTimerTimeout) to this event just like we did in the previous versions for Godot and Unity.

Finally, this C# timer also has Start() (line 117) and Stop() methods to start and stop it.

The only precaution to take with this timer is that you should never call its Start() method unless you’re sure the previous countdown has finished. If you need to start a new countdown before the previous one ends, you must first call Stop() and then Start(). The issue is that this timer is optimized for multithreaded environments, so when you call multiple Start()s in a row, it doesn’t finish the previous countdowns but accumulates them in different threads, causing the countdowns to run in parallel and the events to trigger as those countdowns finish (which may appear as irregular timing due to being from different countdowns).

Conclusion

If you program in C# in both Godot and Unity, there are very few reasons not to use the C# timer. It’s lightweight, efficient, and being cross-platform, it allows you to reuse code between Unity and Godot more easily.

The only reason I can think of to keep using Godot’s node is for manipulation from the inspector when integrating with other game elements; but beyond that, I don’t see much use in continuing to use either Godot’s node or Unity’s coroutine-based timers.