Einige werden sich sicherlich fragen, was es mit dem Titel so auf sich hat.
Prinzipiell ist das ganz einfach.
Wenn man programmiert/scriptet gibt es fast nichts schlimmeres, wenn man unstrukturiert arbeitet.
Besonders unvorteilhaft ist das, wenn viele an einem Script gearbeitet haben.
Man hat bei Dialogen meistens auch überhaupt keinen Überblick, welche DialogIDs man schon genutzt hat
und welche nicht.
Das sieht denn meistens in den Scripten so aus:
(grobes Beispiel :P)
#define Dialog1 5
#define Dialog2 6
#define Dialog3 7
// weitere defines z.B. Farben
#define Dialog8 20
#define Dialog9 21
// usw - meistens hängen dann noch new und forwards dazwischen
defakto hat man keinen Überblick mehr.
Hier haben wir freie DialogIDs von 8 bis 19.
Das ist zwar nicht weiterschlimm, aber unvorteilhaft, da man nicht mehr weiß welche bereits belegt sind.
Dafür hab ich nun die Perfekte Lösung gefunden, die Lösung exestiert schon etwas länger, nur habe ich vermutet, dass man damit Speicher belegt.
Dies passiert aber nicht.
Es ist mehr eine andere Art Konstanten bzw Macros zu erstellen.
Wichtig: Nicht zu verwechseln mit dem const Keyword, es ist diesem nur sehr ähnlich.
Soviel zur Theorie.
Kommen wir zu Praxis:
Der Schlüssel heißt enum.
Was machen wir jetzt damit?
Üblicherweise erstellt man damit eine kleine Struktur, von Variablen.
Enum kann aber viel mehr als nur eine Struktur erstellen.
Eine Technik wenden wir hier an.
Hier ein Beispiel, welches noch einmal behandelt wird.
enum // DialogIDs - hier brauchen wir keinen Namen, da wir im nachinein nicht auf einen Array verweisen, bzw auf einen Arrays hinauswollen
{
DIALOG_LOGIN,
DIALOG_REGISTER
};
DIALOG_LOGIN bekommt vom Enum die ID 0 - nicht den Wert - zugewiesen.
DIALOG_REGISTER bekommt vom Enum die ID 1 - nicht den Wert - zugewiesen.
Warum ist das nun so?
Wie möglicherweise aus der üblichen Arbeitsweise bekannt ist,
simmuliert der Enum Arraywerte.
Beispiel:
enum Spieler
{
Kills, // hat die ID 0
Tode, // hat die ID 1
xBeligigerArray[10] // hat die Werte 2-12
// Der Enum nummeriert also durch
};
new SpielerInfo[50][Spieler];
// Wir können statt SpielerInfo[5][Kills] die Variable auch direkt ansprechen
// dies funktioniert in dem wir dem compiler ersteinmal erklären welchen Enum er nun ansprechen soll, es gibt ja schlißlich nicht nur einen
// Wir nehmen den Enum Namen und benutzen ihn als Tag im Array, den wir bearbeiten wollen
Spieler:Kills[playerid] = 8; // wäre somit falsch
//richtig wäre
SpielerInfo[playerid][Spieler:0] = 8; // 0 - weil Kills vom Enum die ID 0 bekommen hat.
Um das noch einmal zu verdeutliche - ich weiß, ihr wollt endlich wissen wie das nun angewendet werden kann.
Die Theorie zur Praxis ist nunnmal nicht ganz unwichtig
Weiter im Text,
um das nochmal zu verdeutlichen:
Dieser Code:
const Array1 = 0; // oder #define Array1 0
const Array2 = 1; // oder #define Array2 2
const Array3 = 2; // oder #define Array3 2
new Array[3];
//Anwendung:
Array[Array1] = 2;
Array[Array2] = 5;
Array[Array3] = 8;
Ist hoffentlich selbst erklärend.
Man könnte dies natürlich auch wieder per Enum machen
Aber nungut, ihr wollt ja schließlich was über die Anwendung lernen.
Machen wir also weiter
Den Enum von Oben:
enum
{
DIALOG_LOGIN,
DIALOG_REGISTER
};
Benutzen wir einfach in einem Dialog für die DialogID
ShowPlayerDialog(playerid,DIALOG_LOGIN,DIALOG_STYLE_PASSWORD,"Login","Willkommen auf XYZ.\nBitte logge dich ein","Login","Ich gehe");
Eigentlich sollte das nun selbst erklärend sein, sofern man die Theorie von oben verstanden hat.
Falls nicht, nochmal lesen.
Falls beim 2. Mal es immer noch nicht verstanden wurde, im Thread fragen - dafür ist er schließlich da
Einige werden sich bestimmt fragen, ob man damit nun speicher belegt.
Seid beruhigt.
Ich würde dieses Tutorial nicht machen, wenn man dies tuen würde.
Beiweis:
//Defines
#include <a_samp>
#define Test1 0
#define Test2 1
main() { }
public OnGameModeInit()
{
print("loaded");
return true;
}
//Enum
#include <a_samp>
enum
{
Test1,
Test2
};
main() { }
public OnGameModeInit()
{
print("loaded");
return true;
}
enum
{
Test1,
Test2
};
wenn wir nun uns die Anforderungen ansehen:
Vom ersten Test:
Header size: 136 bytes
Code size: 84 bytes
Data size: 28 bytes
Stack/heap size: 16384 bytes; estimated max. usage=9 cells (36 bytes)
Total requirements: 16632 bytes
Vom 2. Test:
Header size: 136 bytes
Code size: 84 bytes
Data size: 28 bytes
Stack/heap size: 16384 bytes; estimated max. usage=9 cells (36 bytes)
Total requirements: 16632 bytes
Stellt man sicherlich fest, das es vollkommen identisch ist.
Dies trifft auch auf mit dem Keyword const erstellen zu, diese sind aber wie defines ziehmlich unübersichtlich ;(,
deswegen nicht zu empfehlen.
Die "Anforderungen" bekommt ihr einfach, wenn ihr mit -d3 compiliert
Vorteile:
- Übersicht
- kein Speicherverbrauch
- Klare Struktur
- Keine unnötigen freien DialogIDs
- Kein überlegen mehr, welche DialogID noch frei ist (Zeit ersparnis)
Nachteil:
Leider gibt es auch einen Nachteil, und zwar der, dass man in Filterscripten/Includes so nicht arbeiten sollte,
es wird zu einer Überschneidung kommen
Dies kann man aber umgehen, in dem man die IDs im Enum ändert.
Dies geht folgendermaßen:enum
{
DIALOG_LOGIN = 500,
DIALOG_REGISTER
};
Dies braucht man überlicherweise nur beim ersten machen, da Enum dann weiterzählt.
DIALOG_REGISTER hat somit die ID 501.
Natürlich könnte man die IDs auch häufiger ändern, man sollte aber aufpassen, nicht das man durcheinander kommt.
Ich hoffe, ich konnte euch die PAWN Welt ein bisschen aufhellen.
Fehler und Verbesserungen sind natürlich erwünscht