Scripting Basics PL

From SA-MP Wiki

Jump to: navigation, search
Strona główna | Funkcje | Callbacki | Podstawy pisania skryptów | Pluginy | Poradniki


Contents

Rozpoczynanie!

Poniżej jest przykład najbardziej podstawowego skryptu którego można napisać:

#include <a_samp>
 
main()
{
	print("Hello World!");
	return 1;
}

Różne aspekty zostaną pokryte z kolei, ale zacznijmy od spojrzenia na pierwszą linię.

Includy

#include <a_samp>

To w zasadzie ładuje kod z pawno/includes/a_samp.inc do skryptu, więc ma wszystko co można użyć. Jedną z rzeczy, jest to:

#include <core>
#include <float>
#include <string>
#include <file>
#include <time>
#include <datagram>
#include <a_players>
#include <a_vehicles>
#include <a_objects>
#include <a_sampdb>

Obejmuje to wszystkie inne pliki w tym katalogu, tak, dodając, że w jednym wierszu masz dostęp do wszystkich funkcji w SA:MP (więcej na temat funkcji później).

Wywołania

Kolejna część ma dwie strony z wywołaniem funkcji. main() jest funkcją którą można pisać kod i jest zwracana gdzie indziej, print(string[]) jest funkcją która pozwala wyświetlać komunikaty w konsoli serwera. Obecnie to wszystko załaduje i wyświetli ciąg (np. print("Hello World!") (Bez cudzysłowów) (w tradycji wszystkich języków skryptowych)) do konsoli serwera i koniec. To:

return 1;

Przekazuje wartości (1) z powrotem na miejsce, gdzie zostało zawołana funkcja main() żeby powiedzieć to, co się stało (dokładna wartość przekazywana tutaj nie ma znaczenia, ale w innych miejscach tak jest). Teraz masz swój pierwszy (bardzo podstawowy) skrypt. Jeśli wybierzesz Plik-> Nowy w pawno to dostaniesz znacznie więcej zwrotnych do użycia w skrypcie (patrz poniżej), w tym main() (co nie jest technicznie callback, ale działa podobnie).

Wyrażenia

Funkcja print() i return mają znak ";" (średnika) na nich, to po prostu oznacza koniec instrukcji (oświadczenie to grupa jednego lub więcej funkcji i operatorów, które razem coś zrobią, podobnie jak zdanie w języku potocznym). Większość ludzi umieszczają jednostkowe sprawozdania na osobnych liniach, ale nie jest to wymagane, to po prostu sprawia, że ​​wszystko wygląda wyraźniej. Można też napisać taki kod właśnie tak:

main() { print("Hello World!"); return 1; }

{} (szelki, nie nawiasy) złączają grupę wypowiedzi, które powinny być wykonywane razem (jak pkt w języku potocznym). Jeśli napisałbyś kod tak:

main() print("Hello World!"); return 1;

Dostałbyś błąd, ponieważ teraz "return 1;" nie jest tak zgrupowane więc nie jest częścią funkcji main(). Szelki złączają zestaw instrukcji do pojedynczej instrukcji (tzw. oświadczenie złożone) i funkcje tak to mają jedno stwierdzenie z nimi. Bez szelek, funkcje print() i return są zupełnie odrębnymi oświadczeniami, więc nie wiedzą kiedy mają być wezwane, szczególnie return, który tak naprawdę nie byłby funkcją.

Funkcje

Funkcja jest po prostu kawałkiem kodu, która robi coś i można powiedzieć jej, aby zrobiła to gdzieś indziej. Można również przekazywać dane o tym, co zrobiła, z powrotem na miejsce gdzie została zawołana.

Wołanie

print("Hello World!");

Jak opisano w rozpoczynaniu, to sprawia, że ​​funkcja "print" (zdefiniowana w a_samp.inc, dlatego należy umieścić ją) i mówi jej, aby wyświetliła coś w konsoli serwera.

