Reittisuunnittelu

Reittisuunnittelu auttaa tiettyjen instanssien paikasta toiseen liikuttamisessa niin, että se välttelee törmäyksiä tiettyjen muiden instanssien (kuten seinien) kanssa. Reittisuunnittelu on myös vakava ongelma. On nimittäin mahdotonta antaa yleisiä funktioita, jotka toimivat kaikissa tilanteissa oikein. Törmäysvapaiden liikeratojen laskeminen on myös aikaavievä operaatio. Niiden käyttämisessä tulee siis miettiä, miten ja milloin niitä kannattaa käyttää. Pidä nämä huomion arvoiset seikat mielessä, kun käytät seuraavia funktioita.

Game Maker tarjoaa monenlaisia reittisuunnittelufunktioita. Niistä yksinkertaisin laittaa instanssin kulkemaan askeleen eteenpäin kohdetta kohti suoraa reittiä, mutta tarpeen mukaan muuttaen suuntaa. Näitä funktioita tulisi käyttää instanssin askeltoiminnossa (Step). Ne vastaavat reittisuunnittelufunktioita, jotka ovat myös tarjolla:

mp_linear_step(x,y,stepsize,checkall) Tällä funktiolla instanssi ottaa askeleen määritettyä pistettä (x,y) stepsize määrää askeleen koon. Jos instanssi on jo pisteessä, se ei liiku enää edemmäs. Jos checkall on tosi, instanssi pysähtyy, kun se törmää mihin tahansa muuhun objektin instanssiin. Muulloin se pysähtyy vain, kun se törmää kiinteään (solid) instanssiin. Huomaa, että tämä funktio ei yritä käyttää kiertoteitä, kun se törmää esteeseen. Se vain pysähtyy. Funktio palauttaa totuusarvon, joka ilmoittaa, pääsikö instanssi määritettyyn pisteeseen.
mp_linear_step_object(x,y,stepsize,obj) Sama kuin ylempi funktio, mutta tällä kertaa vain arvoa obj vastaavat instanssit lasketaan esteiksi. obj voi olla joko objekti tai instanssin id.
mp_potential_step(x,y,stepsize,checkall) Kuten edellisellä funktiolla, tämälläkin funktiolla instanssi ottaa askeleen kohti tiettyä sijaintia. Tässä tapauksessa se kuitenkin yrittää välttää esteitä. Kun instanssi olisi törmäämässä kiinteään instanssiin (tai mihin tahansa instanssiin, kun checkall on tosi), se muuttaa suuntaansa yrittäen väistää instanssia ja kiertää sen ohi. Tämän reitinsuunnittelutavan toiminta ei aina toimi, mutta helpoimmissa tilanteissa instanssi liikkuu tehokkaasti kohti tavoitepistettänsä. Funktio palauttaa totuusarvon, joka ilmoittaa, pääsikö instanssi määritettyyn pisteeseen.
mp_potential_step_object(x,y,stepsize,obj) Sama kuin ylempi funktio, mutta tällä kertaa vain arvoa obj vastaavat instanssit lasketaan esteiksi. obj voi olla joko objekti tai instanssin id.
mp_potential_settings(maxrot,rotstep,ahead,onspot) Seuraavien kahden funktion toiminta perustuu useaan parametriin, joiden arvoja voi muuttaa tällä funktiolla. Yleisesti reittisuunnittelu toimii seuraavasti: ensin instanssi yrittää liikkua suoraan kohdepistettä kohti. Tämä tarkistetaan tietyn askelmäärän päähän, jota vastaa parametri ahead (oletusarvo 3). Tämän arvon pienentäminen tarkoittaa, että instanssi alkaa muuttaa suuntaansa myöhemmin. Sen suurentaminen taas tarkoittaa, että suuntaa aletaan muuttaa jo aiemmin. Jos tämä tarkistus johtaa törmäykseen, instanssi alkaa tarkistaa parhaasta reitistä enemmän vasemmalle ja oikealle poikkeavia teitä. Tämän se tekee askelilla, joiden koko on rotstep (oletusarvo 10). Tämän pienentäminen antaa enemmän liikkumismahdollisuuksia, mutta on hitaampaa. Parametri maxrot on vähän vaikeampi selittää. Instanssillahan on nykyinen suunta. maxrot (oletusarvo 30) ilmoittaa, kuinka paljon instanssi saa muuttaa nykyistä suuntaansa askeleen aikana. Joten jos instanssi voi liikkua esim. suoraan maaliin, se tekee niin vain, jos se noudattaa tätä enimmäissuunnanmuutosta. Jos annat maxrotille suuren arvon, instanssin liikesuunta voi muuttua paljon askeleen aikana. Tällöin lyhyen reitin löytäminen helpottuu, mutta polku tulee olemaan rumempi. Jos taas asetat sen arvoksi pienen arvon, polusta tulee sulavampi mutta se voi käyttää pitempiä kiertoteitä, eikä välttämättä edes löydä kohdesijaintiansa. Kun askelta ei voi ottaa mihinkään suuntaan, seuraava käyttäytymistapa riippuu parametrista onspot. Jos onspot on tosi (oletusarvo), instanssi kääntyy paikallaan maxrotin määräämän määrän. Jos se on epätosi, instanssi ei liiku lainkaan. Sen asettaminen epätodeksi voi olla hyödyllistä esim. autojen kanssa, mutta se pienentää reitin löytämismahdollisuutta.

