Tämmösen funktion olisi tarkoitus kertoa, missä heksassa annettu piste/pikseli sijaitsee. Ongelma on, että kun piste on heksan reunalla, funktio palauttaa joskus reunan toisen puolen heksan ja joskus toisen puolen. Riippuu käsittääkseni siitä miten ne pisteen desimaalit sattuivat asettumaan tai jotain semmosta.
Käytin ohjeena GameDev.netin Coordinates in Hexagon-Based Tile Maps-artikkelia. Tosin heksa on 90 astetta eri suunnassa.
Käytetyt muuttujat lasketaan heksaluokan konstruktorissa, jonka parametrinä on heksan a-mitta tai s-mitta.
a = 2*r b = h+s -- = h ____ / \ | / \ | = b \ / | \____/ | ---- = s | / |\ | | |/ | \___| | = ruutukor |\ A | / B | | |_\___|/____| | ----- = ruutulev
Luulisin että jotain koordinaatteja pitäisi jossain kohtaa pyöristää. Mutta missä ja mitä? Taikka sitten pitäisi käyttää <= ja >= -operaatioita siinä vaiheessa kun tarkastellaan ollaanko suoran vasemmalla vaiko oikealla puolella?
def a_hx(self, x,y): # origon siirto x += self.h + self.s * 0.5 y += self.r # missä ruudussa ollaan rx = x // self.ruutulev ry = y // self.ruutukor # onko ruutu A-tyyppinen # round(rx)? Atyyppinen = not( int(rx) & 1 ) # missä ruudun pisteessä ollaan px = x - rx * self.ruutulev py = y - ry * self.ruutukor # osoittaako piste oikeata heksaa # jos ei niin siirrytään viereiseen heksaan # A-tyyppinen if Atyyppinen: # yläosa if py > self.r: # vasen osa if py > self.k * px + self.r: return rx-1,ry # oikea osa else: return rx,ry # alaosa else: # vasen osa if py < - self.k * px + self.r: return rx-1,ry-1 # oikea osa else: return rx,ry # B-tyyppinen else: # yläosa if py > self.r: # vasen osa if py < - self.k * px + self.r * 2: return rx-1,ry # oikea osa else: return rx,ry # alaosa else: # vasen osa if py > self.k * px: return rx-1,ry # oikea osa else: return rx,ry-1
Liukuluvuilla et voi odottaa saavasi tarkkaa tulosta. Vaikka piste liikkuisi täsmälleen rajaa pitkin, eri arvoilla voi tulla erilaisia pyöristysvirheitä, joiden takia algoritmi ilmoittaa vuorotellen kahta yhtä hyvää vaihtoehtoa. En tiedä ohjelmasi lähtökohtia, mutta yksi ratkaisu on sijainnin jatkuva pyöristely niin karkealle tarkkuudelle, ettei pyöristysvirhe muuta tuon laskun tulosta. Toinen vaihtoehto on tallentaa edellinen tulos ja muuttaa vastausta vain, jos ollaan jo selvästi toisen ruudun puolella.
Eksoottisempi ratkaisu olisi vaihtaa ohjelma käyttämään koordinaatistoa, jossa akselit olisivat 120° (tai 60°) kulmassa toisiinsa nähden, mutta tämä täytyisikin sitten huomioida aika monessa paikassa.
Ongelman lähtökohta näkyy jotenkin tässä kuvassa.
Jokainen pieni heksa kuuluu johonkin isoon heksaan. Pienten ja isojen heksojen koordinaatiston origot on samassa kohtaa. Tarkoitus olisi, että isot heksat olisivat kaikki samankokoisia esim 5 heksaa per sivu. Pienissä heksoissa näkyvien koordinaattien värit kertovat mihin isoon heksaan ne kuuluvat. Ongelma näkyy mm. heksassa (4,7) joka on siis sininen vaikka voisi luulla sen kuuluvan oikealla alapuolella olevaan isoon heksaan.
Tuli juuri mieleeni että täytyyköhän ison heksan a-mitan olla pienen heksan b-mitan tai (s + h)-mitan kerrannainen. Mutta tuskimpa sentään.
Metabolix kirjoitti:
Eksoottisempi ratkaisu olisi vaihtaa ohjelma käyttämään koordinaatistoa
Onnistuu kohtalaisen nopeasti kun mulla on vielä toi paperisuunnitelma tallessa, mutta luulen ettei koordinaatiston vaihtaminen ratkaise tätä vaan justiin joku pyöristäminen.
Sun pitää lähinnä päättää millä säännöillä mikin useampaan isoon kuuluva pieni kuuluu mihinkin. Tai jos et tee selkeää sääntöä niin voit yhtä hyvin arpoa mihin ne kuuluu.
Säännöt menee sillain että pieni heksa kuuluu isoon heksaan, jonka sisäpuolella pienen heksan keskipiste sijaitsee.
Noitten isojen raja menee noitten pienten keskipisteen kohdalta, joten noi rajalla olevat palat pitäisi sitten olla rajan värisiä?
Eli siirrä jomman kumman origoa pari pikseliä sivuun niin homma toimii säännönmukaisesti. Vaikka 2 pikseliä ylös ja 2 vasemmalle.
pipo kirjoitti:
Säännöt menee sillain että pieni heksa kuuluu isoon heksaan, jonka sisäpuolella pienen heksan keskipiste sijaitsee.
Pienet kulmiot ovat rajalla, kuten Grez sanoi. Ratkaisusi ei siis toimi ilman ehdotettua kikkailua.
pipo kirjoitti:
Luulen ettei koordinaatiston vaihtaminen ratkaise tätä vaan justiin joku pyöristäminen.
Kyllä se ratkaisisi. Koordinaatisto voisi mennä niin, että y kasvaisi ylävasemmalle ja x kasvaisi yläoikealle. Tällöin oikealle x kasvaisi ja y pienenisi. Ruudun etäisyys toisesta (kulmioita pitkin) laskettaisiin kaavalla max(abs(dx), abs(dy), abs(dx + dy)). Saat etäisyyden kokonaislukuna, jolloin ei tule pyöristysvirheitä. Rajatapaukset voit ratkaista yksinkertaisesti niin, että riitapukareista valitaan ensisijaisesti alempana oleva, tai jos kaksi on yhtä alhaalla, näistä vasemmanpuoleinen.
Testasinkin koordinaatistoa, ks. kuva. Käytin seuraavia muunnosfunktioita ja etäisyysfunktiota (kielenä JavaScript):
// Muunnos kuusikulmioista oikeaksi: function hex2euc(p) { return { "x": (p.x - p.y) * 0.5, "y": (p.x + p.y) * Math.sqrt(3) / 2 }; } // Muunnos oikeasta kuusikulmioiksi: function euc2hex(p) { return { "x": p.y / Math.sqrt(3) + p.x, "y": p.y / Math.sqrt(3) - p.x }; } // Kuusikulmiopisteiden etäisyys kokonaisina kuusikulmioina: function hexdist(a, b) { var dx = b.x - a.x; var dy = b.y - a.y; return Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dx + dy)); }
Aihe on jo aika vanha, joten et voi enää vastata siihen.