^Tartalom^- - - Következő oldal »



A GML használatával sokszor áttekinthetőbbé válik, és minél inkább ezzel váltjuk ki az ikonok használatát, annál kisebb méretű lesz a programunk.
GML programsorokat az eszközsorok között található "Add a script" vagy az "Object Properties/Code" csoportján belül lévő "Execute a piece of code" ikonok használatával írhatunk.
Harmadik esetben a szobákhoz (Rooms) is készíthetünk, mégpedig a "Room properties" "Settings" fülén belül található "Creation code" gombra kattintva. Az ott leírtak a szoba létrehozásakor hajtódnak végre.
Az első mód ("Add a script") szerint megírt alprogramot (amely függvény; lásd: 10. pontnál) szintén az Object Properties-ban tudjuk hozzárendelni valamely objektumhoz az "Execute a script" ikonnal, melynél a "Script" mezőhöz ki kell választanunk az előzőleg megírt programot, de bármelyik GML programsorból is hívható a neve és (ha vannak) paraméterei begépelésével.
Bármely módot használjuk is, a program megírásához azonos felületet kapunk, azzal a különbséggel, hogy az első esetben nevet is adhatunk a programunknak, illetve a másodikban beállíthatjuk, hogy a programot az adott objektumhoz (Self), a többihez (Other) vagy egy kiválasztott objektumhoz (Object) rendeljük hozzá.
A megírt program nyelvtani helyességét a "Check the script for syntax errors" ikonra való kattintással ellenőrizhetjük le. Hiba esetén a hibás sor fekete téglalapba kerül.

A programot egy-egy kapcsos zárójel nyitja és zárja, a kifejezések ;-vel vannak elválasztva:

{
<kifejezés>;
<kifejezés>;
}


A kapcsos zárójeleket a program elejére és végére nem muszáj kitenni, és a pontosvesszők használata sem kötelező, kivéve a var kulcsszó (lásd: 3. pont) mögé felsorolt változónevek után, illetve ha több utasítást, kifejezést gépelünk egy sorba, pl.:
<kifejezés>; <kifejezés>

Megjegyzéseket (ezeket a fordító nem veszi figyelembe, így írhatunk pl. magyarázatokat)
/* így is és */
// két perjel után is megadhatunk.

Fontos tudni, hogy a GML különbséget tesz a kis- és nagybetűk között, tehát ha pl. If-et írunk if helyett, az hibának minősül.


1. VÁLTOZÓK:

A változók a memória egy-egy darabjai, melyek információt (valós számot vagy szöveget) tárolnak.
Nevüket onnan kapták, hogy értékük a program futása során megváltozhat (csökkenhet illetve növekedhet).
A GML jónéhány beépített változót is tartalmaz (pl. mouse_x, mouse_y, amik az egérmutató x és y koordinátáját jelzik), melyekről később még esik szó.
A változók nevének hosszúsága legfeljebb 64 írásjel lehet; csak az angol ABC betűit és - az első írásjelet kivéve - valós számokat tartalmazhat, valamint az _ -jelet.

Értéket a változóhoz a <változó> = <kifejezés>; alakkal adhatunk, pl.:

{
x = 23;
szin = $FFAA00;
szoveg = 'Szervusz világ';
y += 5;
x *= y;
x = y << 2;
x = 23*((2+4) / sin(y));
szoveg = 'Szervusz' + " világ";
b = (x < 5) && !(x==2 || x==4);
}



2. LOGIKAI MŰVELETEK:

&& : és (and), || : vagy (or), ^^ : kizáró vagy (xor) (az és művelet végeredménye akkor igaz, ha a kiértékelendő feltételek mindegyike igaz, a vagy műveleté akkor, ha legalább egyikük igaz, míg a kizáró vagy eredménye hamis, ha a feltételek mindegyike ugyanolyan (akár igaz vagy hamis)).
<, <=, = =, !=, >, >=: kisebb, kisebb vagy egyenlő, egyenlő, nem egyenlő, nagyobb,
nagyobb vagy egyenlő (összehasonlító műveletek).
|, &, ^: biteltoló műveletek (| = biteltoló vagy, & = biteltoló és, ^ = biteltoló kizáró vagy)
<<, >>: biteltolás balra, biteltolás jobbra
+, -: összeadás, kivonás
*, /, div, mod: szorzás, osztás, egész osztás (tört eredmény esetén csak az egész részt adja eredményül), maradékképzés (osztás során a maradékot adja eredményül)
!: nem (not) (az igaz értéket hamisra, a hamisat igazra állítja)
-: negálja a következő értéket (megfordítja a biteket és hozzáad egyet).

A nekik megfelelő jelek helyett az and, or, xor, not szavak is használhatók.
Értékként számok, változók vagy értéket visszaadó függvények használhatók. Minden műveleti jel valós számokkal dolgozik. Az összehasonlító műveletek használhatók szövegeknél is, és a + jel szövegek összefűzésére (mint a fentebbi példában: szoveg='szervusz'+" világ").
Néhány műveletet tömörebben is kifejezhetünk, pl. az x=x+1-et úgy is, hogy x+=1. (Ez pl. azt jelenti, hogy az x változó új értéke legyen a jelenlegi érték 1-gyel megnövelve. Vagyis ha most 2, akkor az új értéke 3 lesz.)


3. KÜLÖNLEGES VÁLTOZÓK:

Új változókat egy érték hozzájuk rendelésével is készíthetünk. Ha egyszerűen egy változónevet használunk, a változó csak az aktuális objektummal (amelyhez a programsor hozzá van rendelve) fog eltárolódni. Más objektumokhoz úgy lehet bárhonnan beállítani a változót, ha az objektum nevét egy ponttal elválasztva a változónév elé írjuk, pl. labda.speed=5.
Az olyan változó létrehozásához, mely mindenhonnan elérhető a játék során az összes objektum számára, a változónév elé egy ponttal elválasztva a "global" szót kell írni. Pl.:

{
if (global.csinald)
{
// csinál valamit, miután értékét hamisra állítjuk
global.csinald = false;
}
}


GM 7-től másképp is megadhatunk globális változókat, a következőképpen:
globalvar <valtozonev1>,<valtozonev2>,<valtozonev3>,...;
Amint ez a deklaráció végrehajtódik, a változó globálisként kezelődik anélkül, hogy a global szót és a pontot elé kellene írni. Ezt csak egyszer kell megadni a kódban, ezután minden más helyen globálisként kezelődik.

Az "all" szó használatával a változó értéke az összes objektumra, az other-ral a másikra (ütközés esetén) érvényes, a "self" pedig önmagára vonatkozik.
Nemcsak az objektum neve, hanem egyéni azonosítója, vagyis id-je is használható, ami egy 100000-nél nagyobb, vagy azzal egyenlő szám. Mivel azonban a pont tizedespontként fordítódik, ezért az id-t zárójelek közé kell rakni, tehát pl. (100032).speed=0;

Ha egy változó meglétére szükség van, de pl. kezdőértéket még nem kell hozzá megadni, akkor a noone-t hozzárendelhetjük "üres" kezdőértéknek. Természetesen ezt az "üres" értéket bármikor megadhatjuk a változónak, nemcsak a létrehozásakor.

Ha a változó(ka)t csak az aktuális programsorban használjuk, akkor a "var" kulcsszóval a programsor elején deklarálni kell a következő formában:

var <valtozonev1>,<valtozonev2>,<valtozonev3>, ...

Az így deklarált változók csak ezen programrész használatakor léteznek, vagyis fölöslegesen nem foglalnak helyet a memóriában.
Például a labda objektumhoz tartozó xx és yy nevű változók esetén:

{
var xx,yy;
xx = x+10;
yy = y+10;
instance_create(xx,yy,labda);
}