Funkcja składa się z nazwy funkcji (np. print), która informuje system o fragmencie kodu którym chcesz zawołać, i listę parametrów, zamkniętych w () po nazwie funkcji, które przesyłają dodatkowe dane do funkcji, aby pomóc jej uruchomić. Jeśli nie masz parametrów, musiałbyś mieć miliony funkcji:

printa();
printaa();
printab();
printac();
itd...

Funkcje mogą mieć tyle parametrów, ile chcesz, zaczynając od 0 (może być górna granica, ale to co najmniej 128):

printf("Hello World!", 1, 2, 3, 4, 5, 6);

Nie martw się o to, co ta funkcja ma teraz, po prostu wiedz, że ma 7 parametrów oddzielonych przecinkami.

Definiowanie

Będąc w stanie wywołać istniejących funkcji można też napisać i wywołać własne:

#include <a_samp>
 
main()
{
	return MojaFunkcja();
}
 
MojaFunkcja()
{
	print("Hello World!");
	return 1;
}

To właśnie ma dokładnie taki sam kod jak oryginalny kod, ale wygląda inaczej. Kiedy main() jest wywoływany i gdy tryb jest uruchamiany, (jest to automatyczne) wywołuje nową, niestandardową funkcję o nazwie MojaFunkcja(). Funkcja ta wypisuje komunikat w konsoli serwera następnie zwraca liczbę od 1 do main(). main() bierze zwróconą wartości (1) i zwraca ją do samego serwera (czyli miejsca, w którym sama funkcja była wołana w pierwszej kolejności). Jako "return MojaFunkcja();" jest jednym stwierdzeniem, można zrobić:

#include <a_samp>
 
main() return MojaFunkcja();
 
MojaFunkcja()
{
	print("Hello World!");
	return 1;
}

Ale większość ludzi tego nie robi, dla jasności. Możesz również nie wykorzystywać wartości MojaFunkcja na wszystkich i zrobić:

#include <a_samp>
 
main()
{
	MojaFunkcja();
	return 1;
}
 
MojaFunkcja()
{
	print("Hello World!");
	return 1;
}

Parametry

Parametry to rodzaj zmiennej której nie trzeba deklarować, gdyż pochodzi z miejsca, które nazywa się funkcją:

#include <a_samp>
 
main()
{
	return MojaFunkcja("Hello World!");
}
 
MojaFunkcja(string[])
{
	print(string);
	return 1;
}

Kod ten nadal robi to samo, ale teraz woła funkcję MojaFunkcja() co do wyświetlenia. Zawołanie przesyła ciąg znaków "Hello World!" do funkcji, gdzie są one przechowywane w zmiennej o nazwie string[] ([] oznacza że jest to tablica jak wyjaśniono później). Funkcja print() jest wołana, przekazując zawartość zmiennej string. Wiemy, że jest zmienną, ponieważ nie ma już cudzysłowów.

Zmienne

Zmienna jest w zasadzie część pamięci, gdzie dane są przechowywane i mogą być zmienione i odczytywane zgodnie z wymaganiami. Zmienne zabierają jedną lub więcej komórek, komórki są 4 bajty duże i domyślnie podpisane więc mogą przechowywać numer od -2147483648 do 2147483647 (choć -2147483648 jest słabo zdefiniowane w PAWN i daje dziwne wyniki, jeśli wyświetlane). Zmienna wykonana z więcej niż jednej komórki nazywa się tablicą, ciąg to specjalny rodzaj tablicy, gdzie każda komórka posiada znak łańcucha (lub 4 znaki w pakowanym ciągu, ale nie są one opisane tutaj).

Deklaracja

Aby utworzyć nową zmienną trzeba ją zadeklarować tak:

new
	mojaZmienna;

To mówi systemu, aby utworzyć nową zmienną o nazwie mojaZmienna, wartość początkowa tej zmiennej wynosi 0.

Ustawianie

new
	mojaZmienna = 7;

To deklaruje nową zmienną i ustawia jej wartość początkową na 7, więc wyświetlanie zmiennej będzie zwracało 7. Aby wyświetlić zmienną, która nie jest tekstem, musimy wrócić do funkcji printf() wspominana wcześniej i zrobić:

new
	mojaZmienna = 7;
printf("%d", mojaZmienna);

Ponownie, na razie wszystko co musisz wiedzieć jest to, że to będzie drukować wartość mojaZmienna (tj. 7 w tym momencie) do serwera.

new
	mojaZmienna = 7;
printf("%d", mojaZmienna);
mojaZmienna = 8;
printf("%d", mojaZmienna);

Ten kod wypisze 7, zmieni wartość zmiennej na 8 i wyświetli nową wartość ponownie. Istnieje wiele innych rzeczy które można ze zmiennymi, niektóre są wymienione poniżej, a w większości są wymienione gdzie indziej:

mojaZmienna = mojaZmienna + 4;

Ustawia wartość mojaZmienna do starej wartości mojaZmienna plus 4, tzn. wzrost jej wartości o 4. Może to być również zapisane jako:

mojaZmienna += 4;

Co oznacza po prostu "wzrost mojaZmienna przez 4".

mojaZmienna -= 4;

To zmniejszy wartość o 4.

mojaZmienna *= 4;

To pomnoży wartość o 4.

mojaZmienna /= 4;

To podzieli wartość przez 4.

Tablice

Deklaracje

Tablica to zmienna, w której można przechowywać wiele fragmentów danych na raz i mieć do nich dostęp dynamicznie. Tablica jest zadeklarowana do ustawiania rozmiaru w czasie kompilacji więc musisz wiedzieć, ile sztuk potrzebnych danych do przechowywania, dobrym przykładem jest to bardzo często używana tablica MAX_PLAYERS, będzie to miało jeden slot dla każdego ewentualnie podłączonego gracza, więc wiesz, że dane dla jednego gracza nie będą kolidować z danymi do innego gracza (więcej o definicjach później).

new
	mojaTablica[5];

Ten kod będzie deklarował tablicę z 5 slotami, więc można przechowywać 5 sztuk zwykłych danych na raz w tym jednym. Czego nie możesz zrobić, to coś takiego:

new
	mojaZmienna = 5,
	mojaTablica[mojaZmienna];

Ten kod wygląda jakby utworzył tablicę wielkości numeru jaki jest zapisany w mojaZmienna (tutaj 5, ale to może być cokolwiek), ale nie można tego zrobić. W PAWN pamięć dla zmiennych jest przypisana podczas kompilowania kodu, tablice oznaczają zawsze jeden rozmiar, nie można ustawić rozmiaru dobrowolnie.

Dostęp

Aby ustawić wartość w tablicy trzeba powiedzieć, w której części tablicy chcesz przechowywać dane, można to zrobić przy użyciu innej zmiennej:

new
	mojaTablica[5];
mojaTablica[2] = 7;

Będzie to deklarowało tablicę z 5 slotami i ustawi wartość 7 w TRZECIM slocie, zważywszy, że zmienne zawsze zaczynają jako 0 to spowoduje, że wartości w tablicy:

0, 0, 7, 0, 0

A czemu nie:

0, 7, 0, 0, 0

zastanawiasz się? To dlatego, że liczenie faktycznie zaczyna się od cyfry 0, nie 1. Rozważmy to:

2, 4, 6, 8

Jeśli przejdziesz przez listę, a następnie po numer 2 masz już jeden numer (2), oznacza to, że jeśli liczą numery do czasu gdy osiągnie liczbę 4 są już w jednym, nie jesteś w jeden, gdy dojdziesz do 2, jesteś na zero. Tak więc 2 jest w pozycji zerowej i 4 na pozycji numer jeden, a więc wynika, że ​​6 jest w pozycji dwa, czyli tam, gdzie 7 w pierwszym przykładzie powyżej. Jeśli za-etykietujemy sloty na pierwszym przykładzie mamy:

0 1 2 3 4
0 0 7 0 0

Istnieje pięć slotów ale jak widać, i to jest bardzo ważne, NIE MA SLOTU 5, wykonując następujące czynności może spowodować awarię serwera:

new
	mojaTablica[5];
mojaTablica[5] = 7;

Jak wspomniano powyżej, indeks tablicy (indeks jest slotem, do którego wpisujesz dane) może być cokolwiek, liczba, zmienna, a nawet funkcja, która zwraca wartość.

new
	mojaTablica[5],
	mojIndeks = 2;
mojaTablica[mojIndeks] = 7;

Po tablicy i indeksu można użyć tego bloku dokładnie tak, jak gdyby innej zmiennej:

mojaTablica[2] = mojaTablica[2] + 1;
mojaTablica[2] += 1;
mojaTablica[2]++;

Przykład

Jak wspomniano powyżej popularnym typem tablicy jest tablica MAX_PLAYERS. MAX_PLAYERS nie jest zmienną, to określenie, które zostanie wyjaśnione później, ale teraz przyjmij, że jest to stała liczba równa maksymalnej liczby graczy na serwerze (to domyślnie jest 500, nawet w przypadku zmiany liczby w plik server.cfg). Poniższy kod używa normalnych zmiennych do przechowywania danych dla 4 graczy i zrobi coś z tymi graczmi w funkcji (dla uproszczenia zakładamy MAX_PLAYERS jest 4 na razie):

new
	gPlayer0,
	gPlayer1,
	gPlayer2,
	gPlayer3;
 
SetPlayerValue(playerid, value)
{
	switch(playerid)
	{
	    case 0: gPlayer0 = value; // to jest to samo co -- if(playerid == 0)
	    case 1: gPlayer1 = value; // to jest to samo co -- if(playerid == 1)
	    case 2: gPlayer2 = value; // to jest to samo co -- if(playerid == 2)
	    case 3: gPlayer3 = value; // to jest to samo co -- if(playerid == 3)
	}
}

Zobacz sekcję na temat struktur kontroli po więcej informacji na temat tego, co się tam dzieje, również pamiętaj, że można to zrobić jako przełącznik, ale to mniej wyraźne dla przykładu i skutecznie robi to samo.

Teraz porównaj to z pomocą tablicy z jednego slota dla gracza, pamiętając, że indeks tablicy może mieć dowolną wartość:

new
	gPlayers[MAX_PLAYERS];
 
SetPlayerValue(playerid, value)
{
	gPlayers[playerid] = value;
}

To stworzy globalną tablicę (patrz punkt na zakresach) z jednym slotem dla każdego gracza, potem ta funkcja przydziela, co jest w zmiennej "wartość" do slota dla określonego gracza. Pierwszy przykład był duży z tylko czterema graczami przy użyciu 4 linijek na gracza; to jest w 2000 linijek dla 500 graczy (jeśli może być mniejsza, ale jest jeszcze dużo), druga wersja jest w jednej linii i nie ma znaczenia ile graczów masz.

Ciągi znaków

Podstawowy użytek

Ciąg znaków jest specjalnym rodzajem tablicy, który jest używany do przechowywania wielu znaków, aby utworzyć słowo lub zdanie w formie czytelnej dla ludzi. Znak ma wielkość jednego bajtu (choć nie są rozszerzone zestawy, gdzie znak ma wiele bajtów, ale te nie są dobrze zdefiniowane w SA:MP) i domyślnie znak zajmuje jedną komórkę (jedna normalna zmienna lub jeden slot w tablicy). Znaki są kodowane w systemie o nazwie ASCII, znak "A" jest reprezentowany przez liczbę 65, mówi, że system wyświetla liczbę daje 65, który mówi, że system wyświetlany znak da duże A. Oczywiście że jeden znak zajmuje jedną komórkę, gdzie wiele znaków (czyli tekst) zajmie wiele komórek. Zbiory komórek, jak już wyjaśniono, nazywane są tablicami.

