Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Ajopelin törmäyshallinta

punppis [16.09.2010 21:17:36]

#

Ei ole tuo matematiikka ihan vahvinta, joten kysyn täältä. Jos tiedän (suorakulmion muotoisen) objektin leveyden, korkeuden, x- ja y-koordinaatin sekä rotaation (asteina tai radiaaneina), niin miten saan selville mitkä pikselit se vie näytöltä (tai mahdollisesti vain kulmassa olevat pikselit). X ja y koordnaatit ovat objektin keskeltä.

Teen siis 2D-ajopeliä, jossa tarkastan törmäyksen kartan värin avulla: jos auton alueella on muuta kuin x-värillisiä pikseleitä, niin törmäys on tapahtunut.

Tässä vielä kuva havainnollistamaan. Tarkoitus on siis saada sinisen neliön jokaisen pikselin koordinaatti.

Jokotai [16.09.2010 21:27:29]

#

Selittäisitkö mitä tarkoitat kohdalla: "mitkä pikselit se vie näytöltä (tai mahdollisesti vain reunimmaiset pikselit)" Tarkoitatko siis, että mitkä ovat näytön reunimmaiset pikselit? Jos niin, niin vastaus on: "Useat graafiset-kirjastot pitävät sisällään ikkunankoon palauttavat arvot."

Voisit lisäksi kertoa, että mitä graafista-kirjastoa käytät.

punppis [16.09.2010 21:35:58]

#

Käytän C#:aa ja XNA:ta. Haluan siis saada tietooni, mitkä pikselit näytöllä sininen laatikko täyttää.

Metabolix [16.09.2010 21:49:44]

#

Sivujen pituuksista saadaan suoraan kulmien sijainnit, kun objekti on suorassa, ja näistä voidaan laskea tavallisilla pyörityskaavoilla kulmien sijainnit kääntyneessä objektissa. Kun tulokseen lisätään objektin sijainti, saadaan kulmien todelliset sijainnit pelimaailmassa.

Kulmien välisiä pisteitä voisi laskea jollain hienolla viiva-algoritmilla, mutta nykykoneilla on yleensä turha kikkailla tällaisen pikkujutun takia, joten yksinkertainen liukulukulaskukin riittää:

// Tarkistetaan, osuuko sivu.
bool osuma(piste a, piste b) {
  float len = sivun_pituus; // Kaiva jostain tai laske Pythagoraan lauseella
  float dx = (b.x - a.x) / len;
  float dy = (b.y - a.y) / len;

  for (int i = 0; i < len; ++i) {
    float x = a.x + i * dx;
    float y = a.y + i * dy;
    if (onko_seina((int) x, (int) y)) {
      return true;
    }
  }
  return false;
}

// Koko kulmion tarkistuksessa tietysti tutkitaan kaikki sivut:
bool osuma(piste a, piste b, piste c, piste d) {
  return osuma(a, b) || osuma(b, c) || osuma(c, d) || osuma(d, a);
}

(Tarkkasilmäinen ehkä huomaa, että ensimmäinen tarkistusfunktio jättää päätepisteen b tarkistamatta. Tämä kuitenkin korjautuu sillä, että seuraava kutsu osuma(b,c) aloittaa juuri siitä.)

punppis [20.09.2010 00:26:05]

#

Nyt hetken testailtuani, haluaisin sittenkin per-pixel törmäyksen tunnistuksen. Yritän tehdä tätä siten, että ensin teen taulukon autossa olevista värillisistä pikseleistä. Hommaa toimii hienosti ilman rotaatiota, mutta heti kun yritän kääntää tuota taulukkoa, niin homma kusee ja koordinaateista tulee ihan vääriä.

class Koordinaatti {
   float x, y, pituus;
   void LaskeKulmat(float rotaatio) {
       x += (float)Math.Cos(rotaatio * Math.PI / 180) * pituus;
       y += (float)Math.Sin(rotaatio * Math.PI / 180) * pituus;
   }
}

Koordinaatti-luokassa (tästä olen siis tehnyt taulukon) on siis x- ja y-sijainti, sekä sijainnin etäisyys objektin keskipisteestä. Heti kun ajan LaskeKulmat-funktion, niin homma räjähtää käsiin. Miten saisin tuon rotaation toimimaan?

Grez [20.09.2010 00:35:34]

#

Ei tuossa kyllä ole mitään järkeä. Ota kynä käteen ja piirrä paperilla mitä tuossa tapahtuu...

Oikea tapa kiertää origon ympäri olisi jotakuinkin:

class Koordinaatti {
   float x, y;

   void Kierrä(float rotaatio) {
       float oldX=x, oldY=y;
       x = (float)Math.Cos(rotaatio) * oldX - Math.Sin(rotaatio) * oldY;
       y = (float)Math.Cos(rotaatio) * oldY + Math.Sin(rotaatio) * oldX;
   }
}

Laitoin nyt tuossa että rotaatio annettaisiin suoraan radiaaneina funktiolle.

Parempi idea on säilöä ne alkuperäiset pisteet ja sitten vaan tehdä eri asentoja varten uudet laskut alkuperäisestä, kuin kääntää olioon tallennettuja uudestaan ja uudestaan kunnes ne sekoavat epätarkkuuden kumuloituessa.

punppis [21.09.2010 21:42:14]

#

Pitää kyllä myöntää, että nämä rotaatiot ei ole kyllä ihan vahvinta alaani... Tajusin virheeni jossain vaiheessa ja tällä hetkellä ratkaisu on sellainen, että minulla on taulukossa pikselin suunta asteina keskipisteestä sekä sen etäisyys keskipisteeseen. Tällä tavoin sain koodin toimimaan vallan mainiosti tuolla edellisellä koodilla.

Vastaus

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

Tietoa sivustosta