6
\$\begingroup\$

How is an economy system implemented in clicker games? Obviously, you can't store values like 1 Quintilian in long type. I understand that there might be some string operations or even better, some int array where every index has it's value, though I'm curious if there are better methods and what they are.

Also, how to make this system generic and reusable for any other clicker or not clicker game.

And about bonus system, for example, 50 000% increase, I bet it's a bad idea to multiply this value every frame for every other kind of object that generates game currency.

How is this system implemented as well? If you have different sources of bonuses, do you have modifier object that multiplies values?

\$\endgroup\$
  • \$\begingroup\$ Thanks for answers guys, that explains it. But what about boosters? How do you handle them on OOP level? I have a few ideas on how to implement, it's not a problem because I'm pretty familiar with patterns and OOP, though I'm curious what is the common approach. I thought of Observer for every type of bonus that multiplies income values when bonus value is upgraded, is it a good approach in your opinion or is there is a better way?. \$\endgroup\$ – Candid Moon _Max_ Jun 11 '17 at 22:03
  • \$\begingroup\$ Do you really need "quintillions" with a precision of 1? 64 bits is used even by NASA for solar system calculations... And they went to the moon on a 16 bits guidance system. \$\endgroup\$ – Olivier Grégoire Jun 12 '17 at 10:42
  • \$\begingroup\$ @OlivierGrégoire You are right, I don't need them. Just asking about different implementations. \$\endgroup\$ – Candid Moon _Max_ Jun 12 '17 at 17:53
10
\$\begingroup\$

There are data types that handle these situations, like C#'s BigInteger:

The BigInteger type is an immutable type that represents an arbitrarily large integer whose value in theory has no upper or lower bounds.

Which I would guess is actually just int[] with some nice features wrapped around it. Being immutable could certainly be a problem for lots of calculations, as you'd need to create new values frequently.

However, attempting to keep track of the exact value in a clicker game probably wouldn't be how I'd do it. I'd probably use something like along for the significant digits and keep track of the exponent separately. As the number grows, increase the exponent and shift the significant digits down.

You can store your insignificant values as you shift them out, so you can restore them when the exponent on your economy comes down.

When you're making a quintillion dollars a second, does it matter that you're not making a quintillion and one dollars a second?

BTW, a double will take you all the way up to a Uncentillion.

\$\endgroup\$
  • 5
    \$\begingroup\$ It's a uint[] actually, since you only want to store the sign bit once, which has the bonus of doubling the range. But no real functional change otherwise. \$\endgroup\$ – Clockwork-Muse Jun 11 '17 at 22:53
  • \$\begingroup\$ Interestingly, BigInteger won't allocate the internal array if the value it's storing fits in an int. It has a sign field that is just a normal int, so it'll store any values that can fit in that field and won't allocate any arrays. \$\endgroup\$ – Kyle Jun 12 '17 at 13:57
  • \$\begingroup\$ not knowing what a "clicker game" is, (and that tag only refers to this question) I don't know how important accuracy is, but a double is, iirc only countable up to ~2^54 (about 1.8x10^16) after which you start to get un-representable integer values... \$\endgroup\$ – Baldrickk Jun 12 '17 at 16:54
6
\$\begingroup\$

In my implementation I use a double to store the value. A double can store really large values (up to 1.8 × 10308 in case of an IEEE 754 64-bit double, i.e. 180 Uncentillion) so you shouldn't have to worry about hitting the cap. To put that number into perspective if you gave your player 1 Quintillion [whatever] every second it would take you 5 Trenonagintillion years to reach that value! And the downside of precision is negligible when you're dealing with such large numbers.

I've also experienced that using a double is faster than BigInteger or similar data structures. So in case performance is required it should be preferred.


As for how you handle bonuses what I did was separate the logic into two steps:

  1. The prediction
  2. The calculation

The calculation would only be performed every once in a while depending on how much you're making and how much you currently have (greater values = fewer updates). For example at over 1 quintillion I only update once every second.

The prediction however would save objects such as Multiplier (increases value by a Multiplier such as * 2) and FlatIncrease (increases value by a flat value such as + 10). These would be saved and then applied to the calculation when you need the exact value. First the FlatIncrease would be added then the Multiplier would multiply the value.

\$\endgroup\$
  • \$\begingroup\$ Well yeah a double will be faster. It has built-in hardware support, whereas most stuff like BigInteger is an aggregate of values in an array, and operations have to work on chunks at a time. \$\endgroup\$ – Clockwork-Muse Jun 11 '17 at 22:55
  • 1
    \$\begingroup\$ Downvoter: care to explain your downvote? :) \$\endgroup\$ – Charanor Jun 12 '17 at 9:22
  • 1
    \$\begingroup\$ I wasn't the downvoter, but I was tempted to based purely on the "you don't ever have to worry about hitting the roof cap." First, as a developer you should always worry about what will happen when you hit that cap, even if it's fairly unlikely. Second, without knowing how OP's app works, it's pretty darn hard to say that they'll never get a score that big. It depends on the points scale that OP's working at, and who knows -- perhaps they're doing something nutty like doubling your score every time you get a certain achievement! \$\endgroup\$ – A C Jun 12 '17 at 13:46
  • \$\begingroup\$ @AC I disagree that hitting the cap is a concern (even in the most extreme of cases) and especially that you should always worry about hitting the cap (perhaps if you're using an integer, but not a double). I have nevertheless edited the question to add the actual size of a double and added an example of how large it actually is... \$\endgroup\$ – Charanor Jun 12 '17 at 13:58
  • 1
    \$\begingroup\$ @AC dev's don't usually worry about caps being hit when it will take longer than a lifetime to do so. \$\endgroup\$ – UKMonkey Jun 12 '17 at 15:34
3
\$\begingroup\$

You don't have to update resources every tick.

Instead, it's enough to just store the formula that lets you compute how many resources you will have at any given time. And then you only ever bother doing so when the value is actually needed.

When the player gets a bonus to production, it's simply a matter of updating the formula to account for it.

\$\endgroup\$
  • \$\begingroup\$ This likely goes against the core of a clicker game. It's all about making a number get bigger. Seeing that happen, watching the numbers roll over to higher and higher amounts, is an important part of the game. \$\endgroup\$ – MichaelHouse Jun 12 '17 at 18:27
  • 1
    \$\begingroup\$ @Byte56: Updating the screen is a reason to actually need the value, but that only needs to happen a few times per second. \$\endgroup\$ – user64554 Jun 12 '17 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.