#include <conio.h> #include <stdlib.h> #include <iostream.h> void GenerateLevel(void) { int a; int b; for (a=1;a<80;a++) { for (b=1;b<25;b++) { gotoxy(a,b); cprintf("#"); } } } int main(void) { GenerateLevel(); }
Koodi toimii kyllä niinkuin pitää, eli täyttää näytön #-merkeillä, mutta merkkien kirjoittamisen ehtii nähdä ja se tapahtuu vielä hitaammin kuin QBasicissa. Kysyisin, että minkä vuoksi, ja miten sen saa nopeammaksi, sillä pakkohan tähän on jokin keino olla. Eihän C++ nyt QB:tä hitaampi voi olla. Käytössä on sitten Borland-kääntäjä, jos sillä on jotain merkitystä.
No en sitten tiedä, mutta voisi ehkä generoida ensin tuon levelin johonkin bufferiin ja sitten tulostaa sieltä. Sitten tietysti voisi cprintfin sijasta kirjoittaa suoraan muistiin tuon merkin. Ja eikös C++:n kanssa pitäisi käyttää couttia?
Mikähän kääntäjä on kyseessä? Kääntäjän valmistaneen firman nimi ei vielä kerro oikein mitään.
Tuossa tosiaan kannattaa piirtää suoraan näyttömuistiin, riippuu vähän ympäristöstä. Mutta cprintf on hidas siksi että 1) se piirtää värin kera (ei varmaankaan tunne puskurointia) 2) joutuu miettimään merkkijonon parsausta.
Edelleen, C++:n nopeutta ei pidä lähteä arvioimaan käyttämällä epästandardeja funktioita, saati funktioita muutenkaan.
Ja vielä edelleen, periaatteessa cout olisi tosiaan se tapa tulostaa tekstiä C++:ssa, mutta tällaisen ohjelman (ilmeisesti peli) ollessa kyseessä tulee ehdottomasti käyttää joko muistiin kirjoittamista tai käyttöjärjestelmän funktioita (esim. Windowsin API). Periaatteessahan konsolissa kaiken edeltävän tekstin pitäisi olla kokoajan näkyvillä ja sitähän nämä pelit eivät noudata. Tämä selittää myös mm. sen miksi C:n ja C++:n standardikirjastosta ei löydy funktiota näytön tyhjentämiseen.
Käytin kyllä alunperin coutia ja kokeilin tuota cprinf:ää vain koska cout oli aivan yhtä hidas. Mikäs on tekstinäytön muistiosoite? Olisin lähtenyt alunperin sille linjalle, sillä haluaisin tehdä mahdollisimman paljon itse, mutta minulle sanottiin aikaisemmin, ettei pidä ruveta kirjoittamaan mitään suoraan näyttömuistiin, mutta taidanpa tässä sittenkin kirjoittaa. Voisitteko pistää yksinkertaisen koodinpätkän niin opettelen siitä.
Kyseessä on siis Borland C++ 5.02
jos se on konsoliohjelma, aja se koko ruudun tilassa.
Älysin kokeilla sitäkin jo aikaisemmin, eikä ollut merkitystä. Eihän konsolissa ajaminen XP:ssäkään sinänsä hidasta, vaan ikkuna ikään kuin päivittyy vain nykivin välein, mutta tässä ei ollut kyse siitä, vaan jokainen merkki ilmestyy tasaisesti, mutta hitaasti. Ilmeisesti nopeinta on nyt tuo suoraan muistiin kirjoittaminen, eli voisitteko pistää esimerkin. Lähinnä tarvitsisin vain osoitteen, mutta mahdollisimman yksinkertainen koodiesimerkki olisi myös kiva.
tähän vois olla parempi käyttää jotain vastaavanlaista:
char *yono = new char[80]; gotoxy(1, 1); for (int y = 0; y < 25; y++) { for (int index = 0; index < 80; index++) { yono[index] = '#'; } cout << yono; }
tais sitten tehdä koko roska kerralla. eg.
char *mjono = new char[80 * 25];
ja muutat vain indexin pituutta pituuteen 80*25 ja jätät y loopin pois
Edelleen onkos tuo Borland C++ 5.02 siis joku DOS-softa? Jos se kääntää Windows-ohjelmia et voi kirjoittaa suoraan näyttömuistiin, vaan nopeinta on käyttää Windows API:n tarjoamia palveluita.
Pieslice, vaikka koodistani tosiaan sai sellaisen kuvan, tarkoituksena siis ei ollut pohjimmiltaan täyttää ruutua samoilla merkeillä. Se oli vain testi, kuinka nopeasti merkkien piirto tapahtuu. Eli yritän siis aloitella merkkipohjaisella roolipelillä, joka kaatui QB:ssä hitauteen.
Ja kyseessä on siis Windows-pohjainen kääntäjä, eli jos näyttömuisti ei siis toimi, niin mitenkä tuota Win API:a kutsutaan?
Käytä WriteConsoleOutput-funktiota. Konsolin kahvan saat GetStdHandle-funktiolla. Katso lisää MSDN:stä (Googleta hakusanoilla "funktionnimi msdn"). Jos ongelmia ilmenee, voinen vääntää pienen esimerkin.
hunajavohveli kirjoitti:
Pieslice, vaikka koodistani tosiaan sai sellaisen kuvan, tarkoituksena siis ei ollut pohjimmiltaan täyttää ruutua samoilla merkeillä. Se oli vain testi, kuinka nopeasti merkkien piirto tapahtuu. Eli yritän siis aloitella merkkipohjaisella roolipelillä, joka kaatui QB:ssä hitauteen.
Ja kyseessä on siis Windows-pohjainen kääntäjä, eli jos näyttömuisti ei siis toimi, niin mitenkä tuota Win API:a kutsutaan?
kyllä ton mun koodin pitäis toimia win32 konsolitilassa. se ei siis kirjoita näyttömuistiin mitään vaan tekee merkkijonon, joka sisältää levelin. tätä vois jatkaa siten että sen levelin saa generoitua esim jollain editorisoftalla, joka tallettaa kyseisen merkkijonon tiedostoon, ja pistää sen kerralla näytölle. merkkijonon voi jättää muistiin, jolloin sitä voi käyttää törmäyschekkiin tyyliin->
if (levelData[play_y * 80 + play_y] != ' ') { (TÖRMÄYS) } else { (EI TÖRMÄYSTÄ) }
tyhjät on siis välilyöntejä, ei NULL merkkejä, koska ne ei tulostu näytölle. sun täytyy siis ottaa levelin pohjaksi 80*25 välilyöntiä sisältävä merkkijono.
ja törmäyscheckkihän tehdään siten että katsot mihin pelaaja on LIIKKUMASSA, ja sitten katsot voiko siihen mennä. jos voi, niin sitten siirrä pelaaja, muuten et.
(kun luet merkin merkkijonosta, ja muutat sen int:iksi saat merkin ascii koodin, jolloin voit tulkita mitä siinä kohdassa on.) tai sitten vaan tyyliin
if (levelData[play_y * 80 + play_x] == 'D') { (LOHIKÄÄRME) }
helppoa.
muuten: eihän sitä leveliä tarvitse piirtää kuin kerran.
varsinainen ongelma roguepeleissä on se pelilogiikka. voin kyllä jatkossakin auttaa mm. tekoälyn kanssa.
Tekoälyn ja pelimoottorin osasin QB:lläkin rakentaa mainiosti itse, mutta kuten sanoin, vastaan tuli vain hitaus. Kun on 100 monsteria yhtä aikaa kehissä, se ei oikein QB:llä pyöri. Varsinkin kun on tarkistettava jokaisen monsterin mahdollinen törmäys toisiinsa niin...
Niin käsitinkö oikein tuon mitä yritit neuvoa, että leveli tallennettaisiin ensin char-taulukoon (jonka käsittely siis toimii todella nopeasti) ja sitten kerralla tulostettaisiin koko taulukko ruudulle? Mutta tämä ei toimi sitten niiden monsterien ja muiden kanssa. Tarvitsisin vain yhden yksinkertaisen käskyn, joka tulostaa merkin näytölle. Tuota vinkkiäsi voin kyllä hyödyntää itse kentän piirrossa. Yritän etsiä Googlella tuota fawkzin funktiota.
niin tarkoitin sitä että sitä leveliä ei tarvii tulostaa kuin kerran. monsterit ja vastaavat tulostetaan mm. for-silmukan sisällä.
niillä on oma datarakenne. mielellään C++ luokka. tai struct.
kun pidät huolen siitä että ne monsterit ei "syö" (eli siis liiku mm. seinän päälle) sitä leveliä, niin sehän säilyy sellaisenaan kun sen kerran printtaa. onko peli muuten vuoropohjainen?
"animaatio" siis voi toimia jotenkin tällä tavalla. C++ luokassa, joka omistaa:
int x, y; // -> paikka char monsterChar; // -> "sprite" merkki
#define NORTH 1 #define SOUTH 2 #define WEST 3 #define EAST 4 extern char *levelData; void SingleMonster::Move(int direction) { int requested_x = x; int requested_y = y; switch (direction) { case NORTH: if (y > 0) requested_y = y - 1; break; case SOUTH: if (y < 24) requested_y = y + 1; break; case WEST: if (x > 0) requested_x = x - 1; break; case EAST: if (x < 79) requested_x = x + 1; break; } if (levelData[requested_y * 80 + requested_x] != 32) return; gotoxy(x, y); printf(" "); x = requested_x; y = requested_y; gotoxy(x, y) printf("%c", monsterChar); }
ja sitten teet silmukan joka ajaa tekoälyn ja liikuttaa monstereita. Luokkahan määritellään mielellään omassa Cpp filussa. Kannattaa lukaista Päivi Hietasen C++ ja Olio-ohjelmointi kirjasta miten luokka määritellään.
karkeaa pseudo-ohjelmaa:
// koodin alkuun globaaliksi: SingleMonster *monsterObject = new SingleMonster[TOTAL_BADASSES];
missä TOTAL_BADASSES on itse määrittelemäsi vakio
toi luokka pitää resetoida, eg kirjoitta sen muuttujille oletusarvot ennen kuin sitä käyttää.
liikefunktion pseudokoodi
for (int index = 0; index < TOTAL_MONSTERS; index++) { if (monsterObject->alive == true) { aja_tekoaly__hanki_direction(); monsterObject[index]->Move(direction); } }
Jos tarkoitat vuoropohjaisella sitä, että kaikki liikkuu yhden pykälän aina sitä mukaa kun painetaan jotain näppäintä, eli liikutetaan omaa äijää johonkin suuntaa, niin sellainen juuri on tarkoitus tehdä. QB:ssä käytin etupäässä pelkkiä taulukoita monstereissa, mutta Struct-rakenne mahdollistanee sen, että tehdään jokaiselle monsterille myös tavaralista yms. jotka vaativat useamman alkion, mutta niin ettei tilaa mene taulukosta hukkaan. Mutta osaan minä pelin rakenteen koodata. Kysyn sitten lisää, jos sen kanssa tulee ongelmia. Ensin minun pitää vain saada merkkien piirto niin, ettei sitä ehdi huomata.
luokat on parempia kuin structit koska niille voi määrätä myös metodeja eli funktioita, kuten tossa esimerkkikoodissa näkyy. kyllä ton silmukan pitäis aika vauhtiveikko olla.
Pistin sähköpostilla sinulle esimerkin Rogue-tyyppisestä pelistä, jonka tein QB:llä jo aika kauan sitten. Näet siitä (toivon mukaan) että osaan kyllä tehdä pelimoottorin tuollaiseen, vaikka se onkin keskeneräinen. Ei minulle pitäisi tuottaa ongelmia kääntää sitä C++:lle muuta kuin tuo merkin piirto. Mutta kysyn sitten lisää neuvoja, jos kuitenkin tulee ongelmia moottorin kanssa.
Aihe on jo aika vanha, joten et voi enää vastata siihen.