Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Madon häntä

Sivun loppuun

ristokor [25.02.2006 10:36:34]

#

Matopeliä olen viime aikoina tehnyt ja alkaa olla valmis, mutta pitkään olen yrittänyt saada madon hännän seuraamaan itse matoa. Ajatuksena on, että madon x ja y arvo talletetaan taulukkoon ja seuraavassa kertauksessa piirretään häntäpala entiseen madon kohdalle. Ennen mitään liikkumisia piirretään mato+kolme häntäpalaa vierekkäin (10 pikselin välein)ruudulle. Sitten jokaisen palan x ja y arvot talletetaan taulukkoon kohtiin p_valiax[pala] ja p_valiay[pala]. Sitten joka liikkumiskerralla otetaan aina tämänhetkinen madon x ja y arvo ja sijoitetaan taulukon kohtiin 0. Seuraavalla kerralla [0]:n arvo sijoitetaan kohtaan [1] ja piirretään se, mutta näin ei toimi. Alussa näyttöön tulee vain yksi madon pala, omenan syömisen jälkeen omenan paikalle ilmestyy häntäpala (joka ei liiku) ja seuraavan omenan syömisen jälkeen matoa seuraa välkkyvä pala melkein madon päällä. Seuraavan omenan syömisen jälkeen uusi pala ilmestyy ylänurkkaan. Mikähän vikana ja miten itse toteuttaisitte tämän.
Koodi:

