44
\$\begingroup\$

I'm trying to create a formula that can be modified simply by changing two values: number_of_levels, and last_level_experience. This is to enable people modding the game to change the levelling requirements.

I've got it so that I can specify the number of XP needed for the last level up, but I want to be able to control the XP needed for the first level up, which in this case can differ wildly. For example, if I have 40 levels, and 1,000,000 XP for the last level, the first level up requirement is then 625. But if I change the levels to 80, the first level up becomes 156. In both cases, the last level needs 1,000,000.

There must be some way to get the computer to work out a suitable curve given just these two basic values.

#include <iostream> int main() { int levels = 40; if (levels < 2) levels = 2; int experience_for_last_level = 1e6; float fraction = 1.0 / levels; { int i = 0; float fraction_counter = fraction; int counter = levels; int total = 0; for (i = 1; i <= levels; ++i, fraction_counter += fraction, --counter) { int a = static_cast<int>(fraction_counter * experience_for_last_level / counter); std::cout <<"Level "<<i<<": "<<a<<" ("<<counter<<")"<<"\n"; total += a; } std::cout << "\nTotal Exp: " << total; } } 

Output:

Level 1: 625 (40) Level 15: 14423 (26) Level 29: 60416 (12) Level 2: 1282 (39) Level 16: 16000 (25) Level 30: 68181 (11) Level 3: 1973 (38) Level 17: 17708 (24) Level 31: 77499 (10) Level 4: 2702 (37) Level 18: 19565 (23) Level 32: 88888 (9) Level 5: 3472 (36) Level 19: 21590 (22) Level 33: 103124 (8) Level 6: 4285 (35) Level 20: 23809 (21) Level 34: 121428 (7) Level 7: 5147 (34) Level 21: 26250 (20) Level 35: 145833 (6) Level 8: 6060 (33) Level 22: 28947 (19) Level 36: 179999 (5) Level 9: 7031 (32) Level 23: 31944 (18) Level 37: 231249 (4) Level 10: 8064 (31) Level 24: 35294 (17) Level 38: 316666 (3) Level 11: 9166 (30) Level 25: 39062 (16) Level 39: 487499 (2) Level 12: 10344 (29) Level 26: 43333 (15) Level 40: 999999 (1) Level 13: 11607 (28) Level 27: 48214 (14) Level 14: 12962 (27) Level 28: 53846 (13) 
\$\endgroup\$
2
  • 13
    \$\begingroup\$ The fundamental problem is that there are infinitely many XP level curves that would end with the last level requiring that much XP. You have not constrained the dimensions of the problem, because you have not stated how you want the XP to change from level to level. Do you want an exponential growth curve? A parabolic growth curve? A linear one? Your problem is unsolvable in its current state. Personally, if I were modding the game, I'd want more control over the XP curve than just last level number and last level XP. I'd want to control the actual curve itself. \$\endgroup\$ Commented Dec 12, 2011 at 8:02
  • \$\begingroup\$ I can allow modders to control levelling via a script. \$\endgroup\$ Commented Dec 12, 2011 at 8:23

3 Answers 3

72
\$\begingroup\$

Though there are infinitely many ways to choose them, it is common for leveling curves to follow a power rule such as the following one:

f(level) == A * exp(B * level) 

The major advantage of this formula can be easily explained: for a given rule, there is a fixed value N such that each level costs N percent more than the previous one.

Your initial variables add the following restrictions:

f(1) - f(0) == experience_for_first_level f(levels) - f(levels - 1) == experience_for_last_level 

Two equations, two unknowns. This looks good. Simple maths give A and B:

B = log(experience_for_last_level / experience_for_first_level) / (levels - 1); A = experience_for_first_level / (exp(B) - 1); 

Resulting in the following code:

#include <cmath> #include <iostream> int main(void) { int levels = 40; int xp_for_first_level = 1000; int xp_for_last_level = 1000000; double B = log((double)xp_for_last_level / xp_for_first_level) / (levels - 1); double A = (double)xp_for_first_level / (exp(B) - 1.0); for (int i = 1; i <= levels; i++) { int old_xp = round(A * exp(B * (i - 1))); int new_xp = round(A * exp(B * i)); std::cout << i << " " << (new_xp - old_xp) << std::endl; } } 

