Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Janan seuraaminen

Sivun loppuun

mika132 [20.09.2010 14:19:20]

#

En keksinyt parempaa otsikkoa, mutta tarkoitus on saada radalleni autot menemään rataa pitkin, mutta tämän hetken koodi ei ole edes lookinen. Eli kysymys kuuluu miten tuo kannattaisi toteuttaa, että autot menevät rataa pitkin? :o

Pistän vielä tämän oman kyhäelmän mistä ei tarvitse mainita sen enempää kun tiedän jo sen kaikki virheet tiedän, että mahdoton toteuttaa sitä varmaankin noin, koska tulee aivan törkeäm pitkä ja tiedän myös sen, että se on täysin epälookinen, mutta pistän sen siksi, että näette, että olen jotain yrittänyt.

piirra_kuva(kuvat::rata_1, 0, 0);
piirra_kuva(kuvat::auto_1, kuski_1_x, kuski_1_y);
if (kuski_1_y <= 120) {
    kuski_1_x+=1;
    kuski_1_y+=1;
    if (kurvi_1 == 0) {
        kurvi_1+=1;
    }
} else {
    kuski_1_y -= 3;
}
if (kuski_1_x >= 250 && kuski_1_x <= 260) {
    if (kurvi_1 == 1) {
        kuski_1_y+=2;
        kurvi_1+=1;
    }
    if (kurvi_1 == 2) {
        kuski_1_y+=2;
    }
}
if (kuski_1_y >= 300 && kuski_1_y <= 340) {
    kuski_1_x+=1;
    kuski_1_y+=1;
    if (kurvi_1 == 2) {
        kuski_1_x+=2;
        kurvi_1+=1;
    }
}

Jokotai [20.09.2010 16:27:55]

#

Tahdotko siis, että autot menevät automaattisesti janaa pitkin, vai että autot eivät voi lähteä radalta?
Tapaus 1: Autot kulkevat suoralla 0 asteen kulmassa janaan. Kun jana kääntyy suoritetaan graafinenderivointi ja auto käännetään tangentin suuntaiseksi.
Tapaus 2: Auto tutkii joka päivityksellä, että riittäkö sen nopeus ylittämään radan. Jos rata ylitettäisiin, suoritetaan törmäys.

jalski [20.09.2010 21:34:14]

#

Tulee muuten kohtuullisen tylsän näköinen tulos, jos kaikki ei-pelaajan autot kulkevat vain yksinkertaisesti "janaa" pitkin. Käytä edes jotain spline-käyrää.

Itse kokeilisin ehkä käyttää apuna jonkunlaista potentiaali karttaa ei-pelaajan autojen tekoälyn toteutuksessa.

Eli idea pelaa siis siten, että tarvitset erillisen kartan, mihin tallennat erilaisten esteiden (radan reunat, muut autot, sun muut) aiheuttamat potentiaali kentät. Potentiaali kentät voivat olla negatiivisia tai positiivisia, eli siis ne voivat joko hylkiä autoa tai vetää sitä puoleensa. Kun olet saanut esteiden aiheuttamat potentiaalikentät ynnäiltyä potentiaali karttaan, niin pelissä auto tietää suunnistaa automaattisesti potentiaalien mukaan ja osaa myös sopeutua muutoksiin pelialueella. Nyt vain sytyttelet potentiaali kartalle radan välietapin kohdalle potentiaalin, mikä vetää autoa puoleensa ja laitat autolle "hännäksi" potentiaalin, mikä työntää sitä oikeaan suuntaan. Kun välietappi on saavutettu, niin sammutat sen potentiaalin ja sytytät seuraavan välietapin potentiaalin.

Spongi [21.09.2010 06:10:17]

#

Itse tein omaan kouluprojektiini tekoälyn rakentamalla neliöistä ajoreitin. Tällöin leveys kertoo suoraan kuinka kaukana on sallittua ajaa keskiviivasta, myös jonkinlaista maksiminopeutta kikkailin sen suhteen kuinka lähellä ollaan seuraavaa pistettä ja mikä on kahden seuraavan pisteen kulma (eli mahdollisesti hiljennetään loppua kohti jos tulee jyrkkä mutka). Tietty rattia käänneltiin sen mukaan jos ajetaan "liikaa väärään suuntaan".

Suurinpana ongelmana itselleni oli puut ja muut vähän erilaisemmat esteet, joten toteutin purkkaratkaisun ja katsoin onko auto liikkunut 3 sekunttiin tarpeeksi, jollei ole niin pakki päälle ja käännetään rattia päinvastaiseen suuntaan. Ja jollei auto ollut saavuttanut 30 sekunnin sisällä seuraavaa pistettä, resetoitiin se takaisin edelliseen pisteeseen.

