Hallo liebe Community,
ich sehe hier öfters wie einige Probleme haben dynamisch veränderbare Sachen zu erstellen. Ich möchte hiermit einen Einblick schaffen wie soetwas aussehen kann ohne mich jetzt auf eine bestimmte Sache zu fokusieren, es geht lediglich um darum wie man dynamische Strukturen schafft und volle Kontrolle darüber erreicht.
Nun, jeder kennt Pawn als Sprache und somit auch die Fähigkeit der Multidimensionalen Array sprich eine Variable die mehrere Speicherplätze hat aber immer den selben Bezeichner hat, dieser Bezeichner spricht nachher die Stelle im Speicher an welche zeigt wo sich der Anfang dieser Variable bzw. die Variable selbst befindet zudem wird dort die Größe initialisert die zeigt wie groß unsere Variable eigentlich ist z.b.
new unsertext[] = "Hallo Welt";
Wie man sieht ist die Variable als Array gekennzeichnet und zeigt dem Compiler beim Kompilierungsprozess dass es sich hierbei um einen Array handelt und sich mehrere Werte darin befinden,
hier haben wir ,,Hallo Welt´´ definiert sprich 10 Zeichen mit einem weiteren Zeichen welches \0 kennzeichnet sprich hier ist Sense.
würden wir unsere Variable nun ohne Text definieren wollen aber mit der selben Größe so müssten wir Sie wie folgt definieren
new unsertext[11];+
und könnten später 10 zeichen oder 10 integer Werte darin speichern, Integer steht hierbei für einen Zahlenwert sowohl im Minus als auch im Plus Bereich.
wir können einen Array auch Multidimensional definieren sprich so
new unsertext[][] = {{"Hallo Welt"},{"Wert2"}};
Die Datentypen bleiben vorerst die selben sprich Zeichenketten , einzelne Zeichen oder Integer. Um dass mit den Zeichen nocheinmal zu zeigen und was ich mit Zeichenketten meine
new unsertext[] = {'H','a','l','l','o',' ','W','e','l','t'};
entspräche auch
new unsertext[] = "Hallo Welt";
Um auf einen index in der Variable zuzugreifen sprich einen Speicherplatz könnte man dies tun
new unserzeichen = unsertext[1]; // Rückgabe hierbei wäre jetzt a
Nie vergessen, ein Array fängt immer bei 0 , eigentlich logisch doch für viele ist es die Gewohnheit bei 1 anzufangen denn dies haben wir ja in der Schule gelernt.
Kann ich auch andere Datentypen verwenden ?
Ja dies ist möglich. Ihr müsste dem Compiler nur bescheid geben dass Ihr einen anderen Datentyp verwenden wollt da jeder Datentyp eine andere Größe besitzt die später erst reserviert werden muss sonst findet der Compiler weder Anfang noch Ende der Variable sprich der Registereintrag wäre falsch und wäre unauffindbar!
z.b.
new Float:unsereVariable[] = { 3.14 , 4.32, 5.22 };
dies ginge auch Multidimensional wie bei allen anderen datentypen
new Float:unsereVariable[][] = { {3.14 , 4.32, 5.22} };
oder noch größer usw... z.b. 3 dimensional , auch 4 dimensional usw...
new Float:unsereVariable[][] = { { {3.14 , 4.32, 5.22}, {3.14 , 4.32, 5.22} },
{ {3.14 , 4.32, 5.22}, {3.14 , 4.32, 5.22} }
};
nun wissen wir dass wir auch andere Datentypen verwenden können, aber was wenn wir mehrere Datentypen verwenden möchten ? Nun dann definieren wir eine Struktur die angibt welche Größen nach welcher Reihenfolge vorhanden sind damit auch hier richtige Einträge in das Register eingetragen werden können sprich wir geben dem Compiler bescheid welche Datentypen wir haben möchte und geben Ihnen einen Bezeichner , hierzu nehmen wir mal "enum" als Anweisung
enum unsereStruktur // wir geben der Struktur mal diesen Namen
{
Float:eineKommaZahl,
eineGanzeZahl,
einearray[32] // auch in einer Struktur können weitere Strukturen die bereits da sind verwendet werden, hier nehme ich einfach ein array mit 32 Plätzen für 31 Zeichen oder Zahlen
};
diese kann man jetzt sozusagen jeder Variable verergeben und kann somit mehrere Datentypen in eine Variable einbinden z.b. so
new unsereVariable[unsereStruktur]; // nun hat diese Variable ,,unsereStruktur ´´ "geerbt" und man kann sie dann dementsprechend ändern z.b.
unsereVariable[eineGanzeZahl] = 5;
wir greifen hier auf den Bezeichner "eineGanzeZahl" in "unsereVariable" zu sprich wir sprechen genau diese Stelle im Speicher an welche uns anzeigt es kann ein Integer/char eingetragen werden sprich dessen Größe hat , würden wir versuchen einen String zuzuweisen so gäbe es ein Problem, die größe wäre nicht für eine Kette von zeichen vorgesehen und somit würde alles was über einem Zeichen/Integer ist den Speicher dahinter überschreiben wollen, dieser Bereich ist aber schon reserviert bzw. geschützt was zu einem fatalen Fehler kommen würde denn so kämme der ganze Ablauf durcheinander und das Register wäre Fehlerhaft!
wir können Strukturen auch Multidimensional verwenden
new unsereVariable[20][unsereStruktur];
so hätten wir 20 Plätze die jeweils alle die Datentypen aus "unsereStruktur" beinhalten.
Zugriff hätten wir z.b. ganz einfach so :
unsereVariable[2][eineGanzeZahl] = 5;
jetzt hat "eineGanzeZahl" in Platz 2 der Variable "unsereVariable" den Wert 5. Die anderen Plätze kann man auch mit jeweils einer Zahl belegen genauso wie man die anderen Bezeichner jeweils belegen kann
so könnte man Werte gleich festlegen was rein soll :
new unsereVariable[][unsereStruktur] = { {5,3.14,"Hallo Welt"} , {7,4.22,"nummer 2"}};
natürlich muss alles festgelegt werden was die Struktur "unsereStruktur" angibt und jeweils im vorgegebenen Datenytp. Würden wir eine feste Größe definieren wollen muss diese mit der Anzahl der angegebenen Daten überein stimmen
new unsereVariable[2][unsereStruktur] = { {5,3.14,"Hallo Welt"} , {7,4.22,"nummer 2"}}; // hier müsste also eine 2 stehen, 0 für Eintrag 1, 1 für Eintrag 2, und 2 für die information wo die variable endet, nur für den Speicher wichtig
Dynamisch arbeiten
Als erstes definieren wir uns eine array im Kopf des Skripts und einen variable die zurückgibt wieviele id's gespeichert wurden
new unsereIDS[20]; // 20 Speicherplätze in denen ich 20 Autos speichere
new count = -1; // ich setze hier mal auf -1 da ich zuerst hochzähle und dann erst verwende, kann jeder machen wie er will
Nun gehe ich in die öffentlich Funktion "OnGameModeInit" und gehe wie folgt vor
count++; // ich zähle wie gesagt zuerst hoch um den Speicherplatz festzulegen den ich als nächstes verwende
if(count <= 19) // damit der speicher nicht höher als 19 geht und so ein fehler auftritt da unsereIDS nur 20 slots hat und davon 19 verwendet werden können von 0 angefangen!
{
unsereIDS[count] = CreateVehicle(...); // Ich erstelle das Fahrzeug und speichere dessen ID in unsereIDS auf dem jeweiligen platz
}
würde ich jetzt abfragen wollen ob z.b. dies ein Auto aus der array ist so muss die ID des Fahrzeugs auch in der Variable vorhanden sein z.b. so
for(new i = 0;i<count;i++)
{
if(GetPlayerVehicleID(playerid) != unsereIDS[i])continue; // wenn die ID des Autos in dem wir sitzen nicht unsereIDS[speicherplatz] dann schleife fortsetzen und weitersuchen
SendClientMessage(playerid,0xFFFFFFFF,"Es ist ein Auto aus der Array!"); // wird die schleife nicht übersprungen wie oben gezeigt mit continue so muss er an diese stelle kommen und es ist ein Auto aus dem Array
break; // schleife gleich beenden denn wir müssen nicht mehr weitersuchen, jeder wie er will, ich mache es so
}
Um nun etwas genauer zu werden und eine Struktur einzubinden mache ich folgendes :
ich behalte count als zähler variable und erstelle nun eine struktur :
enum unserFahrzeug
{
id,
kostet,
gehoert[MAX_PLAYER_NAME]
};
nun ändere ich meine Variable unsereIDS um in
unsereIDS[20][unserFahrzeug];
so vererbe ich die Struktur unsereIDS und kann detailiertere Infos eintragen und verwenden und habe so mehr Möglichkeiten
wenn ich nun das Fahrzeug erstelle tuhe ich dies so
count++; // wie immer erst den Platz hochzählen beim erstellen
if(count <= 19) // ihr wisst ja was ich gesagt hab!
{
unsereIDS[count][id] = CreateVehicle(...); // nun speichern wir die ID in "id" und in platz den count zurückgibt
// hier weise ich mal zum test den rest zu, diesen kann man später woanders ändern mit einer schleife oder so, hier nur als test für nachher
unsereIDS[count][kostet] = 200; // kostet kriegt jetzt den Wert 200 also im übertragenen sinne soll mein preis 200$ für dieses Fahrzeug sein.
format(unsereIDS[count][gehoert],MAX_PLAYER_NAME,"%s","EinName"); // ich setze gehoert auf "EinName" natürlich wieder im Platz den "count" zurückgibt
}
nun wenn ich später abfrage tuhe ich wieder folgendes
new formatmsg[MAX_PLAYER_NAME + 32]; // für später um den Namen anzuzeigen
for(new i = 0;i<count;i++)
{
if(GetPlayerVehicleID(playerid)
!= unsereIDS[i][id])continue; // wenn die ID des Autos in dem wir sitzen
nicht unsereIDS[speicherplatz][id] dann schleife fortsetzen und weitersuchen
format(formatmsg,sizeof formatmsg,"Dieses Auto gehoert %s und kostete %i",unsereIDS[i][gehoert],unsereIDS[i][kostet]); // wird die schleife nicht übersprungen
wie oben gezeigt mit continue so muss er an diese stelle kommen und es
ist ein Auto aus dem Array
SendClientMessage(playerid,0xFFFFFFFF,formatmsg); // zeigt die Nachricht die ich formatiert habe an
break; // schleife gleich beenden denn wir müssen nicht mehr weitersuchen, jeder wie er will, ich mache es so
}
Also, dass wars, ich hoffe ich konnte euch einen Schritt näher an die Sache bringen und es etwas verdeutlichen, es ist aus dem Prinzip heraus nicht schwer und mit etwas Zeit kriegt es jeder hin.