Ciągi znaków w PAWN (i w innych językach) są tym, co nazywa się "NULL terminated", oznacza to, że gdy skończymy pisać w ciągu, znak '0' zostanie automatycznie wpisany, co daje znać systemowi, że to koniec ciągu. To nie jest takie samo jak znak "0", co jest reprezentowane przez liczbę 48, jest to znak NULL, co jest reprezentowany przez liczbę 0. Oznacza to, że możesz mieć tablicę długości 20 komórek, ale tylko ze 3 znakami, gdzie czwarty znak będzie znakiem NULL, sygnalizując koniec ciągu. Nie można mieć jednak 20 znaków w tablicy z 20 komórkami, gdyż znak NULL będzie się liczył jako 21 znak, co by stwarzało problemy.

new
	mojCiag[16] = "Hello World!";

Ten kod deklaruje, nowy ciąg z wystarczającą ilością miejsca dla 15 znaków i ustawia go początkowo na ciąg z 13 znakami o treści "Hello World!", cudzysłowie dookoła tekstu wskazują, że jest to ciąg znaków. Wewnątrz, tablica będzie wyglądać następująco:

104 101 108 108 111 0 x x x x x x x x x x

"x" oznacza coś, w tym przykładzie będzie to 0, ale ponieważ są one po znaku NULL, nie ma znaczenia, czym są, nie mają wpływu na łańcuch.

Ciągi można manipulować jak tablice, na przykład:

new
	mojCiag[16] = "Hello World!";
mojCiag[1] = 97;

To zmieni znak w slocie 1 na znak reprezentowany przez liczbę 97 (mała litera "a"), co zmieni znak 'e' na 'a', teraz zamiast "hello" będzie się wyświetlało "hallo". To może być napisane czytelnie i bardziej łatwe do edycji, czyli tak:

new
	mojCiag[16] = "Hello World!";
mojCiag[1] = 'a';

Pojedyncze cudzysłowie dookoła "a" oznacza, że jest to znak, a nie ciąg znaków, znaki nie muszą być zakończone ze znakiem NULL, gdyż będą zawsze tylko o długości jednej komórki, mogą one również być używane zamiennie z numerami, jeśli wiesz co one znaczą.

new
	mojCiag[16] = "Hello World!";
mojCiag[1] = '\0';

'\0' jest dwoma znakami, jednak \ jest znakiem specjalnym, który modyfikuje następny znak, \0 oznacza NULL, co oznacza że kod jest taki sam jak ten:

new
	mojCiag[16] = "Hello World!";
mojCiag[1] = 0;

Ale NIE JEST tym samym, co:

new
	mojCiag[16] = "Hello World!";
mojCiag[1] = '0';

Pierwsza i druga wersja spowoduje że ciąg jest po prostu:

h

Trzecia wersja spowoduje że ciąg jest:

h0llo

Znak modyfikacji

Jak było wspomniane, ukośnik jest znakiem specjalnym, wstawiane:

'\'

lub:

"\"

będzie dawało błąd kompilatora, ponieważ \ modyfikuje następny znak więc stałe nie zostaną zakończone poprawnie, może to być wykorzystywane do tworzenia znaków, które nie mogą być tworzone, na przykład:


new
	mojCiag[4] = "\"";

Ten kod tworzy ciąg składający się z tylko cudzysłowów, zwykle cudzysłowie sygnalizują koniec określania ciągu, ale ukośnik powoduje, że cudzysłów jest wstawiony, a cudzysłów po tym kończy ciąg. Inne znaki specjalne:

\0 Znak NULL Kończy ciąg.
\n "Line feed" Rozpoczyna nową linię
\r "Carriage return" Używaj \r\n żeby rozpocząć nową linie w Windows
\\ Ukośnik Używane do wprowadzenia rzeczywistego ukośnika w ciągu
\' Pojedyńczy cudzysłów Używane do robienia rzeczywistego apostrofa
\" Podwójne cudzysłowie Używane do robienia rzeczywistych podwójnych cudzysłowów

Istnieją też inne, ale te są najważniejsze z nich.

Etykiety

Etykieta jest dodatkowym elementem informacji do zmiennej, która określa, gdzie może ona być stosowana. Na przykład:

new
    Float:a = 6.0;