Videota vanhemmasta versiosta löytynee jos kiinnostaa (tekoälyt jäivät vielä aika pahasti puihin kiinni, eikä tainnut mitään resetointiakaan olla), http://www.youtube.com/watch?v=wrxv-I_0sYA

Torgo [21.09.2010 11:15:34]

#

Minäkin tein aikoinaan tuollaisen kouluprojektina. Tein siihen PID-säädön, joka sääti auton nopeutta ja ratin kääntöä suhteessa auton ja radan tangentin väliseen kulmaan. Tavoitteena oli tietysti saada 0-kulma, jolloin ratti suoristetaan ja nopeus on maksimissa. PID-kertoimet olivat säädettäviä ja sopivat arvot löytyivät kokeilemalla. Järkevistä ajolinjoista ei ollut puhettakaan, mutta muuten tuo toimi varsin mainiosti ja ajoi kivoja aikoja.

Tässä nyt esimerkin vuoksi yksinkertaistettu pseudo, miten tuo säätö menisi ratin kääntöön.

     // Lasketaan paljonko suunta on nyt pielessä
     kulma = radan_tangentti - auton_suunta
     // Integroidaan, eli paljonko suunta on ollut kaikenkaikkiaan pielessä
     integ = integ + kulma * aikaväli
     // Derivoidaan, eli paljonko suuntaa on saatu korjattua viime kerrasta
     deriv = (kulma - vanha_kulma) / aikaväli
     // Rattia käännetään PID-kertoimien ja edellisten laskujen perusteella
     säätö = P * kulma + I * integ + D * deriv
     vanha_kulma = kulma

Toista säätö kun aikaväli on kulunut.

Tälläisellä säädöllä helposti ajetaan ojaan, jos ollaan liian ahneita noiden PI-kertoimien kanssa. Eli tarvitaan vielä algoritmi joka ohjaa eksyneen auton takaisin radalle.

mika132 [27.09.2010 23:19:31]

#

Olisin voinut tehdä oman topicin mutta ajattelin, että miksi täyttäisin turhaa foorumia topiceilla, kun sen voi perjaatteessa laittaa tänne, koska se liittyy melkein samaan asiaan.

Tein tuon pyörimis jutun. Palautin siis vain mieleeni SDL_gfx ominaisuuksia, mutta nyt ongelma on se, että auto "rikkoo" kartan ja jättää mustan taustan pyörimis liikkeeseensä. Eli. Annan kaksi kuvaa esimerkiksi, jotta näette auton kahdesta eri asennosta jos ymmärtäisitte mitä tarkoitan.

Kuva 1
Kuva 2


Miten siis tuon mustan kohdan saa pois?

Grez [28.09.2010 10:42:12]

#

Määrittelet auton ulkopuolisen alueen "läpinäkyväksi" eli et piirrä sitä tai piirrät taustan värillä.

jalski [28.09.2010 11:48:22]

#

Sinulle on muuten vastattu samaiseen kysymykseen aikaisemminkin.

Katsopa seuraavanlaisen vanhan keskustelun loppuun, sinulle esitettiin kaksi erilaista ratkaisua: https://www.ohjelmointiputka.net/keskustelu/20833-hiireen-katsominen

mika132 [28.09.2010 19:19:52]

#

Pienen tutkimisen jälkee tuo johtuu varmaan siitä että se vaihtaa "Surfacea" kesken, mutta mites muutenkaan voin mitään tehdä?

Tässä koodi noista kohdista jotka tohon liittyvät:

	kuvat::auto_1 = kuvat::lataa("data/kuvat/auto_1.bmp", true);
	kuvat::rata_1 = kuvat::lataa("data/kuvat/rata_1.bmp", true);

//Siis nämä on ihan eri funktioissa sitten
        piirra_kuva(kuvat::rata_1, 0,0);
        //Kilpailu alkaa
        double kulma = std::atan2((double)x_jana, (double)y_jana);
        kulma += 90;
        kuvat::temp = rotozoomSurface(kuvat::auto_1, rad2deg(kulma), 1, 1);
        piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);

jalski [28.09.2010 21:38:05]

#

Luitko edes vastaukseni?

En ole SDL:n kanssa ohjelmoinnut ikinä, mutta voin silti päätellä, että color key arvo ei kopioidu rotatoinnin mukana. Aseta kuvat::temp:ille sama color key ennen piirtämistä, kuin kuvat::auto_1:llä on ja homma pelaa tai sitten käytä PNG-kuvia ja alpha-kanavaa.

mika132 [29.09.2010 19:15:50]

#

Nyt ainakin kopioituu. muutin auton kuvaa hieman isommaksi ja pistin reunoille pinkin värin. (255,0,255)