Huomaa, että tämä potentiaalinen lähestymistapa käyttää vain paikallista tieto. Se löytää siis polun vain, jos tätä paikallista tietoa on tarpeeksi oikean liikesuunnan päättelemiseksi. Se siis esimerkiksi (suurimmassa osassa tapauksista) epäonnistuu löytämään polkua ulos sokkelosta.

Toinen funktioiden tyyppi laskee instanssille törmäysvapaan polun. Kun tämä polku on laskettu, voit liittää sen instanssille, jolloin se voi seurata sitä päästäkseen kohteeseensa. Polun laskeminen vie vähän aikaa, mutta sen jälkeen sen seuraaminen on nopeaa. Tämä toimii tietysti vain, kun tilanne ei muutu. Jos esteet siis esimerkiksi muuttuvat, voi olla, että polku täytyy laskea uudestaan. Huomaa myös, että myöskään nämä funktiot eivät välttämättä toimi aina. Nämä funktiot ovat käytettävissä vain Game Makerin Pro-versiossa!

Kaksi ensimmäistä funktiota käyttävät lineaariseen liikkeen ja potentiaalisen kentän lähestymistapaa, joita käytettiin myös askelfunktioissa.

mp_linear_path(path,xg,yg,stepsize,checkall) Tämä funktio laskee suoraviivaisen polun instanssille sen nykyisestä pisteestä pisteeseen (xg,yg) käyttämällä annettua askelkokoa. Se käyttää askeleita kuten funktio mp_linear_step(). Ilmoitetun polun on oltava olemassa ja uusi polku kirjoitetaan sen päälle. (Myöhemmissä luvuissa on tietoa polkujen luomisesta ja tuhoamisesta.) Funktio palauttaa totuusarvon, joka ilmoittaa, löytyikö polku. Funktio pysähtyy ja ilmoittaa epäonnistumisesta, jos alun ja päämääränä olevan pisteen välille ei voi tehdä suoraa polkua. Jos se epäonnistuu, se luo silti polun, joka jatkuu pisteeseen, jossa törmäys sattui, asti.
mp_linear_path_object(path,xg,yg,stepsize,obj) Sama kuin ylempi funktio, mutta tällä kertaa vain arvoa obj vastaavat instanssit lasketaan esteiksi. obj voi olla joko objekti tai instanssin id.
mp_potential_path(path,xg,yg,stepsize,factor,checkall) Tämä funktio laskee polun instanssille sen nykyisestä pisteestä ja suunnasta pisteeseen (xg,yg) käyttämällä annettua askelkokoa ja vältellen törmäyksiä esteiden kanssa. Se käyttää potentiaalisia kenttäaskeleita kuten funktio mp_potential_step() ja myös niitä parametreja, jotka voi muuttaa funktiolla mp_potential_settings(). Ilmoitetun polun on oltava olemassa ja uusi polku kirjoitetaan sen päälle. (Myöhemmissä luvuissa on tietoa polkujen luomisesta ja tuhoamisesta.) Funktio palauttaa totuusarvon, joka ilmoittaa, löytyikö polku. Jotta polkua ei laskettaisi ikuisesti, pituuskertoimeksi factor on annettava suurempi arvo kuin 1. Funktio pysähtyy ja ilmoittaa epäonnistumisesta, jos se ei löydä lyhyempää reittiä kuin tämä kerroin kerrottuna alku- ja loppupisteiden etäisyydellä. Yleensä kerroin 4 on tarpeeksi hyvä, mutta jos odotat pitkiä kiertoreittejä, voit antaa sille suuremmankin arvon. Jos se epäonnistuu, se luo silti polun, joka liikkuu kohdepistettä kohti, mutta ei saavuta sitä.
mp_potential_path_object(path,xg,yg,stepsize,factor,obj) Sama kuin ylempi funktio, mutta tällä kertaa vain arvoa obj vastaavat instanssit lasketaan esteiksi. obj voi olla joko objekti tai instanssin id.

