Wie erstelle ich eine anpassbare Formel für RPG-Level-Up-Anforderungen?

44

Ich versuche, eine Formel zu erstellen, die einfach geändert werden kann, indem zwei Werte geändert werden: number_of_levels und last_level_experience. Auf diese Weise können Benutzer, die das Spiel modifizieren, die Levelanforderungen ändern.

Ich habe es so, dass ich die Anzahl der für das letzte Level benötigten XP spezifizieren kann, aber ich möchte in der Lage sein, die für das erste Level benötigten XP zu kontrollieren, was in diesem Fall sehr unterschiedlich sein kann. Wenn ich zum Beispiel 40 Level und 1.000.000 XP für das letzte Level habe, ist die erste Level-Aufwärtsanforderung 625. Wenn ich jedoch die Level auf 80 ändere, wird das erste Level 156. In beiden Fällen muss das letzte Level erreicht werden 1.000.000.

Es muss eine Möglichkeit geben, den Computer dazu zu bringen, eine geeignete Kurve zu berechnen, wenn nur diese beiden Grundwerte gegeben sind.

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

Ausgabe:

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)
Knüppel
quelle
13
Das grundlegende Problem ist, dass es unendlich viele XP-Level-Kurven gibt, die enden würden, wenn das letzte Level so viel XP erfordert. Sie haben die Dimensionen des Problems nicht eingeschränkt, da Sie nicht angegeben haben, wie die XP von Stufe zu Stufe geändert werden soll. Möchten Sie eine exponentielle Wachstumskurve? Eine parabolische Wachstumskurve? Eine lineare? Ihr Problem ist im aktuellen Zustand nicht lösbar. Persönlich, wenn ich das Spiel modifizieren würde, würde ich mehr Kontrolle über die XP-Kurve wünschen als nur die letzte Level-Nummer und die letzte Level-XP. Ich möchte die tatsächliche Kurve selbst steuern.
Nicol Bolas
Ich kann Moddern erlauben, das Leveln über ein Skript zu steuern.
Schlagstock

Antworten:

71

Obwohl es unendlich viele Möglichkeiten gibt, sie auszuwählen, folgt das Nivellieren von Kurven häufig einer Potenzregel wie der folgenden:

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

Der Hauptvorteil dieser Formel kann leicht erklärt werden: Für eine gegebene Regel gibt es einen festen Wert N, so dass jede Stufe N Prozent mehr kostet als die vorherige .

Ihre anfänglichen Variablen fügen die folgenden Einschränkungen hinzu:

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

Zwei Gleichungen, zwei Unbekannte. Das sieht gut aus. Einfache Mathe geben Aund B:

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

Daraus ergibt sich der folgende 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;
    }
}

Und die folgende Ausgabe:

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
quelle
12
Wenn nur alle Antworten so gut geplant und durchdacht wären.
Nate
Die Kurve hier ist viel schmackhafter.
Schlagstock
Gute Antwort. Das mag eine blöde Frage sein, aber wie rechnen NSie das aus, was Sie oben beschrieben haben? Was ist, wenn Sie Ndie steckbare Variable machen wollen? Lassen Sie mich wissen, ob ich dazu eine eigene Frage stellen soll.
Daniel Kaplan
1
@tieTYT die Beziehung zwischen Nund Bist exp(B) = 1 + Noder B = log(1 + N). Wenn Sie also möchten, dass jedes Level z. B. 15% mehr als das vorherige erfordert , müssen Sie dies tun B = log(1 + 0.15) = 0.13976.
Sam Hocevar
18

Vergessen Sie nicht, die Zahlen zu runden, nachdem Sie Ihre Kurve herausgefunden haben. Es macht wenig Sinn, dem Spieler mitzuteilen, dass er 119.378 Erfahrungspunkte benötigt, um das nächste Level zu erreichen - denn die Person würde es immer als "ungefähr 120.000" verstehen. Somit sind Sie besser dran, selbst zu runden und Ihren Spielern "saubere" Ergebnisse zu präsentieren. Zum Beispiel wird der folgende Code (der sich auf den Sam Hocevar erstreckt) versuchen, auf ≈2,2 signifikante Stellen aufzurunden (offensichtlich kann diese Konstante nach Belieben angepasst werden):

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

Die Ausgabe ist:

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
Pascha
quelle