No pinkkiä aluetta ei näy ja silti musta alue "rikkoontuu" karttaan? Pitäisikö kuvapäivitys tehdä jotenkin eritavalla vai mikä vielä neuvoksi? En usko, että se .PNG kuvistakaan auttaa, koska transparenttina niidenkin tausta on. Eli tilanne on sama kuin nyt.

Koodia:

kuvat::auto_1 = kuvat::lataa("data/kuvat/auto_1.bmp", true);
kuvat::rata_1 = kuvat::lataa("data/kuvat/rata_1.bmp", true);

//Ja sitten pelin sisäinen toiminta funktio jossa tuo ajojuttu on:

piirra_kuva(kuvat::rata_1, 0,0);
x_jana = (120 - kuski_1_x); /* (60 - 200) = -40 */
y_jana = (120 - kuski_1_y); /* (80 - 100) = -20 */
double kulma = std::atan2((double)x_jana, (double)y_jana);
kulma += 90;
kuvat::temp = rotozoomSurface(kuvat::auto_1, rad2deg(kulma), 1, 1);

SDL_SetColorKey(kuvat::temp, SDL_SRCCOLORKEY, SDL_MapRGB(kuvat::temp->format, 255, 0, 255));

piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);
kuski_1_y-=nopeus;
SDL_FreeSurface(kuvat::temp);
[ccode]



Annan vielä tuon piirra_kuva funktion, jotta näette olisiko siinä jokin väärin mikä aiheuttaa tuon:
[ccode]
static void ohjelma::piirra_kuva(SDL_Surface *kuva, int x, int y, bool keskikohta) {
	SDL_Rect r = {x, y};
	if (keskikohta) {
		r.x -= kuva->w / 2;
		r.y -= kuva->h / 2;
	}
	SDL_BlitSurface(kuva, 0, ruutu, &r);
}

Metabolix [29.09.2010 20:42:00]

#

mika132 kirjoitti:

En usko

Tuo onkin aivan täsmälleen oikea vastaus, kun viisaammat sanovat, miten pitäisi tehdä. Alfakanavallinen PNG on ainakin ennen toiminut aivan täydellisesti, eikä sen kanssa tarvitse välittää koko color key -asiasta.

Toinen helppo ratkaisu olisi käyttää kaikissa kuvissa läpinäkyvänä mustaa ja aesttaa myös tuolle käännetylle kuvalle näin. Sekaannusten välttämiseksi pelin "mustat" asiat voi sitten piirtää hyvin tummalla harmaalla.

Deffi [29.09.2010 21:11:04]

#

Mustalta toi reuna näyttää. Mitä tapahtuu jos teet näin:

SDL_SetColorKey(kuvat::temp, SDL_SRCCOLORKEY, SDL_MapRGB(kuvat::temp->format, 0, 0, 0));

mika132 [29.09.2010 23:52:33]

#

eikun ongelma ratkes. Muutin .png kuvaksi, mutta siitä ei tule kuin ongelma perään. En käsitä miten voin lada .png kuvan temp tiedostoon rotozoomin yhteydessä, koska rotozoomihan ja piirto tapahtuu koko ajan. Peli kasvaisi ja kasvaisi kunnes kone kaatuisi. Havainnollistan:

// Ei toimiva versio (eli siis näkyy mustaa)
	kuvat::auto_1 = kuvat::lataa_png_kuva("data/kuvat/auto_1.png");
//ei mitään true:ta koska alpha kanavasta pistetty läpinäkyväksi PNG kuvaksi jo.
	kuvat::rata_1 = kuvat::lataa("data/kuvat/rata_1.bmp", true);
//jatkuvasti tapahtuvaa:
        piirra_kuva(kuvat::rata_1, 0,0);
        x_jana = (120 - kuski_1_x); /* (60 - 200) = -40 */
        y_jana = (120 - kuski_1_y); /* (80 - 100) = -20 */
        double kulma = std::atan2((double)x_jana, (double)y_jana);
        kulma += 90;
        kuvat::temp = rotozoomSurface(kuvat::auto_1, rad2deg(kulma), 1, 1);
        piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);
        kuski_1_y-=nopeus;
        SDL_FreeSurface(kuvat::temp);
//Toimiva versio, mutta raskaantuu tosiaankin nopeasti (noin 10sek 100 000Kt muistin syöntiä, koska lataa kuvaa uudestaan ja uudestaan). Kaikki muu lataus samallaista paitsi, että tässä ladataan vielä erikseen tempille oma juttu
        piirra_kuva(kuvat::rata_1, 0,0);
        x_jana = (120 - kuski_1_x); /* (60 - 200) = -40 */
        y_jana = (120 - kuski_1_y); /* (80 - 100) = -20 */
        double kulma = std::atan2((double)x_jana, (double)y_jana);
        kulma += 90;
        kuvat::temp = rotozoomSurface(kuvat::auto_1, rad2deg(kulma), 1, 1);
        kuvat::temp = kuvat::lataa_png_kuva("data/kuvat/auto_1.png");
        piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);
        kuski_1_y-=nopeus;
        SDL_FreeSurface(kuvat::temp);

Miten sen voisi muuten sitten toteuttaa?

Grez [30.09.2010 00:41:10]

#

Lataat sen yhden kerran alussa ja käytät jatkossa aina sitä jo ladattua.

Metabolix [30.09.2010 07:30:08]

#

mika132 kirjoitti:

En käsitä miten voin lada .png kuvan temp tiedostoon rotozoomin yhteydessä

En käsitä, mitä ihmettä yrität tehdä. PNG-kuvan käyttämisessä ei ole mitään ihmeellistä BMP:hen verrattuna: koodista tarvitsee muuttaa vain latausfunktion toiminta ja ottaa SDL_SetColorKey pois, ja kuvankäsittelyohjelmalla pitää vaihtaa reunaosat aidosti läpinäkyviksi.

mika132 [30.09.2010 16:37:48]

#

Kyllä. Ja yritin tuotakin systeemiä että lataan sen latausfunktiossa kerran aluksi, mutta kun kääntymis kohta tulee se "lataa" uudestaan itsensä. Eli ei toimi enää.

Yritin sen jälkeen näin:

//ensimmäinen versio:
kuvat::temp = rotozoomSurface(kuvat::auto_1, rad2deg(kulma), 1, 1);
piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);
//Tässä jää musta "viipale"

//toinen versio:
rotozoomSurface(kuvat::temp, rad2deg(kulma), 1, 1);
piirra_kuva(kuvat::temp, kuski_1_x, kuski_1_y);
//ei tapahdu mitään

ja temppiin ladattiin latausfunktiossa kuva, mutta tuossa on ongelmana se, että auto ei tee mitään. Se vain pysyy paikallaan. Se ei pyöri.

Eli miten voin muulla tavalla käyttää samaa kuvaa?

Ps. Anteeksi voi olla hieman outoa tekstiä, kun valvoin eilen noin kello 3, selvitellessäni tota, mutta en saanut selvitettyä.

jalski [30.09.2010 17:09:22]

#

Et taaskaan mieti, mitä teet. Ota rauhassa, keskity ja kokeile...

En muuten ymmärrä, mitä tarkoitat sillä, että "Lataa uudestaan itsensä"?

Jos olet määrittänyt ja ladannut tuon auton kuvan 32-bittisenä alpha-kanavaisena PNG-kuvana, niin tuo rotozoomSurface:han toimii siten, että se palauttaa uuden rotatoidun ja skaalatun pinnan (kuvan). Palautetun pinnan pitäisi olla 32-bittisessä RGBA muodossa, eli läpinäkyvyyden pitäisi toimia suoraan. Jos mietit asiaa, niin tämähän tapahtuu siksi, että pelkästään peräkkäin alkuperäistä kuvaa käsiteltäessä: pyöritettäessä ja skaalatessa tarkkuus häviäsi ja jäljestä ei kohta tulisi kovin kaunista katsottavaa.

Ps. Et taida muuten ikinä vapauttaa tuota uutta rotatoitua pintaa...

mika132 [30.09.2010 18:23:55]

#

Mahtaako se musta reikä tulla sitten jostain muusta syystä.

Ja kyllä vapautan kuvan. Annan koko lähdekoodin (joka on ehkä ihan törkeän sekainen, koska en ole sitä ehtinyt siistimään erillaisten kikkalujen takia)

Jospa teenkin vain jonkun ohjelman väärällä tavalla:
Ohjelma.cpp


Tuolla koodilla jää se musta siihen karttaan. Se on ihan alhaalla se piirto kohta. Riviltä 862 alkaen.

Metabolix [30.09.2010 18:53:23]

#

Kannattaisi ihan oikeasti opetella ymmärtämään, mitä ne funktiot tekevät, eikä vain kopioida niitä suoraan esimerkeistä.

SDL_DisplayFormat-funktion kuvauksesta:

lainaus:

If you want an alpha channel, see SDL_DisplayFormatAlpha.

Edit: Näköjään SDL_DisplayFormatAlpha-funktio osaisi muuttaa myös color keyn alfakanavaksi, joten jos pystyt asettamaan color keyn jo lataa-funktiossa, voit käyttää olemassaolevia BMP-kuviasi. Toisaalta PNG:n käytöstä on muutakin etua (kuvatiedostot ovat pienempiä), joten ehkä kannattaa vain käyttää kaikkeen sitä.

mika132 [30.09.2010 19:23:43]

#

Kiiitos!! Kiitos erittäin paljon! Nyt se toimii kuten pitääkin. Vielä kerran Kiitos kärsivällisydestänne. :D


Sivun alkuun

Vastaus

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

Tietoa sivustosta