^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...