Як створити регульовану формулу для вимог до рівня RPG?


44

Я намагаюся створити формулу, яку можна змінити, просто змінивши два значення: number_of_levels та last_level_experience. Це дозволяє людям, які моделюють гру, змінити вимоги до рівня.

Я отримав це так, що я можу вказати кількість XP, необхідного для останнього рівня вгору, але я хочу мати можливість контролювати XP, необхідний для першого рівня вгору, який у цьому випадку може сильно відрізнятися. Наприклад, якщо у мене 40 рівнів, а для останнього рівня - 1 000 000 XP, вимога до першого рівня - 625. Але якщо я зміню рівні на 80, перший рівень вгору стає 156. В обох випадках потрібен останній рівень 1 000 000.

Має бути якийсь спосіб змусити комп'ютер опрацювати відповідну криву з урахуванням саме цих двох основних значень.

#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;
    }
}

Вихід:

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)

13
Основна проблема полягає в тому, що існує нескінченно багато кривих рівнів XP, які закінчуватимуться останнім рівнем, що вимагає стільки XP. Ви не обмежували розміри проблеми, оскільки ви не заявили, як ви хочете, щоб XP мінявся з рівня на рівень. Ви хочете кривої експоненціального зростання? Параболічна крива росту? Лінійний? Ваша проблема нерозв’язна в поточному стані. Особисто, якби я моделював гру, я хотів би більше контролювати криву XP, ніж просто номер останнього рівня та останній рівень XP. Я хотів би сам контролювати фактичну криву.
Нікол Болас

Я можу дозволити моддерам контролювати нівелювання за допомогою сценарію.
Тренчон

Відповіді:


71

Хоча існує нескінченно багато способів їх вибору, для вирівнювання кривих зазвичай дотримуватися правила потужності, такого як наступне:

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

Основну перевагу цієї формули можна легко пояснити: для даного правила існує фіксоване значення N таке, що кожен рівень коштує на N відсотки більше, ніж попередній .

Ваші початкові змінні додають такі обмеження:

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

Два рівняння, дві невідомі. Це добре виглядає. Прості математики дають Aі B:

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

Отриманий наступний код:

#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;
    }
}

І наступний вихід:

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

12
Якби тільки всі відповіді були цілком сплановані та продумані.
Нейт

Крива тут набагато приємніша.
Тренчон

Хороша відповідь. Це може бути дурним питанням, але як ви обчислите Nте, що ви описали вище? Що робити, якщо ви хочете зробити Nплагін змінної? Дайте мені знати, чи варто мені поставити окреме запитання для цього.
Даніель Каплан

1
@tieTYT відносини між Nі Bє exp(B) = 1 + N, або B = log(1 + N). Тож якщо ви хочете, щоб кожен рівень вимагав, наприклад, на 15% більше, ніж попередній, вам знадобиться B = log(1 + 0.15) = 0.13976.
sam hocevar

18

Не забудьте округлити цифри після того, як ви зрозуміли свою криву. Немає сенсу говорити гравцеві, що йому потрібні 119 378 балів, щоб досягти наступного рівня - адже людина завжди розумів би це як "приблизно 120 000". Таким чином, вам буде краще робити округлення самостійно і представляти «чисті» результати своїм гравцям. Наприклад, наступний код (який поширюється на Сем Хочевара) намагатиметься округлити до ≈2,2 значущих цифр (очевидно, що константа може бути налаштована так, як ви хочете):

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)) )

Вихід:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.