int valitaulu[1][800]={0};
    if (p_omenalkm==10)
    {
       int mihinx=mx;
       p_valiax[0]=mx;
       p_valiay[0]=my;
       for (int i=0; i<p_mlkm;)
       {
               draw (mato, screen, p_valiax[i], p_valiay[i]);
               mihinx+=10;
               p_valiax[i]=mihinx;
               p_valiay[i]=my;
               i++;
       }
    }

    while (!kertaus) //Toistetaan jos kertaus ei ole tosi.
    {
        draw (ltausta, screen, 0, 0);

        p_valiax[0]=mx;
        p_valiay[0]=my;

        for (int i=0; i<p_mlkm;)
        {
            valitaulu[0][i]=p_valiax[i];
            valitaulu[1][i]=p_valiay[i];
            i++;
        }
           for (int i=0; i<p_mlkm;)
               {
               draw (mato, screen, p_valiax[i], p_valiay[i]);
               i++;
               }
           for (int a=1; a<p_mlkm;)
           {
               p_valiax[a]=valitaulu[0][osa];
               p_valiay[a]=valitaulu[1][osa];
               a++;
               osa=a;
               osa--;
           }

        SDL_Flip (screen);

Metabolix [25.02.2006 11:11:49]

#

No ainakin koodista päätellen pitäisi olla valitaulu[2][800].

Ensinnäkin, on hirvittävän rumaa pitää yhtä taulua x-koordinaateille ja toista y-koordinaateille. Tee struct, joka sisältää x:n ja y:n ja käytä sellaisia sijaintien ilmoittamiseen.

Ja kun kerran C++:aa käytät, niin ota siitä ilo irti: käytä jonoa (STL + queue; Google tietää). Toinen äkkiseltään mieleen tuleva vaihtoehto on, että käytät tasotaulua, jossa siis pidät kaikkea tietoa tasosta, ja varaat madolle vaikka kaikki negatiiviset numerot. Joka framella kierrät taulun läpi, pienennät kaikkia negatiivisia yhdellä ja poistat, jos menee pienemmäksi kuin madon pituus (negatiivisena).

ristokor [25.02.2006 12:47:38]

#

Tuosta queuesta. Kun kääntää ohjelmaa niin tulee linkkeri virhe. Eli pitääkö sinne projectin optionsiin laittaa taas jotain tekstiä? (SDL_image tapauksessa se -ISDLmain vaimikäolikaan)

Metabolix [25.02.2006 13:32:45]

#

Ei pitäisi tarvita. Kai koodisi kääntyy g++:lla eikä gcc:llä? -lstdc++ voi kuitenkin auttaa.

ristokor [25.02.2006 13:46:53]

#

hmm... g++, gcc, minulle tuntemattomia käsitteitä. Dev-cpp:tä käytän ja mureakuhan komentojono esimerkkikoodia yritän kääntää.

Metabolix [25.02.2006 13:57:36]

#

No mikähän linkkerivirhe siitä sitten mahtaa tulla?

ristokor [25.02.2006 14:00:23]

#

[Linker error] undefined reference to 'CommandQueue::InsertCommand(void(*)())'
[Linker error] undefined reference to 'CommandQueue::InsertCommand(void(*)())'
Id returned 1 exit status

Ja jos tuohon esimerkkikoodiin nyt laittaisi sitten niitä omia komentoja nuitten tulostuskomentojen tilalle niin toimisiko se sillä?

Metabolix [25.02.2006 14:10:24]

#

Oletko aivan varmasti kopioinut koko tuon esimerkkikoodin? Kyllä se nimittäin toimii aivan hyvin. Aivan kuin olisit jättänyt tuon yhden funktion kopioimatta.

ristokor [25.02.2006 14:17:10]

#

*hävettää* (pahoittelut vaivaamisesta)
Koko koodi oli kopioitu, mutta kun dev-cpp ei osaa itse nuita kopioituja rivittää niin olipahan kommenttien sekaan jäänyt yksi tärkeä sinnekuulumaton lause.


Lisää:
Mites tuossa queue jutussa, kun siinähän laitetaan arvoja peräkkäin, niin sehän toimisi pelkällä x arvolla. Pitääkö tehdä kaksi queueta, että voi kaksi jonoa tehdä?

Blaze [25.02.2006 15:04:56]

#

Kuten aiemminkin jo vinkattiin: tee yks jono structeista.

Metabolix [25.02.2006 16:33:27]

#

Ei se queue välttämättä olekaan tähän aivan paras, kun sitä ei voi käydä läpi. Elikkä vector ehkä ennemmin.

tn [25.02.2006 18:14:16]

#

Joo, vectorilla se lienee helpoin tehdä. Oikeastaanhan tuohon saattaisi sopia parhaiten list, mutta se taas vaatisi iteraattoreden käyttöä.

koo [25.02.2006 18:27:44]

#

Itse käytän usein perus-containerina std::dequeta, ellei nimenomaan ole tarvis olla yhteensopiva C-tyylin taulukon kanssa, mihin taas vector on suunniteltu.

Tähän hommaan sopivin voisi tosiaan olla list. Iteraattorit voivat kuulostaa vaikealta, mutta ei niiden käyttö sitten niin hankalaa ole, nehän ovat melkein kuin osoittimia. Kannattaa perehtyä joka tapauksessa.

os [25.02.2006 19:14:55]

#

Ei tässä mitään STL:lää tarvita...

Harjoituksen vuoksi voi koodata madolle vaikka ihan oman linkitetyn hännän:

class Nikama {
  public:
   int x, y;
   Nikama *seuraava;

   Nikama(int x0, int y0, Nikama *seur) :
    x(x0), y(y0), seuraava(seur) {}

   Nikama *PoistaViimeinen() {
     if(seuraava==NULL) { delete this; return NULL; }
     seuraava = seuraava->PoistaViimeinen();
     return this;
   }
};

Nikama *mato = new Nikama(x,y,NULL);

joka framella:

mato = new Nikama(mato->x+xnop,mato->y+ynop, mato);
if(mato ei ole syönyt) mato->PoistaViimeinen();

ristokor [25.02.2006 23:19:03]

#

Ööh. Mitenhän tuohon saisi sitten vielä sen piirtovaiheen. Joka framella kohdan jälkeen, lisäämällä draw(matoi, screen, x, y); sain edelleen sen yhden madon palan tulemaan ruudulle. Pitääkö se piirtokohta laittaa eri tavalla?

Metabolix [25.02.2006 23:21:42]

#

No tietenkin ne pitää kaikki piirtää. (Kerro ensin, mitä tapaa käytät, niin on helpompi kertoa, miten ne kaikki käydään läpi.)

ristokor [25.02.2006 23:31:30]

#

No ennen tuon esimerkkikoodin copy-pasteamista käytin tapaa:

for (int i=0; i<p_mlkm;)   //p_mlkm on funktiolle parametrina välitettävä madon "osien" lukumäärä.
{
    draw (matoi, screen, mx, my);   //matoi on madon kuva ennen esimerkkikoodin lisäystä nimenä oli pelkkä mato.
    i++;
}
//mx ja my on vain muodon vuoksi, kun en tiedä mitä nyt pitäisi laittaa. Ennen esimerkkikoodia se oli p_valiax[i] ja p_valiay[i]

Metabolix [25.02.2006 23:38:09]

#

Älä ikinä, siis ikinä vain kopioi esimerkkikoodia, vaan aina yritä ajatuksella ymmärtää sen idea, ja tuollaisessa lyhyessä tapauksessa kirjoita oma versiosi! Tarkoituksenasi on kuitenkin toivottavasti oppia tekemään matopeli eikä vain tehdä sitä muiden antamista pätkistä ymmärtämättä, miksi se toimii.

Linkitetyn listan voit käydä läpi niin, että teet uuden osoittimen ja osoitat sen ensin listan ensimmäiseen kohtaan. Eli osoitin = mato. Siirryt aina seuraavaan kohtaan laittamalla osoittimen arvoksi osoitin->seuraava. Tätä jatkat, kunnes osoitin == NULL, koska listan viimeisen kohdan "seuraava" on NULL eli nolla eli tyhjä osoitin.

Sanallinen selitys siksi, että joudut itse ajattelemaan etkä voi vain kopioida. Kyllä siinä sanotaan kaikki tarpeellinen, ja jos et heti ymmärrä, lue uudestaan kaikessa rauhassa ja kokeile muutaman kerran.

ristokor [25.02.2006 23:40:06]

#

Kuitenkin piirretään nuilla x ja y arvoilla, vai mitä tekemistä xnop ja ynopilla on tuossa.

Metabolix [25.02.2006 23:41:44]

#

Tietenkin piirretään x- ja y-arvoilla, mistä muualta sen sijainnin saisi? Mutta xnop ja ynop ovat ilmeisesti nopeutta kuvaavia suureita.

ristokor [25.02.2006 23:43:58]

#

Eiku minun omassa versiossani piirto tapahtui taulukosta: draw (matoi, screen, p_valiax[mikäkohta], p_valiay[mikäkohta]);

Metabolix [25.02.2006 23:50:31]

#

Mutta kun et enää ilmeisesti käytä taulukoita, niin et voi ottaa sieltä koordinaattiarvojakaan. Sen sijaan jos nyt käytät linkitettyä listaa, voit äsken selostamallani tavalla käydä kaikki nikamat läpi ja jokaisen kohdalla piirtää käyttäen sen x- ja y-arvoja.

ristokor [25.02.2006 23:57:23]

#

Tein sen näin:

int* osoittelija=0;
osoittelija=&mato;
        for (; osoitin!=NULL;)
        {
        osoitin->seuraava;
        draw (matoi, screen, x, y);
        }

Mutta tulee virhe, mistäköhän johtuu?

Metabolix [26.02.2006 00:01:16]

#

Korjattu koodi.

Nikama * osoitin = mato;
while (osoitin != NULL)
{
  draw(matoi, screen, osoitin->x, osoitin->y);
  osoitin = osoitin->seuraava;
}

os [26.02.2006 12:02:17]

#

Helpoitenhan kaikista matoon liittyvistä toimista selviää rekursiolla. Esimerkkikoodiini kannatta lisätä ainakin seuraavat jäsenfunktiot:

void Nikama::Piirra( /*parametreja (matoi, screen)*/ ) {
  draw(matoi, screen, x, y);
  if(seuraava!=NULL) seuraava->Piirra(matoi, screen);
}

Nikama::~Nikama() { if(seuraava!=NULL) delete seuraava; }

Ja käyttö:

mato->Piirra(matoi, screen);

lopuksi mato täytyy tietysti tuhota (muistin vapautus)

delete mato;

_Pete_ [03.03.2006 09:43:39]

#

Asiaan liittyen. Java WTK:n mukana tuli J2ME esimerkki aplikaatioita, jossa oli minun mielestäni esimerkillisen hyvin tehty matopeli olioita hyväksi käyttäen.

Täältä voi katsoa miten se on tehty jos ei halua koko WTK:ta imuroida:

http://machine.homeunix.net/~petriai/code/WTK_APPS_GAMES/src/example/wormgame/


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta