State Machine:Olvasgatva kicsit az angol fórumon megtaláltam, hogy a PAWNO támogatja az úgynevezett State Machine-t (vagy Autómatát, továbbiakban SM), ami engedélyezi, hogy bizonyos funkciókat külömbözo esetekben használjuk. Ezt a módszert használtam én is, a 3 scriptes szerveremen, és sokkal átláthatóbb lett a kód. Vegyünk egy példát.
#include <a_samp>
forward restart(); // deklaráljuk a prototípust
new RestartReason[1][1];
public OnGameModeInit() {
SetTimer(\"restart\",1000*60*10,false); // Majd egy timert
}
public restart() {
RestartReason[0][0] = 1;
SendRconCommand(\"gmx\");
}
public OnGameModeExit() {
if(RestartReason[0][0] == 1) {
printf(\"A folyamatot a restarter szaktította meg\");
} else {
printf(\"A folyamatot szimplán a felhasználó szaktította meg\");
}
}
Ez muködik. De ismerjük a mondást, attól, mert valami muködik, még nem biztos, hogy jó. Használjuk az SM-et:
#include <a_samp>
forward restart();
public OnGameModeInit() {
SetTimer(\"restart\",1000*60*10,false);
}
public OnRconCommand(cmd[])
{
if(strcmp(cmd, \"gmx\", true) == 0) {
state kilepes:gmx;
}
return 1;
}
public restart() {
state kilepes:restarter; // Létrehoztunk egy state machinet
OnGameModeExit();
}
public OnGameModeExit() <kilepes:restarter>
{
printf(\"A rendszert a restarter újraindította.\");
}
public OnGameModeExit() <kilepes:gmx>
{
printf(\"A rendszert a felhasznalo ujrainditotta.\");
}
Sokan mondják áá ez bonyorult, de nem, képzeljétek el azt, ami nálam fennált. Egy modom volt amibe 3 gm funkcióit surítettem össze. Hogy tudom a parancsokat, a timereiket egyesével kezelni? Ezzel.
A direktívának lehetnek kondíciói. Pl:
state (1 == 1) egyenlo:igen;
state (1 != 1) egyenlo:nem;
Vagy akár használhatjuk parancsként is.
state (!strcmp(cmdtext, \"/parancs\")) meghivva:igen;
A másik ilyen funkció az entry(); ami akkor hívódik meg, ha csak egy autómatás scritpeknél lefut az SM. Példa:
main() {
printf(\"Ez\");
state kiirat:igen;
printf(\"Funkcio\");
}
entry() <kiirat:igen> {
printf(\"Egy\");
}
Ez azt fogja kiírni: EzEgyFunkcio.
Ahogy láthatjuk, ez nagyon, és kicsi megoldás ezekre a problémákra.
Gyorsaság:Vegyünk példának egy ciklust:
for ( new i = 0; i < MAX_PLAYERS; i++ )
Ez gyorsabb, mivel egy konstanst használnuk. De ha például:
for ( new i = 0; f = GetMaxPlayers(); i < f; i++)
Ez viszont - mivel több változót használnuk - lassabb.
Nézzünk egy szokásos hibát:
new Valamennyi = random(10);
printf(\"%d\",Valamennyi);
Mivel itt a valamennyit elobb deklaráltuk, ezért ez folyamatosan a meghatározott funkció névterében marad. Ha a funkcoó engedélyezi a paramétereket (a printf ilyen), akkor egyszeruen tegyük ezt:
printf(\"%d\",random(10));
Ebbol világosan kítunik, hogy a konstansok sokkal gyorsabbak, mint a változók!Egy másik nagy hülyeség:
new var = 1;
if(var == 1) {
printf(\"Expression has..\");
} else {
printf(\"No effect\");
}
Gondolom mindenki látja mi a hiba. Elég lenne ennyi:
printf(\"%d\",1);
IEEE:Sokan használnak érvénytelen értékeket ha nagy vagy ismeretlen számmal van dolguk. Ez azomban nem jó, mivel sokszor azt is meghaladhatja a számítás (pl ha egy távolság lekéronél írunk 10.000 -t elorfordulhat, hogy 10.001 egységre van, szóval érvénytelen lesz a kód). Erre tökéletes megoldás az alábbi három IEEE szabvány:
#define FLOAT_INFINITY (Float:0x7F800000)
#define FLOAT_NEG_INFINITY (Float:0xFF800000)
#define FLOAT_NAN (Float:0xFFFFFFFF)
Bemutatom egy egyszeru példán keresztül
public OnPlayerUpdate() {
new Float:Health;
if(!IsPlayerConnected(playerid)) {
return FLOAT_NAN; // NaN - Nem szám. Tényleg nem. Majd meglátjátok.
} else if GetPlayerHealth(playerid,Health > 100) {
SetPlayerHealth(playerid,FLOAT_INFINITY); // Ha több az élete mint 100, akkor örök életet kap.
} else {
return 0; // Ha egyik sem, akkor 0 a visszatérési értékünk
}
}
A Not a Number nevu szám egy igen érdekes szám. Akármelyik számmal való összehasonlítása (beleértve önmagát is) hamis értékkel tér vissza. Pl:
if(FLOAT_NAN == FLOAT_NAN) { /* Ez nem fog lefutni, mivel a FLOAT_NAN nem egyenlo önmagával sem! */ }
Azomban pont ezt ki lehet játszani. Itt egy példa:
stock IsNotANumber(number) {
return(number != number) // Máshogy kifejezve: if(number != number) { return 1; } else { return 0; }
}
Ha a szám nem egyenlo önmagával, akkor az a NAN.
Egyenloség:Vegyük példának a 0-t, számtalan felírási módja létezik:
5*0
((27 + 3) / 5) - 6)
0+0
0-0
\\0
0x00
0b00000000
0
false
!true
!változó
0.0
0.00000y
Ebbol kiindulva rájöhetünk egy másik gyakran elkövetett hibára. Ha a string üres, sokan így nézik meg:
if (strlen(string) == 0)
{
// a string üres
}
Ez azomban lassú, ha a string nem üres, ezért elég megnézni csak az ELSO karakterét a stringnek, hogy rájöjjünk, üres-e
if(str[0] == \'\\0\') {
// a string üres, mert az elso karaktere = 0
}
Vagy egy másik megoldás
if(!strlen[0]) {
// a string üres, mivel az elso karaktere nem létezik
}
Ezt természetesen az összes 0-s felírási móddal el lehet játszani az összes 0 felírási móddal.
Bitmanipuláció:Gyorsabb mód a matematikai muveletek elvégzésére. Minden egyes eltolt bittel egyenesen artányosan kettot hozzáadunk a szám szorzatához.
<< 1 = *2
<< 2 = *4
<< 3 = *6
<< 4 = *8
A jobb shift pedig ugyanezt csinálja osztással
>>1 = /2
>>2 = /4
>>3 = /6
>>4 = /8
2*2 == 2 << 1
2/2 == 2 >> 1
Dimenziók fölösleges használataMajd meglátjátok, mirol beszélek,. Itt egy tömb:
new Fegyverar[5] { 5000, 1, 600, 100, 5 };
Sokan azt hiszik, ha meg akarják tudni a fegyver ID-jét. kell hozzá egy plussz dimenzió:
new Fegyver[5][1]
De minek?! Egyszeruen fogod, és ezt csinálod:
new OtosIDJuFegyverAra = Fegyver[5];
És kész! Meg van oldva.
A tutorial bizonyos részeiben PAWNO tutorialokat, és IEEE szabványlistát használtam.