4. TÖMBÖK:

A változókkal ellentétben a tömbökben nemcsak egy, hanem több azonos típusú adatot ( pl. számokat vagy szövegeket) tárolhatunk.
A GML-ben 1 és 2 dimenziós tömbök használhatók.
Alakjuk: egydimenziós tömb: nev[index] kétdimenziós tömb: nev[sorindex, oszlopindex]
A tömb neve nem tartalmazhat ékezetes betűt és minden tömb a 0. számú indexről kezd futni.
Egy index használata pillanatában a tömb létre is jön.
Soha ne használjunk negatív számot indexként. A rendszer 32000-ben korlátozza az indexek számát, és 1000000-ban a teljes méretet.
Pl. az "a" egydimenziós tömb 0. eleme legyen 1:
a[0]=1;
A "b" kétdimenziós tömb 4. sorában és 6. oszlopában található elem értéke legyen 32:
b[4, 6]=32;


5. ELÁGAZÁSOK:

- Elágazás (kétfelé):

Alakja: if (<feltétel>) <utasítás>
vagy (elágazás kétfelé): if (<feltétel>) <utasítás> else <utasítás>

Jobban áttekinthető, ha a következőképpen használjuk:

if (<feltétel>)
{
<utasítás>
}
else
{
<utasítás>
}


Elágazás alkalmazásával a kiértékelendő feltétel igaz vagy hamis voltától függően hajthatunk végre utasítás(oka)t. Logikai műveletek segítségével összetett feltételt is megadhatunk (pl. if x>0 and x<100 ...). A feltétel(eke)t nem kötelező zárójelek közé rakni, kivéve persze akkor, ha egy többszörösen összetett feltétel valamely tagjai egy külön feltételt alkotnak (pl. if (x>0 and x<100) and speed<12 ...).
Akár a ha (if), akár a különben (else) ágon szükséges egynél több utasítás végrehajtása, azokat kapcsos zárójelek között kell felsorolni. Mindkét ágra igaz, hogy kapcsos zárójel nélkül csak az utána következő egyetlen utasítást hajtja végre, majd a program futása a következő sortól folytatódik.
A különben ág megadása nem kötelező; ezen az(ok) az utasítás(ok) szerepel(nek), amely(ek)et akkor kell végrehajtani, ha a ha ág feltétele nem teljesült. Több, egymással összefüggő elágazás esetén a további fölösleges vizsgálatok elkerülhetők, ha az egyes elágazások az else-vel vannak elválasztva, mivel így az első igaz feltétel megtalálása után a legközelebbi különben ágat követő rész már nem kerül vizsgálatra.
A ha ág feltétele(i) után megadható a then (akkor) szócska is, hogy az áttekinthetőség kedvéért az utasítás(ok)tól jobban elkülönítsük, de ez nem kötelező (pl. if x>0 and x<100 then ...).

Pl. ha x értéke kisebb, mint 200, akkor x-et növeljük 4-gyel, különben csökkentsük 4-gyel:

{
if (x<200) {x += 4} else {x -= 4};
}


- Elágazás többfelé esetszétválasztással:

Alakja:

switch (<feltétel>)
{
case <érték1>: <utasítás1>; ... ; break;
case <érték2>: <utasítás2>; ... ; break;
...
default: <utasítás>; ...
}


Ezt a fajta elágazást akkor érdemes használni, amikor a feltétel kiértékelése során kapott különböző eredmények, értékek alapján kell elágaztatni a programot.
A "break" utasítás és a "default" elágazás nem kötelező (bár a break-et ajánlott kitenni a további utasítások fölösleges vizsgálatának elkerülése végett).
A "default" ágon az(oka)t az utasítás(oka)t szerepletethetjük, amely(ek)et akkor akarunk végrehajtani, ha egyik eset sem teljesült a felsoroltak közül.
Pl. a következő programrészlet megvizsgálja, hogy történt-e billentyűlenyomás (ezt a keyboard_key nevű beépített változó tárolja), s ha ez a balra nyíl, vagy a numerikus billentyűzet 4-es gombja, akkor az x értékét növeli 4-gyel, ha a jobbra nyíl, vagy a numerikus billentyűzet 6-os gombja, akkor az x értékét csökkenti 4-gyel:

switch (keyboard_key)
{
case vk_left:
case vk_numpad4:
x -= 4; break;
case vk_right:
case vk_numpad6:
x += 4; break;
}



6. CIKLUSOK:

A ciklusok arra szolgálnak, hogy programrészlet(ek)et ismételtessünk valahányszor, vagy valamilyen feltétel be (nem) következtéig.

- Egyszerű ismétlés: Alakja: repeat (<kifejezés>) <utasítás>

A "kifejezés" egy egész szám, amennyiszer ismételni fogja az adott utasítást.
Pl. a következő program 5 labdát hoz létre, véletlenszerű helyekre (pontosabban: 5-ször ismétli meg a "labda" nevű tárgy létrehozását):

{
repeat (5) instance_create(random(400),random(400),labda);
}


- Előltesztelő ciklus (while): nevét onnan kapta, hogy az eldöntendő feltétel (melynek igaz volta esetén hajtódik végre a ciklusmag, vagyis az(ok) az utasítás(ok) mely(ek)et végre kell hajtania) a ciklusmag előtt van.
A ciklus akkor ér véget, ha a feltétel hamissá válik.
Alakja: while (<kifejezés>) <utasítás>

Pl. a következő program megpróbálja az aktuális objektumot elhelyezni egy véletlenszerű, de szabad helyre (vagyis a ciklusmagot addig ismételgeti, amíg a feltétel igaz):

while (!place_free(x,y))
{
x = random(room_width);
y = random(room_height);
}


Vegyük észre a "place_free(x,y)" előtt a felkiáltójelet! Az előzőekben leírtak alapján már tudjuk, hogy ez az utána álló érték tagadását jelenti. Tehát a ciklus mondatszerű leírása így hangzik:
"Amíg igaz az, hogy a place_free(x,y) értéke hamis, ismételd: x értéke legyen random(room_width) és y értéke legyen random(room_height)."

- Hátultesztelő ciklus (do-until): nevét onnan kapta, hogy az eldöntendő feltétel (melynek hamis volta esetén hajtódik végre a ciklusmag) a ciklusmag után következik.
A ciklus akkor ér véget, ha a feltétel igazzá válik.
Alakja: do <kifejezés> until (<utasítás>)

Pl. az előző program ezzel a ciklussal:

{
do
{
x = random(room_width);
y = random(room_height);
}
until (place_free(x,y))
}


Mondatszerű leírása:
"Ismételd: x értéke legyen random(room_width) és y értéke legyen random(room_height), amíg place_free(x,y) értéke igazzá nem válik."

- Számlálós ciklus (for): hasonlít a "Repeat" cilusra; megadott kezdőértéktől megadott végértékig megadott lépésközzel hajtja végre az utasítás(oka)t.
Alakja: for (<utasítás1> ; <kifejezés> ; <utasítás2>) <utasítás3>

Az utasítás1-ben állítjuk be a ciklusváltozó kezdőértékét, a kifejezés-ben adjuk meg a végértéket, az utasítás2-ben a lépésközt, az "utasítás3" pedig maga a végrehajtandó utasítás.

Pl. a következő program feltölti a "tomb" nevű tömböt 1-től 10-ig számokkal:

{
for (i=0; i<=9; i+=1) tomb[i] = i+1;
}