And the following output:

1 1000 9 4125 17 17012 25 70170 33 289427 2 1193 10 4924 18 20309 26 83768 34 345511 3 1425 11 5878 19 24245 27 100000 35 412462 4 1702 12 7017 20 28943 28 119378 36 492389 5 2031 13 8377 21 34551 29 142510 37 587801 6 2424 14 10000 22 41246 30 170125 38 701704 7 2894 15 11938 23 49239 31 203092 39 837678 8 3455 16 14251 24 58780 32 242446 40 1000000 
\$\endgroup\$
4
  • 12
    \$\begingroup\$ If only all answers were this well planned and thought out. \$\endgroup\$ Commented Dec 12, 2011 at 23:07
  • \$\begingroup\$ The curve here is much more palatable. \$\endgroup\$ Commented Dec 22, 2011 at 22:26
  • \$\begingroup\$ Good answer. This may be a stupid question, but how do you calculate N that you described above? What if you wanted to make N the pluggable variable? Let me know if I should ask a separate question for this. \$\endgroup\$ Commented Sep 5, 2013 at 17:30
  • 1
    \$\begingroup\$ @tieTYT the relationship between N and B is exp(B) = 1 + N, or B = log(1 + N). So if you want each level to require e.g. 15% more than the previous one, you’ll need B = log(1 + 0.15) = 0.13976. \$\endgroup\$ Commented Sep 6, 2013 at 9:23
17
\$\begingroup\$

Don't forget to round the numbers after you figured out your curve. It doesn't make much sense to tell the player he needs 119,378 experience points to reach the next level — because the person would always understand it as "roughly 120,000". Thus you will be better off doing the rounding yourself, and presenting "clean" results to your players. For example the following code (which extends upon the Sam Hocevar's) will attempt to round up to ≈2.2 significant digits (obviously that constant can be tweaked as you want):

from math import exp, log levels = 40 xp_for_first_level = 1000 xp_for_last_level = 1000000 B = log(1.0 * xp_for_last_level / xp_for_first_level) / (levels - 1) A = 1.0 * xp_for_first_level / (exp(B) - 1.0) def xp_for_level(i): x = int(A * exp(B * i)) y = 10**int(log(x) / log(10) - 2.2) return int(x / y) * y for i in range(1, levels+1): print( "%d: %d" % (i, xp_for_level(i) - xp_for_level(i-1)) ) 

The output is:

1: 1000 9: 4200 17: 17100 25: 70000 33: 287000 2: 1190 10: 4900 18: 20300 26: 84000 34: 340000 3: 1420 11: 5900 19: 24200 27: 100000 35: 420000 4: 1710 12: 7000 20: 28700 28: 119000 36: 490000 5: 2030 13: 8400 21: 34000 29: 142000 37: 590000 6: 2420 14: 10000 22: 42000 30: 171000 38: 700000 7: 2870 15: 11900 23: 49000 31: 203000 39: 840000 8: 3400 16: 14200 24: 59000 32: 242000 40: 1000000 
\$\endgroup\$
0
\$\begingroup\$

This is a necro answer, but this answer is very different then any of the proposed solutions.

Don't make use an adjustable formula for your level up requirements.

The problem with using a formula:

  1. Its hard to find one that works for any range of levels.
  2. What if I want to mod in a low level game that has a much lower XP cap? but I don't want someone to need 1'000'000 XP for that final level?
  3. Cannot tweak XP requirements ofr individual levels to improve pacing at different stages of the game.

What to do instead?

Use a list! Assign the XP requirements for each level from 1 to N (Where N is the maximum character level).

This gives modders the freedom to choose any curve/ XP progression that they desire (This is also how tabletop games congtrol XP requirements).

They are free to use linear, exponential, or arbitrarly picked values...

And it allows you to game designer to tweak XP requirements in your game to adjust pacing pacing.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.