"Float" jest etykietą, która definiuje że zmienna jest typem float (nie całkowita liczba) i określa, gdzie może ona być stosowana.

native SetGravity(Float:gravity);

Oznacza to, że funkcja SetGravity przyjmuje jeden parametr, który musi być typu float, na przykład:

SetGravity(0.1);
new
   Float:fGrav = 0.05;
SetGravity(fGrav);

To będzie ustawiało poziom grawitacji na 0.1, a następnie na 0.05. Korzystanie innych znaków w złym miejscu często dają niezgodność tagu:

SetGravity(MojaEtykieta:7);

To będzie próbowało ustawić poziom grawitacji na 7 z etykietą "MojaEtykieta", która z pewnością nie jest "Float", więc jest coś nie tak. Należy również pamiętać, że znaczy też wielkość liter.

Zakresy

Zakres jest sytuacją, gdy zmienna może być użyta. Istnieją cztery główne zakresy: lokalny, lokalny statyczny, globalny i globalny statyczny. Wszystkie zmienne mogą być wykorzystywane wyłącznie po ich deklaracji, więc to jest poprawne:

new
    var = 4;
printf("%d", var);

To jest nie poprawne:

printf("%d", var);
new
    var = 4;

lokalna

Zmienna lokalna jest uznana za "nową" wewnątrz funkcji lub część funkcji:

MojaFunkcja()
{
    new
        var1 = 4;
    printf("%d", var1);
    {
        // var1 nadal istnieje gdyż jest to niższy poziom
        new
            var2 = 8;
        printf("%d %d", var1, var2);
    }
    // var2 już nie istnieje gdyż jest to wyższy poziom
}
// var1 już nie istnieje

Zmienne lokalne są zerowane za każdym razem, na przykład:

for (new i = 0; i < 3; i++)
{
    new
        j = 1;
    printf("%d", j);
    j++;
}

Wydrukuje:

1
1
1

Ponieważ zmienna 'j' jest tworzona, drukowana, zwiększona i następnie zniszczona, i tak w kółko.

lokalna statyczna

Lokalna statyczna może być używana w tym samym miejscu, ale nie zapomina jej starej wartości, na przykład:

MojaFunkcja()
{
    static
        var1 = 4;
    printf("%d", var1);
    {
        // var1 nadal istnieje gdyż jest to niższy poziom
        static
            var2 = 8;
        printf("%d %d", var1, var2);
    }
    // var2 już nie istnieje gdyż jest to wyższy poziom
}
// var1 już nie istnieje

Ten kod będzie zachowywał się dokładnie tak samo jak nowy przykład, jednak:

for (new i = 0; i < 3; i++)
{
    static
        j = 1;
    printf("%d", j);
    j++;
}

Wydrukuje:

1
2
3

Ponieważ zmienna 'j' jest statyczna, więc wspomina jej starą wartość.

globalna

Zmienne globalne są deklarowane poza funkcją i mogą być używane w każdej funkcji:

new
    gMyVar = 4;
 
MojaFunkcja()
{
    printf("%d", gMyVar);
}

One nigdy nie są kasowane lub utracone.

globalna statyczna

Globalne zmienne statyczne są jak normalne globalne, ale mogą być używane tylko w pliku, w którym są zadeklarowane:

Plik1:

static
    gsMyVar = 4;
 
MojaFunkcja()
{
    printf("%d", gsMyVar);
}
 
#include "Plik2"

Plik2:

MojaFunkcja2()
{
    // To jest złe, gdyż gsMyVar już tu istnieje
    printf("%d", gsMyVar);
}

statyczne mogą być również stosowane do funkcji w ten sam sposób.

Struktury Sterujące

Main article: Control Structures

Struktury sterujące określają przepływ programu. Mogą wykonać kod lub nie na podstawie zawartości zmiennych, zwracanie funkcji i innych rzeczy. Mogą też robić rzeczy, wielokrotnie w razie potrzeby.

Słowa kluczowe

Main article: Keywords
Personal tools
Navigation
Toolbox