Friday 29 April 2011

Monikerroksinen karttaformaatti

Tänään hahmotin koulussa miltä neliö näyttää! Tämä tarkoittaa että MEMAPPER Beta 5n julkaisu lähenee, kunhan olen toteuttanut neliöt parin muuhunkin työkaluun.

Mutta, olen tehnyt koodauksen ohella mietiskelyä otsikon esittämästä aiheesta. Tätä mietiskelyä pitäisi sitten jäsentää blogiin, ja koska tämä tieto on tärkeää sekä allekirjoittaneelle että MERPGin tilesettien tekijöille, erotan teksteissä koodirelatiivisen ja tilesettien tekijöitä kiinnostavan osan, koska olen huomannut että tilesettien tekijät eivät jaksa/halua lukea tekstiä joka liittyy liikaa ohjelmointipuoleen. Alkuun siis tilesettereitä (mikä termi...) kiinnostava osa.

Mikä idea on toteuttaa toinen layer karttadatan ja hitdatan päälle?

Karttadata-kerros olisi varattu maastolle. Se ei tue maskiväriä (0,0,0/#000000), eli läpinäkyvyyttä, ja se olisi varattu lähinnä maastotileille. Toisesta kerroksesta eteenpäin layerit tukisivat maskiväripohjaista läpinäkyvyyttä, ja nämä olisi tarkoitettu tileille jotka esittävät objekteja joita voi löytyä maastosta. Lisäksi maskiväripohjainen läpinäkyvyys helpottaa tilesettien tekijöiden elämää todella paljon.





Yllä on eräs keskivanha tilesetti, jonka teimme eräänä Yönä MEMAPPER Beta 2:n tai Beta 3:n aikaan. Teknisesti tuon tilesetin oikeudet kuulunevat Tässille, koska hän tuon teki ja minä kommentoin vieressä, mutta oletan nyt itsekkäästi ettei häntä haittaa vaikka käytän tätä kuvaa esimerkkinä :P

Tuossa tilesetissä näkyy selvä ongelma. Siinä on vettä, kalliota ja ruohoa. Mitä jos karttaan haluttaisiin tehdä ranta? Ranta vaatii tietysti maata ja vettä monissa erilaisissa kulmissa; nuo 8 reuna-/kulmatileä eivät muistaakseni riittäneet sujuvaan karttatyöskentelyyn. Lisäksi nämä reilu 8 tileä pitää toteuttaa jokaiselle maastotyypille erikseen! Leikitään että meillä on viisi maastotyyppiä, joiden kaikkien välille pitää toteuttaa tuollaisia "rantoja". Se tekisi vähintään 8*5*8 + 5 (eli 325) tileä. Turha varmaan edes mainita, että ilman erikoislaatuisia käyttöliittymäratkaisuja MEMAPPER ei taivu tuollaiseen. Tilejen määrä moninkertaistuu aina kun tilesettiin lisätään uusi maastotyyppi.

Jos pohjakerroksen päällä  maskiläpinäkyvyyttä tukevia kerroksia, voitaisiin ylläolevaa tilesettiä muuttaa niin, että jokaisesta maastotyypistä tehtäisiin tuollaiset kulmapalat, ja sen sijaan että tilesettiä tehdessä liimattaisiin maastokulmia maastopalojen päälle, liimattaisiin ne vasta MEMAPPERissa.

Monikerroksinen rakenne mahdollistaisi muitakin kikkailuja. Parille ensimmäiselle kerrokselle voitaisiin rakentaa tilen maasto, ja ylemmälle voitaisiin asettaa kartan kannalta relevantti objekti, joka ei kuitenkaan ole niin tärkeä että sitä kannattaisi pelin puolella ladata. Hyvänä esimerkkinävaikka aita, jonka yli ei tietenkään pelissä saa kulkea, mutta jonka erillinen lataaminen pelissä olisi lähinnä typerää.

Mitä tämä toteutus vaatii koodarin näkökulmasta?

Karttatiedoston rakenne ainakin muuttuu. Tällä hetkellä karttatiedoston ensimmäiset kolme tavua ilmaisevat kartan version, kartan leveyden tileinä ja kartan korkeuden tileinä, sitten alkaa karttadata. Uudessa tiedostorakenteessa tiedoston neljäs tavu ilmaisisi karttalayereiden lukumäärää, ja ensimmäisen EOS-tavun (FF/255) jälkeen ei alakaan hit-data, vaan seuraava layer. Ohjelmien pitäisi siis pitää kirjaa montako EOS-tavua on tullut tiedostovirrassa vastaan, ja näin laskea monetta layeriä renderöidään. Eli kahden EOS-tavun sijasta karttatiedostosta pitäisi löytyä layereiden_määrä+1 EOS-tavua (+1 siitä että hitdatakin päättyy EOS:ään).

Tietorakenteiden puolella tämä monilayerisyys on helppo toteuttaa. Ne mitkä olivat ennenvanhaan kaksiulotteisia listoja/vektoreita karttaluokissa, muuttuvat kolmiulotteisiksi. Näin tietyn tilen arvoon viitattaisiin (x,y,z)lla missä x ja y ovat vanhaa kauraa, ja z viittaa layerin järjestysnumeroon. Z:n kanssa pitää huomata että origo on todennäköisesti ruudulla, eli alin layer on tiletaulukko[x][y][maxZ-1] eikä tiletaulukko[x][y][0]. Jos joku hämääntyy C/Java - taulukkonotaatiosta, sama kolmiulotteisella CB-taulukolla olisi tiletaulukko(x,y,z_arvo).

Thursday 28 April 2011

Jos tiput, otan kopin

Edellinen keikka-arvio lienee tässä. Joulun keikasta ei pitäisi olla arviota olemassa.

Joka tapauksessa, eilen oli Sonata Arctican keikka Helsingin Nosturissa. Mitä olin kiertueen edellisiltä keikoilta lukenut, tiesin odottaa klassikoita lavalta. Noh, keikka alkoi Flag in the Groundilla klo 21. Tätä seurasi pari muuta Days of Graysin klassikkoa, Last Amazing Grays ja Juliet muistaakseni. Tonin spiikit olivat ikivihreitä ja biisit kuulostivat hemmetin hyvältä. Pian näiden jälkeen saatiin yllätys: Blank File, Ecliptican eka biisi. Näin yleisön jäsenenä on sanottava että kyseinen kappale kuulostaa helvetin hyvältä livenä.

Emme kuulleet Black Sheepiä, nyyh, ja pari muutakin klassikkoa taisi jäädä väliin, mutta shown puolivälissä lavasta tehtiin akustinen. Kuulimme Mary-Loun, kuulimme Shyn ja kuulimme Danan. Yleisö piti tästä tehotriosta. Lempibiisini shown alkupuolelta on kuitenkin jäänyt mainitsematta: THE MISERY! Tämä jokaisen pöytälaatikkokirjoittajan lempibiisi oli herkkä kuin nörtti jouluna, ja koko yleisö antautui biisin valtoihin.

Shown toisella puolella, akustisen osuuden jälkeen, alkoi tilutus. Kun naisääni alkoi lausua vuorosanojaan, sali räjähti. Victoria's Secretissä yleisö oli hieman mukana, akustiset vedot ja misery vetivät yleisön aivan kyyneliin, mutta mikään näistä ei vetänyt vertoja Calebille. Nekin jotka olivat olleet koko konsertin aivan paikallaan, alkoivat pomppia ja \m/:ttää. Minä kuitenkin pysyin aivan rauhallisena - tai sitten en. Caleb on nimittäin yksi parhaista, ja biisi jonka olisin halunnut kuulla jo Tampereella viime vuoden helmikuussa. Biisin jälkeen tuli vielä Don't Say A Word ja Vodkatarjoilu.

Täytyy sanoa että tälläisille keikoille pääsee kerran 12 vuodessa.

Tuesday 19 April 2011

Beta 5 ja sellaiset

Julkaisin viime perjantaina Memapper Beta 4n, jossa resize-ikkuna kasvatti ja pienensi karttaa mitenpäin vain. Beta 5 tuo suunnitelmien mukaan toisi työkaluikkunan, "hot-plugattavat" työkalut, ja jonkin leikepöytätoiminnallisuuden. Työkaluikkunan toteutin jo Beta 4,5een, julkaistu Fairandcruelissa (ajatuksia kaivataan!), ja seuraavaksi pitäisi toteuttaa työkalurajapinta ja sen päälle pari toimivaa työkaluluokkaa. Jos jaksaisin alkaa kikkailemaan ja opiskelemaan Javan Reflektioapia, voisin toteuttaa oikeasti hotplugattavat työkalut, jotka toimivat niin että käyttäjä koodaa työkaluluokan, joka implementoi TOOL-rajapinnan View-luokan sisään, ja pudotetaan käännettynä extensions - kansioon, josta MAPPER ottaa työkalun käyttöön.

Tämän rajapinnan kautta olisi helppo toteuttaa loput tarvittavat työkalut. Rajapinta tosin vaatii vielä suunnittelua...

Thursday 14 April 2011

TOLPPA

Tolppa, eli pylväs, ja tässä tapauksessa sellainen roomalainen pylväs joka ilmaisee paljonko matkaa on kuljettu. Suomeksi siis ihan virstanpylväs, joka on nyt saavutettu MERPGissä. Meillä on nyt näyttöluokka, jonka periyttämällä saa melko CB:mäisen käyttötuntuman. Tuo luokka osaa piirtää tekstiä annettuun sijaintiin, ja koska teksti annetaan text()-funktiolle std::string - viittauksena, voi tekstin koota suoraan kutsuun seuraavasti:
Text(0,10,"HiiriX: "+hiiriX()+"   hiiriY:"+hiiriY()); //Tyyli on..... lainattu cb-foorumilta, jos näin ei saisi tehdä, on blogissa vieraskommentointi syystä sallittu
Eli parametriin voi asettaa kaikkia niitä tietotyyppejä, joille on ylikuormitettu + - operaattori std::stringissä. Toiminnallisuus on siis paljon kivempi kuin const char* - teksteissä, jotka eivät tue minkäänlaisia kikkailuja, ja sitäkin huonosti.

Lisäksi näyttöluokka ainakin taipuu samanlaiseen piirtelyyn kuin CB:n piirtelyapi,  jos en ole näitä funktioita jo toteuttanut. Luokan getObject/-Anim/-Map - funktiot taas luovat pyydetyn olion, lisäävät siitä osoittimen näyttöluokan piirtojonoon (joka on oikeasti vektori, mutta kun kerran sille on jono - lempinimen antanut niin se sillä pysyy), ja palauttavat tämän osoittimen käyttäjälle. Piirtojono mahdollistaa sen, että kun DrawScreeniä (kyllä, tämä CB-funktioiden apinointi on ihan tarkoituksenmukaista :D lukekaa loppuun) kutsutaan, se piirtää ensin piirtojonon jäsenet takapuskuriin, ja sitten flippaa puskureita. Eli suomeksisanottuna, käyttäjän ei tarvitse erikseen piirtää jokaista lataamaansa kuvankaltaista näytölle, koska koneen voi laittaa tekemään se automaattisesti.

Koska Text - komento ja objektit aiheuttavat ongelmia jo CB:ssä, toteutin näyttöluokkaan myös DrawGame()n, joka piirtää piirtojonon takapuskuriin, jonka jälkeen käyttäjä voi piirtää tekstinsä pelkäämättä että objektit piirtyisivät niiden päälle. Ilman DrawGamea tilanne olisi se, että ensin pääluupissa käyttäjä piirtää tekstejä innoissaan, ja sitten kutsuu DrawScreeniä, joka piirtää objektit ruudulle - suoraan tekstien päälle.

Piirtojonon-rakenteen huono puoli on siinä että käyttäjä ei voi vaikuttaa piirtojärjestykseen muuten kuin lataamalla mediansa oikeassa järjestyksessä (kuvien pointterit lisätään piirtojonoon latausjärjestyksessä). Jos olisin oikein viisas, vaihtaisin piirtojono - vektorin joksikin muuksi tietorakenteeksi, ehkä listaksi, joka mahdollistaa A) läpi-iteroinnin ja B) karttojen asetuksen piirtojonon ensimmäisiksi piirrettäviksi ja muiden asettamisen jonon (LISTAN!!!) loppuun.