A kezdőérték 0 és a ciklus addig fut, amíg a ciklusváltozó el nem éri a 9-et. A lépésköz (mely a ciklusváltozó értékét növeli vagy csökkenti - jelen esetben növeli) értéke 1. A ciklusváltozó és a tömbindex ugyanaz (i).
Mi is történik:
a ciklus indulásakor a ciklusváltozó (i) értéke 0, a tömb első (i-edik, tehát most 0-dik) eleme i+1, vagyis 0+1, azaz 1. ha ez kész, a ciklusváltozó értéke megnő a lépésközben megadott értékkel (jelen esetben i+=1, azaz 1-gyel), értéke tehát 1 lesz. Mivel a tömbindex jele is az "i", ezért annak értéke is 1 lesz, ezért a tömb második (i-edik, tehát most első) eleme i+1, vagyis 1+1, azaz 2.
Ez így megy tovább, míg a ciklusváltozó értéke el nem éri a 9-et, ekkor a kilencedik tömbelem (ami valójában a tizedik, hiszen nulláról indult a sorszámozása) értéke a 10 lesz.

Mindegyik ciklusra igaz, hogy ha a ciklusmagban egynél több utasítást kell végrehajtani, akkor azokat kapcsos zárójelek között kell felsorolni.


7. A BREAK UTASÍTÁS:

A for, while, repeat ciklusokon, a switch elágazáson és a with utasításon belül használva
kiléphetünk ezekből (pl. ha megvan a keresett érték, akkor ne fusson fölöslegesen tovább a ciklus).
Ezenkívül az adott program (de nem a teljes játék) befejezésére is használható.
Alakja: break


8. A CONTINUE UTASÍTÁS:

A for, while, repeat ciklusokon és a with utasításon belül használva folytatja azok futtatását a következő értékükkel.
Alakja: continue


9. AZ EXIT UTASÍTÁS:

Befejezi a program végrehajtását (de nem a játékét, arra a game_end() függvény való).
Alakja: exit


10. FÜGGVÉNYEK:

Előfordulhat, hogy bizonyos programsorokat többször is szerepeltetni kell egy programon belül, vagy ugyanazt más programban is. A többszöri gépelés helyett érdemesebb ezen programoknak külön nevet adni és amikor szükség van rá, csak ezt a nevet beírni a hívásához. Az így megírt programsor(oka)t nevezik függvénynek.
A GML rengeteg beépített függvényt tartalmaz, de a saját magunk által megírt programsorok is függvénynek minősülnek, ha az "Add a script" mód szerint írtuk meg.
Alakjuk a GML-ben: <függvénynév>(<paraméter1>,<paraméter2>,...)

A paraméterek azok a kívülről kapott adatok, amelyekkel a függvény dolgozik. Ezeket a függvénynév után, zárójelek között kell megadni. Ha egy függvénynek nincs szüksége bemenő adatokra (pl. mert csak utasításokat hajt végre) akkor is ki kell tenni a függvénynév után két üres zárójelet, mint ahogy pl. a fentebb említett game_end()-nél (régebbi programnyelveknél az ilyet eljárásnak nevezték).
Minden függvény 16 paramétert (0-15) használhat (az "Execute a script"-tel hívva csak 5 állítható be az argument0 - argument4 szövegdobozokban, és ha csak így hívjuk és nem GML kódból, akkor ékezetes betűt is tartalmazhat a neve).
A GML beépített változói (pl. mouse_x) természetesen mindenütt elérhetőek, így az egyes argumentumokhoz sem kell hozzárendelni, ha függvényben kerülnek alkalmazásra.

Pl. készítsünk egy "szoroz" nevű függvényt, mely a bemenő adatként kapott két számot szorozza össze:
Az "Add a script"-re kattintva megkapjuk a szerkesztőablakot, melybe a következőket kell begépelnünk:

{
eredmeny=argument0*argument1
return eredmeny //A return utasítás magyarázata a 11. pontban olvasható
}