Muut funktiot käyttävät monimutkaisempaa mekanismia, joka toimii ruudukkopohjaisella periaatteella (tästä käytetään joskus nimeä A*-algoritmi). Se löytää polkuja helpommin ja sen löytämät polut ovat lyhyempiä, mutta vaatii enemmän työtä tekijältä. Yleisidea on seuraava: ensiksi huoneen (tai tietyn osan huonetta) päälle laitetaan ruudukko. Voit valita, haluatko käyttää tarkkaa (joka on hitaampi) vai epätarkkaa ruudukkoa. Sitten kaikki ruudut, joissa valitut objektit ovat ainakin osittain, etsitään (käyttämällä joko raja-alueita tai tarkkaa tarkistusta) ja merkitään kielletyiksi. Koko ruutu merkitään siis kielletyksi aina, vaikka este vain osittain olisi sen päällä. Sitten määritetään alku- ja loppupisteet (joiden on oltava vapaissa ruuduissa) ja funktio laskee lyhimmän (oikeastaan lähes lyhimmän) polun näiden välille. Jos siis ruudut ovat niin isoja, että instanssi mahtuu kokonaan yhden ruudun sisälle, tämä toimii. Sitten voit antaa tämän polun instanssille seurattavaksi.

Ruudukkopohjainen lähestymistapa on tehokas (ja sitä käytetään monissa laatupeleissä), mutta se vaatii tekijältä huolellista ajattelua. On päätettävä, mikä alue ja minkä kokoiset ruudut toimivat parhaiten pelin läpäisemiseksi. On myös päätettävä, mitä objekteja vältetään ja että onko tarkka törmäystarkistus tärkeää. Kaikki nämä parametrit vaikuttavat vahvasti tämän tavan tehokkuuteen.

Erityisesti ruutujen koko on tärkeä. Muista, että solujen on oltava tarpeeksi suuria, että liikkuva objekti mahtuu kokonaan ruudun sisälle silloin, kun sen origo on keskellä solua. (Ole varovainen objektin origon sijainnin kanssa. Huomaa myös, että voit siirtää polkua, jos objektin origo ei ole sen keskellä!) Toisaalta, mitä pienempiä ruudut ovat, sitä enemmän mahdollisia polkuja on olemassa. Jos teet ruuduista liian suuria, esteiden välissä olevat välit voivat sulkeutua, koska kaikissa ruuduissa on silloin este.

Itse ruudukkomalliseen lähestymistapaan käytettävät funktiot ovat seuraavat:

mp_grid_create(left,top,hcells,vcells,cellwidth,cellheight) Tämä funktio luo ruudukon. Se palauttaa indeksin, jota on käytettävä kaikissa muissa kutsuissa. Voit luoda ja hallita useita ruudukkorakenteita samanaikaisesti. left ja top määrittelevät ruudukon ylävasemman nurkan sijainnin. hcells ja vcells määräävät vaaka- ja pystysuuntaisten ruutujen määrän. Lopuksi cellwidth ja cellheight määräävät ruutujen koon.
mp_grid_destroy(id) Tuhoaa ruudukon, jolla on annettu id, ja vapauttaa kaiken sen varaaman muistin. Älä unohda kutsua tätä, kun et enää tarvitse ruudukkoa.
mp_grid_clear_all(id) Merkitsee kaikki ruudukon ruudut vapaiksi.
mp_grid_clear_cell(id,h,v) Tyhjentää ilmoitetun ruudun. Ruutu 0,0 on ylävasen ruutu.
mp_grid_clear_rectangle(id,left,top,right,bottom) Tyhjentää kaikki ruudun, jotka leikkaavat määrätyn neliön (huonekoordinaatteina) kanssa.
mp_grid_add_cell(id,h,v) Merkitsee ilmoitetun ruudun kielletyksi. Ruutu 0,0 on ylävasen ruutu.
mp_grid_add_rectangle(id,left,top,right,bottom) Merkitsee kielletyiksi kaikki ruudut, jotka leikkaavat määrätyn neliön kanssa.
mp_grid_add_instances(id,obj,prec) Merkitsee kaikki solut, jotka leikkaavat ilmoitetun objektin instanssien kanssa, kielletyiksi. Voit myös käyttää yksittäistä instanssia asettamalla instanssin id-arvon obj:ksi. Lisäksi voit käyttää avainsanaa all, jolloin tämä koskee kaikkien objektien instansseja. prec ilmaisee, käytetäänkö tarkkaa törmäystarkistusta (toimii vain, jos tämä on sallittu instanssin käyttämän kuvan asetuksista).
mp_grid_path(id,path,xstart,ystart,xgoal,ygoal,allowdiag) Laskee polun ruudukon läpi. Ilmoitetun polun on oltava olemassa ja uusi polku kirjoitetaan sen päälle. xstart ja ystart vastaavat polun alkupistettä ja xgoal ja ygoal sen loppupistettä. allowdiag määrää, onko myös viistottainen liike sallittu vaaka- ja pystysuuntaisen liikkeen lisäksi. Funktio palauttaa totuusarvon, joka ilmoittaa, löytyikö polku. (Huomaa, että polku on riippumaton nykyisestä instanssista; se on polku ruudukon läpi, ei polku tietylle instanssille.)
mp_grid_draw(id) Tämä funktio piirtää ruudukon näytölle, näyttäen vapaat ruudut vihreinä ja kielletyt punaisina. Tämä funktio on hidas ja on olemassa vain testauskäyttöä varten.