Ja niin, onhan meillä muitakin luokkia. Näyttöluokan sisällä koodaavalle kiinnostavia luokkia ovat MEOBJEKTI, MEMAP ja ärsyttävän epäjohdonmukaisesti nimetty ANIMAATIO. Nuo perivät samoja kantaluokkia, joten niiden käyttö on melko samanlaista. Oikeastaan ANIMAATIO ja MEMAP perivät objektiluokan, joten piirtojono oli johdonmukaista toteuttaa MEOBJEKTI* - tyyppisenä rakenteena. Eli jos osaat käyttää MEOBJEKTIA, eivät animaatio ja kartta ole vaikeita. Mitään näistä ei voi suoraan luoda, vaan näyttöluokka hoitaa luonnin, ja siltä saa pyydettyä getObject/-Anim/-Map - funktioilla pointterit uusiin olioihin. Käyttäjälle saattaisi olla ehkä fiksumpaa tarjota viittaus olioihin, mutta en usko että kukaan luokan käyttäjä on niin tyhmä että menee seuraavaan ansaan:

MEOBJEKTI* objekti = getObject("opjekti.bmp");//tee jotain opjektilleobjekti = jotain_muuta;

Kuka tahansa pelkkää CB:täkin koodaillut tajuaa että tässä menee väärin. Siksi en ala avaamaan miksi tämä on väärin, vaan annan seuraavan CB-koodin:


ukkeli = LoadObject("opjekti.bmp")'tee jotain ihmeellisyyksiä objektille
ukkeli = LoadObject("Anööther opjekti")

Tämä on siis klassinen muistivuoto, objektin osoitin hukataan ja objekti jää ikuisesti seilaamaan halki kartoittamattoman RAM-meren. Tämä on ainoa muistinkäytöllinen asia, josta käyttäjän on huolehdittava näyttöluokan sisällä, sillä näyttöluokka varaa puoliautomaattisesti tarvittavan muistin ja vapauttaa myös.

Esittelen noita luokkia myöhemmin lisää :P nyt lähden kouluun

Sitäpaitsi, jos joku ei vastusta, saatan kirjoittaa Fairandcrueliin tuton siitä, kuinka helppoa näyttöluokan sisällä koodailu on.

Wednesday 6 April 2011

Aprillia, kuten sanotaan

Jos joku ei ole sitä tähän mennessä arvannut, edellinen posti oli sitä aprillia.

Julkaisin MEMAPPERista kolmannen Betan, osoite, saa antaa kommentteja ja ajatuksia :P Pitäisi varmaan saada julkaistua pelimoottoristakin joku pikkurelease, joka demonstroi miltä nuo kartat näyttävät pelin puolella.

Friday 1 April 2011

SE OLI SIINÄ

Animaatiomoottori on nyt valmis, ongelma sen takana oli että väärinkäytin muistia. Lisäsin framejen väliin hieman viivettä, ja nyt animaatiot toimivat kuten odottaa sopii.

Olen koko aamun tuottanut proof of concept - tilesettejä, ja tämän tekstin jälkeen toteutan pari karttaa. Sitten iltapäivän aikana toteutan MEMAPperin lähdekoodin pohjalta toimivan, muttei lopullisen, animaattorin ja luon MERPG:in kolmiosta pari animaatiota. Sen jälkeen, kotona, isken moottoriin Smaragdikaupungista tehdyn luonnoskartan, ja tälle kolmion kuljeskelemaan vapaasti kartan sisällä. Tästä se kivuus sitten alkaakin, kun pitää toteuttaa kaupat, item-systeemi, iskut, taistelut, sisätilat, portaaton kulkeminen kartalta toiselle jne. Kuulette ensimmäisestä Betasta viimeistään huomenissa :P

Lisäksi, oli hyvä ratkaisu alkaa kehittämään MERPGiä C++lla ja Javalla, koska CB koki loppunsa :(