Eli tavoitteenani (siis haaveenani (: ) on tehdä pikkupeli C++:lla.
Kysymys koskee kenttien luontia. Eli miten minun kannattaisi tehdä mapit? Mapit tulisi olemaan tätä tyyliä:
+-----+ |___ | | | +-----+
Mutta miten ne kannattaisi luoda, sillä ei välttämättä ole kovin hyvä idea näpytellä kaikkia kenttiä ihan suoraan siihen koodin. Ja kannattaako mapit lukea taulukkoon? Ja miten se tarkalleen toimisi?
Tuollaiset merkkigrafiikkaiset (vai meinaatko tileillä tehdä) kartat kannattaa tallentaa tiedostoon ja lukea sitten sieltä. Se on luullakseni ehkä paras vaihtoehto.
Taso kannattaa ehdottomasti ladata tiedostosta, niin myöhempi muokkaaminen on helpompaa. Käytä vaikkapa char-taulukkoa, tai, jos jokaiselta palaselta tarvitaan enemmän ominaisuuksia, voit luoda oman structin taulukossa käytettäväksi. Tiedostosta voi lukea fread-funktiolla, jolloin datan saa binäärimuodossa. Jos käytät structeja, ei ole kovinkaan vaikeaa tehdä pientä ohjelmaa, joka tekee sattumanvaraisen kartan tiedostoon. Helppo rakenne on vaikkapa se, että ensin luetaan tietuetta "struct TOtsikko", joka sisältää tiedon tason leveydestä, korkeudesta ja muista merkittävistä tiedoista, ja sen jälkeen luetaan oikea määrä (Leveys * Korkeus) struct TRuutu -tietuetta taulukkoon. Eräänlainen esimerkki:
#include <stdio.h> // TPala voi olla ihan hyvin vain char, jos tasolta ei vaadita enempää. #define TPala char // Otsikon on hyvä sisältää kaikki perustiedot tasosta. struct TOtsikko { int Leveys, Korkeus; }; TPala *Tasotaulu; TOtsikko Otsikko; // Määritellään makro, jolla saadaan tasosta tietty pala: #define Taso(X, Y) Tasotaulu[X + Y * Otsikko.Leveys] void LataaTaso(char *Tiedostonimi) { // Avataan tiedosto FILE *hFile = fopen(Tiedostonimi, "r"); // Luetaan Otsikkoon yksi TOtsikon kokoinen pala hFile-tiedostosta. fread(&Otsikko, sizeof(TOtsikko), 1, hFile); // Varataan muistia. Tasotaulu = new TPala[Otsikko.Leveys * Otsikko.Korkeus]; // Luetaan Tasotauluun kaikki tason palat fread(Tasotaulu, sizeof(TPala), Otsikko.Leveys * Otsikko.Korkeus, hFile); } int main() { LataaTaso("Taso1.lev"); printf("Taso ladattu!"); for (Y = 0; Y < Otsikko.Korkeus; Y++) { for (X = 0; X < Otsikko.Leveys; X++) { printf("%c", Taso(X, Y)); // Tulostetaan kohdan (X, Y) merkki } printf("\n"); // Rivin vaihto } // Muistetaan aina myös tuhota taso, jotta muisti vapautuu. delete [] Tasotaulu; return 0; }
Tason saa siis luotua niin, että täyttää TOtsikko-tietueen, kirjoittaa sen tiedostoon (esim. fwrite-funktiolla) ja kirjoittaa sen jälkeen (Leveys * Korkeus) TPala-oliota, joka siis on tuossa tapauksessa sama kuin char.
Kiitti! Toi oli tosi perusteellinen vastaus.
Niin, nyt tulikin ongelma, että miten saisin luettua näppäimistön painalluksia? Siis tietty nuolinäppäimiä. Eli millä funktiolla se onnistuu?
Tarvitset jonkin kirjaston käyttöösi. Esimerkiksi SDL:llä tämä onnistuu. Putkasta löytyy oppaat.
Ncurses(unix*), tai sitten PDcurses(windows), niillä onnistuu näppäinten luku getch(); komennolla
esim.
#include <ncurses.h> int main() { int a = 0; a = getch(); switch(a) { case KEY_A: printw("Painettiin A:ta"); } return 0; }
PS: Sisältää virheitä, koska kirjotin suoralta kädeltä, mutta asia pitäis tulla selväksi, eli getch() ei palauta näppäimen kirjainta vaan vissiin ASCII koodin, joka kuitenkin on #define:llä ohjattu tyyliin: KEY_(kirjain tähän)
EDIT: ainiin toi sun esimerkki ei toimi koska tuosta puuttuu int X ja int y sekä mulla se sanoo (siis vaikka taso o olemassa): what(): St9bad_alloc
Keskeytetty
No onko niin suuri juttu lisätä tuonne "int X, Y;
"? Huomioi, että kirjoitin tuon suoraan tähän pieneen viestilaatikkoon. Muilta osin tuo toimisi, jos sinulla olisi tuon kaavan mukainen tasotiedosto (Taso1.lev), ja sitä sinulla ei tietenkään ole. Totta kai tuosta tulee "bad alloc", kun (Width * Height) on ties kuinka suuri luku, kun siihen ei ole tiedostosta saatu järkevää arvoa. Järjen käyttö sallittu.
ÄÄH! Mä en saa ees tota ZcManderin esimerkki koodia toimimaan :( SHIT!
En oo vieläkään alkuu pidemmällä :(. Eli taidan aloittaa alusta:
Eli, jos nyt aluksi haluaisin tehdä (tulevaan) peliini ukkelin liikutuksen (aloin säätämään vanhaa ja se meni epäkuntoon (: ), niin miten se onnistuisi? Eli pitäisikö tämän toimia:
#include <iostream> #include <conio.h> using namespace std; int main() { gotoxy(4, 5); cout << "*"; getch(); }
Eli pitäisikö tuon koodin laittaa tähti(*) näytölle kohtaan X4 ja Y5?
Conio.h:sta en mene takuuseen, se nimittäin taitaa vain löytyä Borlandin kääntäjästä, lisäksi sanoi, että PDcurses tai Ncurses (ainakin Ncurses) löytyy getch() komento. Taitaa (En allekirjota) olla conio.h:ssa, gotxy komento on kyllä conio.h:ssa
Nurses(tai PDcurses, mutta en ole siihen tutustunut):sin piirto funktio tulee muistaakseni näin:
//mvprintw(rivi,sarake,teksti); //esim. mvprint(4,5,"*"); //Tuo piirtää haluamaasi kohtaan tähden
EDIT:Ncurses:lla haetaan maksimi koot käyttämällä komentoa getmaxxy(int w,int h); Lisätietoa löytyy Ncurses ohjelmointi oppaassa (engl.) http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/index.html
EDIT2:Itsekkin tein merkkipohjasta peliä ja onnistuinki siinä ja aloin lisää kehittämään, mutta sortui huonosti koodattuun engineen (ei luokkia :O), eli nytten mulla on itellä ollut aika kauan merkkipohjanen peli kehitteilla (Eikä pelin idea tullut hov:sta)
Miksi sitten edes mainitsit HoV:n? ;). Ei vaiskaa, toivottavasti saadaan kuulla viel* pelist*si. Ja se on mvprintw, ei mvprint. Mvprintw kirjoittaa haluttua teksti* xy kohtaan stdscreeni*.
Mutta mikä headeri tuolle mvprint():ille tarvitaan?
Aruviel, kirjoititko tahallas tähtinä?
Mutta itse asiaan: Joo, kyllähän multa unohtui tuo w tuolta perästä, kuteskin kommenteissa se on oikein, lisäksi minun tietääkseni tekstitilassa ei ole x ja y:tä (tosin itsekkin niitä käyttelen ;) vaan rivi ja sarake. Tuohan tarttee headereiksi:
Windows:
#include <curses.h>
Linux:
#include <ncurses>
Ja molemminlla pitää linkitää kirjasto ncurses/PDcurses, GCC:llä onnistuu (ncurses): gcc lahde.cc -o peli -lcurses
ZcMander kirjoitti:
Conio.h:sta en mene takuuseen, se nimittäin taitaa vain löytyä Borlandin kääntäjästä
Löytyy myös Dev-C++:sta.
Mul ei toi curses.h:n mvprintw/mvprint() eikä conio.h:n gotoxy() toimi... Mikä tässä nyt neuvoksi? Aika outoa ettei ess toi curses juttu toimi...
Mikä siis on ongelma? Eikö tarvittavaa otsikkoa löydy, vai yritätkö väittää, etteivät funktiot toimi? PDCurses-kirjoston saa osoitteesta http://sourceforge.net/project/showfiles.php?
Ei tietenkään ole, kun se ei ole standarti kirjasto.
Se pitää hakea, kuten kaikki muutkin kirjastot. Dev-c++ Updater ohjelmalla saatta löytyä, mutta jos ei löydy niin sitten se pitää itse säätää. Siinä en valitettavasti osaa auttaa.
Itse asensin Linuxsin itse asentuvista RPM paketeista ;)
En nyt varsinaisesti väitä, ettei PDcurses toimi, vaan en itse saa sitä toimimaan.
Eli pitäisikö tämän koodin asetella tähti(*) näytölle kohtaan X5 Y4:
#include <iostream> #include <curses.h> using namespace std; int main() { mvprint(5, 4, "*"); return 0; }
Ja tuon koodin kääntää näin:
Menee komentoriville ja Dev-Cpp/bin kansioon, sitten antaa komennon:
gcc testi.cpp -o testi.exe -Icurses
Eli pitäisikö tuon toimia?
Käännät C-kääntäjällä (gcc), vaikka iostreamia ei löydy C:stä. Käännä siis g++:lla. Ja minähän sanoin, ettei - ainakaan ncursesissa - ole sellaista funktiota kuin mvprint(), se on mvprintw(). Jos haluat yksittäisiä merkkejä tunkea ruutuun, käytä mvaddch(int y, int x, char ch); -funktiota. Huomaa, että curses ohjelmissa tulee ensiksi ilmoittaa sijainti y-akselilla ja sen jälkeen x-akselilla.
// Funktiot tunkevat (ensimmäisellä vain merkkejä, toisella merkkijonoja) merkin * kohtaan X=4, Y=5. Huomaa myös, että X ja Y alkavat nollasta, joten jos haluat merkin vasempaan yläkulmaan, sinun tulee käyttää X=0, Y=0. mvaddch(5,4,'*'); mvprintw(5,4,"*");
http://en.tldp.org/HOWTO/NCURSES-Programming-HOWTO/printw.html
Ei toimi... Siis vaikka hain PDcursesin, tein asettelemis koodin niinkuin neuvottiin ja käänsin tiedoston niinkuin neuvottiin... Mikähän tässä nyt mättää?
Onko se asennettu? Lisäksi helpottaisi aivan mielettömästi, jos virheet olisivat täällä näkyvillä.
Joo, kyllä on asennettu :)
Se ilmottaa:
undefined referece to 'mvprintw'
Mitäkähän toi nyt sitte tarkottaakaa... (:
Hmm, käytä g++ kääntäjää niin onnistuu, sama ongelma oli minulla. Noh, riippuu tietenkin mitä ohjelmaa käytät, DEV-c++ ohjelmassa lienee pitää laittaa c++ ohjelmaksi ja lisätä libraryt (siis ei pelkästään otsikko tiedostot).
Niin ja tuohan virhe ilmo tulee linkitysvaiheessa, ei käänösvaiheessa, joten libraryt on aika varma syy jos käytät Dev-c++. Ne saa laittamalla asetuksista (yllätys). Lisäksi kannaattee varmuuden vuoksi laittaa koodi tänne. (Joka ei kai ole kovin pitkä?)
Koodi on tossa vähän ylempänä, paitsi että nykyään osaan kirjoittaa mvprintwin oikein :P
Tarkoitin koko koodia, toimiiko tämä koodipätkä:
#include <curses.h> int main() { initscr(); /* Start curses mode */ printw("Hello World !!!"); /* Print Hello World */ refresh(); /* Print it on to the real screen */ getch(); /* Wait for user input */ endwin(); /* End curses mode */ return 0; }
Toi ei toimi. Väitää virhettä joka rivistä :D
Ja varsinaista muuta koodia ei ole, koska olen vasta ihan projektin alussa.
Tein ukon liikutuksen, kääntyy ainakin Dev-C++:ssalla. Muista lisätä projektiisi conio.c.
#include <conio.h> #include <stdio.h> using namespace std; int gox, goy; int main(int argc, char *argv[]) { for(;;){ int a = 0; a = getch(); //Tyhjennetään näyttö clrscr(); switch(a) { case 75: gox--; break; case 77: gox++; break; case 72: goy--; break; case 80: goy++; break; } gotoxy(gox,goy); printf("*"); } }
Siis miten toi conio.c pitää lisätä projektiin?
#include:lla kenties?
(Mikä tuon #includen oikea nimitys muuten on? Komento? Direktiivi? Esikääntäjän ohje?)
Project-valikosta -> Add to project (Olettaen, että onjelmasi yleensä on projekti)
Jos käyttää pelkkää yhtä lähdekooditiedostoa ilman projektia, niin on helpompaa sisällyttää se tuon conio.h :n sijasta.
Hmm... Mulla toi gotoxy koodi ilmottaa:
'gotoxy' undeclared (fist use this function)
eli ei toimi...
Nyt sain ton curses.h:n mvprintwnin menemään kääntäjästä läpi; oli kirjottanu -Icurses vaikka piti kirjottaa -lcurses :@. Ainut ongelma on vielä se, että se mvprintw ei asettele sitä merkkiä, vaan piirtää tyhjää :O Mikä siinä nyt voisi olla vikana?
#include on ainakin minun mielestäni esikääntäjän ohje...
Mutta taas kerran muistutan että se on minun mielestä niin...
Nyt sain ton toimimaan tolla curses.h:lla :D JEAH!!
Nyt vaan tuli eteen sellanen ongelma, että luen näppäimet conio.h:n getch() oliolla, mutta mitenkäs se suu pannaan, kun curses.h:ssakin on getch()? eli nyt ne menee sekasin! Miten ton vois korjata. Pitääkö conio.h:ta muokata tai jotain?
Mitä jos rupeaisit käyttämään pelkkää PDCursesia ja luopuisit coniosta kokonaan?
Jyri, sen takia ei tullut mitään koska perään pitää laittaa refresh(); komento joka päivittää näytön. Ja kuten ylläkin on sanottu, käytä pelkästään PDcurses kirjastoa, siitä löytyy getch(); Emt miksi jotku on ees sekottanut conio.h ja PDcurses:sin keskenään?
ZcMander kirjoitti:
Emt miksi jotku on ees sekottanut conio.h ja PDcurses:sin keskenään?
Koska molemmissa on tämä gotoxy/mvprintw.
Käytä nyt vaan sitä PDCursesia, se on monipuolisempi kuin conio :P
Mutta ku se pdcursesin getch() ei kai toimi ihan samallatavalla kuin conio.h:n getch(), tai siis ainakaan samaa koodia se ei pysty käyttämään. Pitäskö sen siis toimia näin:
int a = 0; a = getch(); if(a == 75) x -= 1;
???
PDCurses:n getch() ei palauta samoja arvoja kuin conion vastaava (näin muistelisin). PDCurses:n mukana tulevassa .H-tiedostossa on määriteltynä vakiot tuolle getch():lle (KEY_A, KEY_LEFT tms). Koeta katsoa jos löytyy/toimii, tai sitten vai testaat erikseen mitä se palauttaa.
Hmm.. ainakaan se ohjelma jolla yritän näppäimistöä lukea ei toimi... Eli se ei tee sitä mitä sen pitäisi tehdä kun painetaan alas, vaan se sammuu.
Kertoisit koodin.
Simple koodi:
#include <iostream> #include <curses.h> using manespace std; int main() { int nappain = 0; initsrc(); nappain = getch(); switch(nappain) { case KEY_LEFT: cout << "Painoin vasemmalle" << endl; } endwin(); }
Hmm.. toi ohjelma ei toimi mulla, se vaan vilahtaa eikö oota mitään napin painallusta.
Jyri kirjoitti:
Hmm.. toi ohjelma ei toimi mulla, se vaan vilahtaa eikö oota mitään napin painallusta.
Joo, oisit voinu lukea vähän noita edellisiä viestejä, nyt kysymys ei ollut siitä, vaan siitä ettei tulo curses.h:n getch(); toiminut oikein.
Laita for(;;)-looppiin (tai vaihtoehtoisesti while(1)).
EDIT: Vähän muuteltu PDCurses-esimerkistä. Sovella.
/* Based on: http://www.linux.cz/noviny/1998-1112/clanek11.html */ #include <curses.h> #include <ctype.h> int main () { int c; initscr (); keypad (stdscr, TRUE); while ( (c=getch()) != KEY_F(10)) { erase(); //Tunnista vasen if (c == KEY_LEFT){ mvprintw (10, 20, "VASEN!!!", s); } } erase (); refresh (); endwin (); exit (0); }
EDIT2: Olin kiltillä päällä ja tein paremman.
(Viitaten getch(); ongelmaan)
Miten niin ei toimi oikein? Kerrot aina yhtä tarkasti ongelmasta. Arvuuttelu ei ole kivaa. Luepa niitä oppaita, miten asia tehdään. Alkuunsa sanon, että funktiokutsut noecho(); ja raw(); liittyvät jotenkin asiaan.
http://en.tldp.org/HOWTO/NCURSES-Programming-HOWTO/init.html
Kiitti! Nyt toimii!
Aihe on jo aika vanha, joten et voi enää vastata siihen.