Névnek a már említett "szoroz"-t adjuk.
Ha a "Code" - "Execute a script"-tel rendeljük egy objektumhoz, akkor a "Script" szövegdoboz melletti gombra kattintva kereshetjük ki a "szoroz" függvényt, az argument0 és argument1 szövegdobozokba pedig a megfelelő számot vagy változót kell beírni.
Az "Execute a piece of code"-ban vagy a Room "Creation code"-ban a már bemutatott alakban hívható, vagyis a neve és utána zárójelek közt a paraméterei, pl.

...
egyik=5; masik=8
szoroz(egyik,masik)
...


Fontos megjegyezni, hogy egy hozzárendelés bal oldalán soha nem szerepelhet függvény. Pl. ahelyett, hogy
instance_nearest(x,y,obj).speed = 0
a következőt kell írni:
(instance_nearest(x,y,obj)).speed = 0.


11. A RETURN UTASÍTÁS:

Egy függvény elkészítésénél gyakran szükség van arra, hogy számításainak eredményei elérhetőek legyenek a futása végeztével.
A "return" utasítás szolgál arra, hogy a függvény visszatérjen egy értékkel. Ennél az utasításnál a függvény végrehajtása befejeződik.
Alakja:
return <kifejezés>

Pl. ez a kis függvény (nevezzük pl. negyzetre-nek) kiszámolja a paraméter négyzetét:

{
return (argument0*argument0);
}


Felhasználása pl.: "if negyzetre(5)==..."


12. A WITH UTASÍTÁS:

Az előzőekben már láthattuk, hogyan kell az objektumok változóinak értékeit kiolvasni és megváltoztatni. De számos esetben egyszerre sokmindent kell csinálni az adott objektummal, vagy az összes létező példányával is.
Tételezzük fel, hogy az összes labdát 8 képponttal kell lefelé mozgatni. Gondolhatnánk, hogy ezt a következő utasítással érhetjük el:
labda.y = labda.y + 8;

De ez nem jó. A hozzárendelés jobb oldalán kapja az első labda y koordinátája az értéket, amihez hozzáadódik 8. Ez az új érték beállítja az összes labda y koordinátáját. Ennek következtében minden labda ugyanazt az y koordinátát kapja, vagyis attól függetlenül, hogy mi volt az y koordinátájuk előző értéke, most mind egy vonalba kerülnek.
A labda.y += 8; utasítással ugyanez a helyzet, hiszen ez csak az előző rövidítése.
Erre megoldás a "with" utasítás, melynek alakja:

with (<kifejezés>) <utasítás>

A "kifejezés" jelöli a tárgyat vagy tárgyakat, ez lehet az azonosítója (instance id), a neve vagy különleges objektumok (all, other, stb.).
Tehát példánk helyes megoldása:
with (labda) y += 8;

Ha nem egy, hanem több utasítást akarunk végrehajtatni, akkor ezeket kapcsos zárójelek közé kell rakni. A következő példa az összes labdát véletlenszerű x és y koordinátákra helyezi:

with (labda)
{
x = random(room_width);
y = random(room_height);
}


Fontos tudni, hogy az utasítás(ok)on belül a jelzett objektum válik azzá, amire a "self" (önmaga) vonatkozik, az eredeti pedig a többivé.
Így például ahhoz, hogy az összes labda oda kerüljön, ahol az aktuális van, a következő programsor használandó:

with (labda)
{
x = other.x;
y = other.y;
}


Ezen kívül a "with" utasítás még sokmindenre használható.
Például az összes labda megsemmisítése:

with (labda) instance_destroy();
Az összes tárgy megsemmisítése adott távolságon belül (pl. egy bomba felrobbanásakor):

with (all)
{
if (distance_to_object(other) < 50) instance_destroy();
}



13. ÁLLANDÓK:

A változókkal ellentétben ezek értéke mindig állandó marad a program futása során.

A GML-ben ezek:

true - (Igaz) Értéke 1.
false - (Hamis) Értéke 0.
pi - Értéke 3.1415...

^Tartalom^- - - Következő oldal »