Como criar uma fórmula ajustável para requisitos de nível de RPG?

43

Estou tentando criar uma fórmula que pode ser modificada simplesmente alterando dois valores: number_of_levels e last_level_experience. Isso permite que as pessoas que estão modificando o jogo alterem os requisitos de nivelamento.

Compreendi para que eu possa especificar o número de XP necessário para o último nível, mas quero poder controlar o XP necessário para o primeiro nível, que neste caso pode diferir bastante. Por exemplo, se eu tiver 40 níveis e 1.000.000 de XP para o último nível, o requisito de primeiro nível será 625. Mas se eu alterar os níveis para 80, o primeiro nível será 156. Nos dois casos, o último nível precisa 1.000.000.

Deve haver alguma maneira de fazer com que o computador calcule uma curva adequada, considerando apenas esses dois valores básicos.

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

Resultado:

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)
Cassetete
fonte
13
O problema fundamental é que existem infinitas curvas de nível de XP que terminariam com o último nível exigindo muito XP. Você não restringiu as dimensões do problema, porque não declarou como deseja que o XP mude de nível para nível. Você quer uma curva de crescimento exponencial? Uma curva de crescimento parabólico? Linear? Seu problema é insolúvel no estado atual. Pessoalmente, se eu estivesse modificando o jogo, gostaria de ter mais controle sobre a curva de XP do que apenas o número do último nível e o XP do último nível. Eu gostaria de controlar a própria curva real.
Nicol Bolas 12/12
Posso permitir que os modders controlem o nivelamento por meio de um script.
Truncheon

Respostas:

70

Embora existam infinitas maneiras de escolhê-las, é comum que as curvas de nivelamento sigam uma regra de potência como a seguinte:

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

A principal vantagem dessa fórmula pode ser facilmente explicada: para uma regra especificada, existe um valor fixo N tal que cada nível custa N por cento mais que o anterior .

Suas variáveis ​​iniciais adicionam as seguintes restrições:

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

Duas equações, duas incógnitas. Este parece ser bom. Matemática simples dá Ae B:

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

Resultando no seguinte código:

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

E a seguinte saída:

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
sam hocevar
fonte
12
Se ao menos todas as respostas fossem bem planejadas e pensadas.
Nate
A curva aqui é muito mais agradável.
Truncheon
Boa resposta. Esta pode ser uma pergunta estúpida, mas como você calcula o Nque descreveu acima? E se você quisesse tornar Na variável conectável? Deixe-me saber se devo fazer uma pergunta separada para isso.
Daniel Kaplan
1
@tieTYT a relação entre Ne Bé exp(B) = 1 + Nou B = log(1 + N). Portanto, se você deseja que cada nível exija, por exemplo, 15% a mais do que o anterior, será necessário B = log(1 + 0.15) = 0.13976.
sam hocevar 6/09/13
17

Não se esqueça de arredondar os números depois de descobrir sua curva. Não faz muito sentido dizer ao jogador que ele precisa de 119.378 pontos de experiência para alcançar o próximo nível - porque a pessoa sempre o entenderia como "aproximadamente 120.000". Assim, você estará melhor fazendo o arredondamento e apresentando resultados "limpos" aos seus jogadores. Por exemplo, o código a seguir (que se estende ao de Sam Hocevar) tentará arredondar para ≈2,2 dígitos significativos (obviamente essa constante pode ser ajustada conforme desejado):

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

A saída é:

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
Paxá
fonte