Guten Tag liebe Leser dieses Tutorial.
Diesen Tutorial befasst sich mit dem erstellen eines Zollsystems , welches sehr einfach erweiterbar ist in der hinsicht auf
weitere
Zollschranken. Zu dem wird hier auch noch gezeigt wie man diese
Zollschranken auch ganz einfach per Dialog verschließen kann.
Da dies mein erstes Tutorial ist , welches ich als offizielles Tutorial hier in diesem Bereich
zur Verfügung stelle. Möchte ich zu mal die Schwierigkeitgrade der System, welche hier wo möglich noch von
mir beschrieben und vorgestellt werden erläutern.Dies soll dazu dienen das
man weiß, ob man mit diesem Tutorial auf Grund seiner eigenen Leistungen
bewältigen kann und somit noch was dazu lernt.Mein Ansicht ist dazu das es nichts
bringt , wenn man ein Tutorial absolvierr, da man nicht
weiß was man macht beziehungsweise nicht weiß , welche Elemente genau dafür benutzt werden und warum.
[tabmenu]
[tab='Einsteiger']
Wenn man frisch in PAWN ist, so bist du bei solch einem Tutorial genau richtig hier werden
nicht so fortgeschrittenere Themen aufgezogen und sämtliche
Funktionen/Callbacks/Operator... und ihre funktionen werden hier genau
erklärt und verdeutlicht.
[tab='Anfänger']
Solltest du schon ein bisschen Ahnung haben von PAWN von den
Callbacks/Funktionen/Operator und den meisten Keywords haben so bist du
bei diesen Schwierigkeitsgrad genau richtig. Hier werden nur untypische Verwendungen Erklärt.
[tab='Fortgeschritten']
Solltest du Ahnung von PAWN haben den meisten
Callbacks/Functionen/Operator/Keyword .. haben so bist du bei diesem
Schwierigkeitsgrad genau richtig.
Hier heißt es selbst mit denken sehr schwierge Bereiche werden
angesprochen die meist in Ausnahmefällen ihre ständige verwendet
erfordert.
[/tabmenu]
[tabmenu]
[tab='Bilder']
Bilder
[/tabmenu]
Inhaltsverzeichniss
- 1.0 Vorraussetzungen
- 1.1 Basis zum Zollsystem
- 1.2 Erstellen der Zollschranken zum Zollsystem
- 1.3 Command zum Zollsystem
- 1.4 Timer für die Zollschranken
-
2. Command zum schließen der Zollschranken | Aufruf des Dialoges
- 2.1 Dialog zum schließen/öffnen der Zollschranken
Vorraussetzungen
Bevor wir Anfangen benötigen wir erstmal 2 Plugins das sscanf & streamer plugin , welche auf folgenden Link zu finden sind
1.1 Basis zum Zollsystem
Nun erstellen wir erstmal die Basis. Dazu benötigen wir zu mal ein enum, welches als index für das folgende 2D Array dient.
Das enum beinhaltet 12 Floats da wir die X- Koordinate, Y- Koordinate, Z- Koordinate, RoatationX- Koordinate,
RoatationY- Koordinate und die RoatationZ- Koordinate brauchen und dies zwei mal da wir in das Array die
Position des Zollschranken eintragen einmal geschlossen und einmal offen.
zObject wird für die Modelid genutzt und zID ist nicht umbedingt nözig jedoch
schreibe ich dies einfach dazu da wir die ID des Objektes in einer Variabel speichern müssen,
um das Object mit MoveDynamicObject zu verschieben.
zState ist der Status der Zollschranke, welchen wir abfragen werden beim "/zoll" Befehl damit das Skript
erkennt das die jeweiligen Zollschranke gesperrt ist.
enum zollsys {
zID,
zObject,
Float:zCX,
Float:zCY,
Float:zCZ,
Float:zCRx,
Float:zCRy,
Float:zCRz,
Float:zOX,
Float:zOY,
Float:zOZ,
Float:zORx,
Float:zORy,
Float:zORz,
bool:zState,
};
Alles anzeigen
Nun
haben wir den Index für die zweite Dimension des Arrays , welches wir
natürlich auch nun erstellen. Der Vorteil mit einem Array zu arbeiten in
diesem falle
ist das dies sehr übersichtlich ist und somit kann man neue Zollschranken ganz leicht hinzufügen mit nur einer Zeile.
new ZollInfo[MAX_ZOLLGATES][zollsys] = {
{0,978,53.61148071,-1525.98864746,4.87745094,0.00000000,0.00000000,83.37002563,53.61148071,-1525.98864746,-6.87745094,0.00000000,0.00000000,83.37002563,false},
{1,978,55.77261353,-1539.03112793,4.95321989,0.00000000,0.50000000,79.91503906,55.77261353,-1539.03112793,-6.95321989,0.00000000,0.50000000,79.91503906,false},
};
Wie
man hier schon sieht habe ich schon zwei Tore hinzugefügt und es
existiert hier schon MAX_ZOLLGATES was man natürlich noch definieren
muss mit
in meinem Falle
Die
defines sind konstante Werte und existieren beim Kompielen in der AMX
nicht mehr da diese ersetzt werden durch den Wert, String , Code oder
Farbcode, welcher sich dahinter verbirgt.
Beispiel:
wird zu
Die Klammern sind nicht nötig beim deklarieren von Zahlen.
Was
man jedoch auch noch zum Thema Array wissen sollte ist, das dies
weniger Memory verbraucht als das deklarieren von mehreren Variabeln.
Der Grund dafür ist das Arrays beim compilen keine einzelne Zeile einnimmt pro Wert.
1.2 Erstellen der Zollschranken zum Zollsystem
So
nun haben wir das Array mit den Toren nun sollten diese auch erstellt
werden unter OnGameModeInit dies tuhen wir mit einer for-Schleife(loop).
new i;
for(;
i < MAX_ZOLLGATES; ++i)ZollInfo[i][zID] =
CreateDynamicObject(ZollInfo[i][zObject],ZollInfo[i][zCX],ZollInfo[i][zCY],ZollInfo[i][zCZ],
ZollInfo[i][zCRx],ZollInfo[i[zCRy],ZollInfo[i][zCRz]);
Was
man hier sieht ist das , das i außerhalb der for-schleife deklariert
habe. Was bewirken soll, dass die for-Schleife schneller ist. Ob dies
der fall ist
garantiere ich nicht jedoch war dies bei mir so nach
mehreren Tests, dass diese Art der For-schleife schneller war, als die
alt bekannte Variante
for(new i; i < MAX_ZOLLGATES; ++i). Jetzt
werden sich auch bestimmt ein paar Fragen warum ++i und nicht i++ das
ist in PAWN Leider das selbe.
Normal ist das erhöhen von einem Werte
mit ++i dem Inkrement Operator schneller als mit dem Dekrement Operator,
da der Postfix-Version
eine Kopie von sich anlegen, erst dann kann sie sich Inkrementieren. Das muss die Präfix-Version nicht daher ist sie schneller.
Jedoch gilt dies nicht meines Erachtens in PAWN.
1.3 Command zum öffen/schließen der Zollschranken
if (!strcmp(cmdtext,"/zoll")){
if(GetPlayerMoney(playerid)< ZOLL_PRICE)return SendClientMessage(playerid,-1,"Du hast nicht genug Geld für den Zoll!");
new i, bool:no;
for(; i < MAX_ZOLLGATES; ++i){
if(IsPlayerInRangeOfPoint(playerid,10.0,ZollInfo[i][zCX],ZollInfo[i][zCY],ZollInfo[i][zCZ])){
if(ZollInfo[i][zState])return SendClientMessage(playerid,-1,"Der Zoll wurde geschlossen!");
printf("%d",i);
GivePlayerMoney(playerid,-ZOLL_PRICE);
SendClientMessage(playerid,-1,"Gute Weiterfahrt");
MoveDynamicObject(ZollInfo[i][zID],ZollInfo[i][zOX],ZollInfo[i][zOY],ZollInfo[i][zOZ],2.0,ZollInfo[i][zORx],ZollInfo[i][zORy],ZollInfo[i][zORz]);
printf("%f %f %f",ZollInfo[i][zOX],ZollInfo[i][zOY],ZollInfo[i][zOZ]);
SetTimerEx("CloseZollGate",ZOLL_OPEN_TIME,false,"i",i);
no = false;
break;
}else no = true;
}
if(no)return SendClientMessage(playerid,-1,"Du bist an keiner Zollschranke!");
return 1;
}
Alles anzeigen
Zum Befehl hin könnt ihr natürlich auch einen Commandprozessor verwenden ob YCMD, ZCMD , RCMD , OCMD ... es ist völlig egal,
jedoch gibts hier unterschiede in der Geschwindigkeit. Der schnellste Commandprozessor ist YCMD.
Nun mal zum Aufruf des Befehls allgemein mit strcmp.
Es gibt ja viele möglichkeiten dies zu tun
Aber warum geht den dies überhaupt mit dem Ausrufezeichen (!) ?
Es geht daher, da es wie bei jedem anderen code auch die selbe abkürzung für 1 ist. Was meine ich damit genau ?
Hier sieht man die vereinfachung von
Also sähe das ursprünglich bei dem strcmp befehl so aus
beziehungsweise in der richtigen Form
Also alles außer 1 und da strcmp beim Vergleich unterschiedliche werte zurück gibt, wie sollte der string identisch sein so wird der wert 0 wieder gegeben.
Daher kann man sich merken sollte eine Funktion die man benutz oder eine Variabel den wert 1 haben so
ist dies die mögliche Abfrageform.
Nun gehen wir zum weiteren Teil des Command hier wird eine for-schleife benutzt die durch die ganzen Werte geht , welche in de Array enthalten sind.
Manche werden sich bestimmt fragen, warum hier ein boolean benutz wird. Nun gut lasst es mich erklären. Ich benutze dies um
falls der Spieler nicht in der nähe einer Zollschranke ist zum Schluss die Nachricht auszugeben das der Spieler nicht am Zollschranke ist.
Daher wird der wert das Boolean auf den wert true gesetzt und wie man vorher lernen konnte ist dies auch dies zum Schluss eine mögliche Abfrageform ob der Wert 1 ist.
Sollte dies sein, so bekommt der Spieler die Nachricht. Nun sollte der Spieler an einer Zollschranke sein
so wird der Code an der Stelle abgebrochen und daher auch der Wert auf 0 gesetzt in dem Falle hier false. (false = 0 | true = 1)
Nun beim Timer ist dies so das hier die Ordnungszahl des jeweiligen Tores an das public per SetTimerEx übergeben wird.
Was man hier noch von eurer Seite hinzufügen kann ist das automatisch beim betätigen des Command der jeweilige Timer Abgebrochen
und danach neu Aufgerufen wird, dass hätte den Vorteil ,das nicht aufeinmal die Zollschranke zu geht nachdem man die Zollgebühr bezahlt hat.
Aber ich hab dies mit absicht weg gelassen. Sollte jemand das Tutorial bis hier in ausführlich gelesen haben so ist er auch dementsprechend
informiert und sollte/könnte dies auch noch hinzufügen.
1.4 Timer zum schließen der Zollschranke
forward CloseZollGate(zollid);
public CloseZollGate(zollid) MoveDynamicObject(ZollInfo[zollid][zID],ZollInfo[zollid][zCX],ZollInfo[zollid][zCY],ZollInfo[zollid][zCZ],2.0,ZollInfo[zollid][zCRx],ZollInfo[zollid][zCRy],ZollInfo[zollid][zCRz]);
Hier wird die Zollschrank auf ihre ursprünglich Position gesetzt. Man braucht dafür keine Klammern solang nur einmal
ein Aufruf einer Funktion statt findet oder die Veränderung eines Wertes usw... .
Daher ist sowas auch möglich man kann sich somit auch die Klammern sparen
geht auch so
Das macht jedoch kein Unterschied zur Benutzung mit Klammern in dem Fall.
Command zum schließen der Zollschranke
else if (!strcmp(cmdtext,"/cgate")){
ShowPlayerDialog(playerid,DIALOG_CLOSE_ZOLL,DIALOG_STYLE_LIST,"Zollverwaltung",ZOLLCSTRING,"Auswählen","Schließen");
return 1;
}
Nun gut hier wird ein Dialog aufgerufen mit der jeweiligen ID, welche wir mit einem #define festgelegt haben. Da ich mir noch was kleines Einfallen lassen hab verwenden wir hier einen schlauen String "ZOLLCSTRING". Der ist in sofern schlau da er die größe des String beim compilen festlegt. Daher auch
Beim compilen multipliziert er 50 mit der Anzahl von MAX_ZOLLGATES sollte dies 2 Sein so ist der String 100 Zeichen groß.
Jedoch das der string das was wir wollen enthält so müssen wir den String natürlich erstmal formatieren
stock ZollDialogText()
{
strdel(ZOLLCSTRING,0,sizeof(ZOLLCSTRING));
new i;
for(; i < MAX_ZOLLGATES; ++i)format(ZOLLCSTRING,sizeof(ZOLLCSTRING),"%s{FFFFFF}Zoll %d | %s\n",ZOLLCSTRING,i,((ZollInfo[i][zState])?("{FF0000}geschlossen"):("{00FF00}offen")));
}
Dazu will ich noch anmerken das man 1 String für alles benutzen kann solange man ihn vor der Verwendung leert.
Um vorzubeugen das andere Elemente doch im string enthalten sind. Da hier der string formatiert werden muss wegen dem Status der Schranke ist man gezwungen format zu benutzen sollte dies nicht der Fall sein so empfehle ich die string Functionen zu benutzen da dies meist schneller sind als format.