Tai rekisteröidy jo tänään!
GameDev Suomi Pelinkehitys Apuosio
Valaistus käyttäen mp_gridiä
Sivuja: [1]

Valaistus käyttäen mp_gridiä

0 jäsentä ja 1 Vieras katselee tätä aihetta.
Aloitusviesti: 15. Maaliskuu 2017, 21:52Peukku ylös +0Peukku alas -0
Selvittelin (jälleen) järkevintä tapaa tehdä fog of war tyylistä valaistusta grideihin perustuvassa pelissä ja jossain foorumilla oli mainittu, että teoriassa mp_grideillä voi myös tehdä line-of-sight tyylisen testauksen.

Tässä jutussa olisi scripti valmiina:
http://gmc.yoyogames.com/index.php?showtopic=640738

Ajattelin että tuolla voisi loopata kaikki mp_gridin solut läpi jotka on tietyllä etäisyydellä pelaajasta/valonlähteestä. En vain pääse alkuun tuon looppaus scriptin kanssa.

Tässä havainnollistava kuva halutusta lopputuloksesta, jossa harmaat palikat edustavat mp_gridin -1 soluja eli seiniä, punainen pelaajaa ja mustat pisteet muita valonlähteitä:


Samalla kuulisin mieluusti onko tämä tapa teho-tehokas ratkaisu vai olisiko järkevämpää käyttää jotain muuta menetelmää.
Tykkään
#1: 16. Maaliskuu 2017, 08:29 (muokannut Igno 16. Maaliskuu 2017, 14:50)Peukku ylös +0Peukku alas -0
Selvittelin (jälleen) järkevintä tapaa tehdä fog of war tyylistä valaistusta grideihin perustuvassa pelissä ja jossain foorumilla oli mainittu, että teoriassa mp_grideillä voi myös tehdä line-of-sight tyylisen testauksen.

Tässä jutussa olisi scripti valmiina:
http://gmc.yoyogames.com/index.php?showtopic=640738

Ajattelin että tuolla voisi loopata kaikki mp_gridin solut läpi jotka on tietyllä etäisyydellä pelaajasta/valonlähteestä. En vain pääse alkuun tuon looppaus scriptin kanssa.

Tässä havainnollistava kuva halutusta lopputuloksesta, jossa harmaat palikat edustavat mp_gridin -1 soluja eli seiniä, punainen pelaajaa ja mustat pisteet muita valonlähteitä:


Samalla kuulisin mieluusti onko tämä tapa teho-tehokas ratkaisu vai olisiko järkevämpää käyttää jotain muuta menetelmää.

Itellä kävi nopeesti mielessä jos ton scriptin muokkais merkkaamaan jokaisen solun jonka läpi se käy scriptiä suorittaessaan. Eli käytännössä suorittais ton vaan jokasen ympyräsäteen reunasolun ja keskussolun välillä. Suorittaessa sitten merkkais niiden välilläkin olevat solut. Säästäis varmaan 80-90% funktiokutsujen määrästä.

Miten taas noi reunasolujen etsiminen kävis niin mietin  jotain tommosta:

for(var angle = 0; angle < 360; angle+=1 ) [
xplus = lenghtdir_x(angle,distance);
yplus = lenghtdir_y(angle,distande);

if xplus != xplus_previous or yplus != yplus_previous [
line_of_sight_funktio(origo_x,origo_y,origo_x+xplus,origo_y+yplus)
]

xplus_previous = xplus;
yplus_previous = yplus;


]

Kysy jos meni mun sepustukset ohi jossain kohtii / koko kirjotukselta :D

Ja tota asteiden/kulman looppausta kannattaa varmaan nopeentaa että plussaa vaikka jotain 2-5 astetta kerralla, koska nyt toi looppaa 360*2 lengthdirtii kerralla :D Toki ton vois varmaan myös toteuttaa pelin alussa ja tallentaa kaikki reunasolut johonkin ds_listiin muistiin niin säästyttäis siltäkin.
EDIT: Ja sit kans et tää laskettais uusiks pelkästään sillon kun pelaaja siirtuu mp_gridin solusta seuraavaan.
1x
Tykkään

#2: 16. Maaliskuu 2017, 17:43Peukku ylös +0Peukku alas -0
Ajattelin että tuolla voisi loopata kaikki mp_gridin solut läpi jotka on tietyllä etäisyydellä pelaajasta/valonlähteestä. En vain pääse alkuun tuon looppaus scriptin kanssa.

Tarvitseeko sen olla kummoisempi kuin jotain tämmöistä:

Koodia: [Valitse]
with (obj_valonlahde_parent) {
    //Jos tsekkaus suoritetaan joka stepissä, niin ei varmaan tartte tehdä mitään jos tämä valo ei ole liikkunut ja seinätkin pysyy paikallaan
    if (mikaan_ei_ole_muuttunut) {
        continue;
    }
   
    //Käydään gridin ruudut läpi
    for (var i = 0; i < grid_width; i++) {
        for (var j = 0; j < grid_height; j++) {
            //Ruutu on jo valaistu tai se on valon ulkopuolella, cool
            if (light_grid[#i,j] == 'valaistu' || point_distance(xpos,ypos,i,j) > distance) {
                continue;
            }
           
            //Muuten valaistaan se kun se on valon ulottuvilla
            if (ds_grid_line_of_sight(wall_grid,xpos,ypos,i,j,distance,false,false)) {
                light_grid[#i,j] = 'valaistu';
            }
        }
    }
}

Ja itse asiassa loopin voisi optimoida vielä niin, että loopataan vain pienin alue johon valo voi vaikuttaa:

Koodia: [Valitse]
    for (var i = max(0,xpos-distance); i <= min(grid_width-1,xpos+distance); i++) {
        for (var j = max(0,ypos-distance); j <= min(grid_height-1,ypos+distance); j++) {

xpos ja ypos on siis valonlähteen koordinaatit gridissä, distance on valon säde.
Tykkään
Spoiler
#3: 16. Maaliskuu 2017, 18:04Peukku ylös +0Peukku alas -0
Kiitos

Jalostin hieman tuota sinun ideaasi ja tein koodin joka laskee pisteet ypyrän kehältä 16pixelin välein jotka sitten muutan ds_gridin arvoiksi jakamalla ne 16:sta

kuva jossa testaan eri säteitä ja tarkastus pisteitä:


light_radius=56//range valolle
angle_plus=(360*16)/(2*pi*light_radius) //lasketaan tarvittava asteluku jottai välit kasva liian suuriksi kaukana ja liian pieniksi lähellä

for(var angle=0; angle<360; angle+=angle_plus )
   {
   var xplus = lengthdir_x(light_radius,angle);
   var yplus = lengthdir_y(light_radius,angle);
   
   instance_create_depth(x+xplus+8,y+yplus+8,-1,obj_dot) //luodaan pisteet merkiksi jotta asia on helpompi havainnollistaa ja tarkistaa että koodi toimii
   }


... eli seuraavaksi lisään scriptin ja tallenna uudet tietot gridiin
1x
Tykkään
#4: 16. Maaliskuu 2017, 18:16Peukku ylös +0Peukku alas -0
Tarvitseeko sen olla kummoisempi kuin jotain tämmöistä:

Koodia: [Valitse]
with (obj_valonlahde_parent) {
    //Jos tsekkaus suoritetaan joka stepissä, niin ei varmaan tartte tehdä mitään jos tämä valo ei ole liikkunut ja seinätkin pysyy paikallaan
    if (mikaan_ei_ole_muuttunut) {
        continue;
    }
   
    //Käydään gridin ruudut läpi
    for (var i = 0; i < grid_width; i++) {
        for (var j = 0; j < grid_height; j++) {
            //Ruutu on jo valaistu tai se on valon ulkopuolella, cool
            if (light_grid[#i,j] == 'valaistu' || point_distance(xpos,ypos,i,j) > distance) {
                continue;
            }
           
            //Muuten valaistaan se kun se on valon ulottuvilla
            if (ds_grid_line_of_sight(wall_grid,xpos,ypos,i,j,distance,false,false)) {
                light_grid[#i,j] = 'valaistu';
            }
        }
    }
}

Ja itse asiassa loopin voisi optimoida vielä niin, että loopataan vain pienin alue johon valo voi vaikuttaa:

Koodia: [Valitse]
    for (var i = max(0,xpos-distance); i <= min(grid_width-1,xpos+distance); i++) {
        for (var j = max(0,ypos-distance); j <= min(grid_height-1,ypos+distance); j++) {

xpos ja ypos on siis valonlähteen koordinaatit gridissä, distance on valon säde.

Sinänsä simppeli ratkaisu, mutta ajattelin tehdä fog-of-warin lisäksi realiaika valon joka näkyy kirkkaampana kun valonlähde lähellä sen lisäksi että jo nähdyt alueet näkyy harmaampana. Ymmärtääkseni tuolla tavalla tarkistus scriptejä tulee huomattavasti enemmän laskettavaksi, kuin silloin jos lasktaan vain kehän reunalla olevat pisteet, vaikkakin tarkistus on tarkoitus tehdä vain silloin kuin pelaaja snappaa uuteen ruutuun.

Eli koska line-of-sight tarkastuksia tulee joka tapauksesas paljon niin täytyy yrittää minimoida tarkistettavat pisteet...
Tykkään
#5: 16. Maaliskuu 2017, 18:40Peukku ylös +0Peukku alas -0
Sen olisin sanonut seuraavaksi, että jos optimointi on hirmu tärkeää, niin ei varmaan kannata käyttää tuota linkkaamaasi funkkaria ihan sellaisenaan. Sehän joka tapauksessa tutkii kaikki ruudut kahden määrätyn ruudun välillä, joten vähän muokkaamalla se voisi saman tien merkitä ne valaistuiksi.
Tykkään
Spoiler
#6: 16. Maaliskuu 2017, 23:57 (muokannut Dart 17. Maaliskuu 2017, 11:24)Peukku ylös +0Peukku alas -0
Hmm..aika raskaaksi menee... ensin ajattelin että 16pixelin välein tehty tarkastus riittäisi, mutta kuten alimmasta kuvasta näkee niin silloin valo auraan jää aukkoja. Ensimmäisessä kuvassa välit on 3 pixeliä, jolloin scripti suoritetaan yli 70 kertaa :) (keskimmäinen kuva on 100pixelin välein josta näkee hyvin "säteen" toimintalogiikan)



Jos jollakulla on parempia ideoita toteuttaa tämä niin kuuntelen mielelläni. Idea on että valon tulee pysähtyä seinään eli ei riitä, että valaistaan ympyrän muotoinen alue.
Tykkään
#7: 17. Maaliskuu 2017, 07:11 (muokannut karhu 17. Maaliskuu 2017, 07:14)Peukku ylös +0Peukku alas -0
Pystyisikös tätä käyttämään tuossa apuna? http://www.roguebasin.com/index.php?title=Restrictive_Precise_Angle_Shadowcasting

Tai tämä http://playtechs.blogspot.fi/2007/03/raytracing-on-grid.html?m=1
Tykkään
WWW: ROITTO.INFO
TWEET: @PRoitto
#8: 18. Maaliskuu 2017, 13:46Peukku ylös +0Peukku alas -0
Pystyisikös tätä käyttämään tuossa apuna? http://www.roguebasin.com/index.php?title=Restrictive_Precise_Angle_Shadowcasting

Tai tämä http://playtechs.blogspot.fi/2007/03/raytracing-on-grid.html?m=1

Kiinnostavia juttuja, mutta vaikutti turhan työläälätä saada toimimaan. Sain kuitenkin optimoitua nykyistä koodiani niin, että tarkistettavien solujen määrä putosi 1400->700:n 10 ruudun valonsäteellä. Tämä onnistui kuin huomasin, ettei tarkistusympyrä ole täysin pyöreä joka aiheutti "reikiä"/pimeitä pilkkuja ympyrän reunoille suurmemmilla asteväli-tarkistuksilla. Lisäksi tajusin että lähimmät solut voi määrittää näkyväksi aina joten niitä ei tarvitse erikseen testata. Nämä solut olivat muutenkin eniten testattuja joka yksinään tuotti 80kpl testauksia vähemmän. Hyöty korostuu varsinkin jos valon kehää suurrennetaan jolloin lähimpien solujen tarkistukseen saatettiin käyttää helposti 200 kertaa.

Optimaalinen ratkaisuhan olisi että testattaisiin vain nuo n.400 ruutua, mutta 700 on close enough :)

Testauskerra havainnolistavassa kuvassa:
1x
Tykkään
#9: 21. Maaliskuu 2017, 13:00 (muokannut Dart 21. Maaliskuu 2017, 13:02)Peukku ylös +2Peukku alas -0
Jes sain koodin toimimaan haluamallani tavalla! Eli nyt "valo"-tarkistus pysähtyy näkymättömiin grid-seiniin. Koodikin on sitä kevyempi mitä enmmän seiniä ympärillä :)


Täytyy vielä hieman tuunata tuota tarkastuskoodia niin voisin siitä tuupata vaikka tutoriaalin kun toimii.
Tykkään
#10: 20. Huhtikuu 2017, 17:36 (muokannut Dart 20. Huhtikuu 2017, 17:51)Peukku ylös +1Peukku alas -0
Noniin
Nyt on koodia optimoitu ja etsitty taian omaisia numeroita tunti kausia. Tein taulukon josta selviää hyvin mitä valonsäteitä voi käyttää ja mitä kannattaa valita käyttöön. Muutana light_radius löytyi myös jotka eivät toteuta täyttä valaistusta koskaan :)

Esimerkiksi light_radius 7.5 on huomattavasti kevyempi suorittaa kuin light_radius 6.5 vaikka valaiseekin yhden ruudun pidemmälle. Tämäjohtuu siitä että 6.5 radius joutuu tarkistamaan säteen 10.2 pikselin välein jotta koko alue saadaan valaistua kun taas radius 7.5 saa alueen katettu 15.7 pixelin tarkistusvälillä.

Väleistä varmasti löytyisi lisää näitä eeppisiä radius numeroita joilla tarkistus olisi mahdollisimman kevyt, mutta nyt alkuun tarkistin vain 0,5 ruuden välit, pois lukian paria 0,25 väliä jotka testasin.


//light_radius 16   | angle_plus 7.1   | tarkistukset 3091
//light_radius 15.5   | angle_plus 5.9   | tarkistukset 3511
//light_radius 15   | EI VOI KÄYTTÄÄ
//light_radius 14.5   | angle_plus 8.1   | tarkistukset 2244
//light_radius 14   | angle_plus 5.5   | tarkistukset 3040
//light_radius 13.5    | EI VOI KÄYTTÄÄ
//light_radius 13.25  | angle_plus 11.9   | tarkistukset 1267
//light_radius 13       | EI VOI KÄYTTÄÄ
//light_radius 12.5    | angle_plus 12.1   | tarkistukset 1108
//light_radius 12   | angle_plus 11.6   | tarkistukset 1043
//light_radius 11.5   | angle_plus 7.6   | tarkistukset 1497
//light_radius 11   | angle_plus 11.5   | tarkistukset 883
//light_radius 10.5   | angle_plus 13.2   | tarkistukset 698
//light_radius 10   | EI VOI KÄYTTÄÄ
//light_radius 9.5   | angle_plus 13.3   | tarkistukset 571
//light_radius 9     | angle_plus 12.6   | tarkistukset 529
//light_radius 8.5   | EI VOI KÄYTTÄÄ
//light_radius 8.25   | angle_plus 13      | tarkistukset 436
//light_radius 8    | angle_plus 11.2   | tarkistukset 466
//light_radius 7.5   | angle_plus 15.7   | tarkistukset 296
//light_radius 7    | angle_plus 11      | tarkistukset 361
//light_radius 6.5   | angle_plus 10.2   | tarkistukset 349
//light_radius 6    | angle_plus 15.1   | tarkistukset 189
//light_radius 5.5   | angle_plus 13.8   | tarkistukset 176
//light_radius 5    | angle_plus 16      | tarkistukset 119
//light_radius 4.5   | angle_plus 14.2   | tarkistukset 116


Ei tästä varmaan kukaan saanut mitään irti mutta postasin tämän tänne läinnä siksi kun olen itse tyytyväinen lopputulokseen :D plus numeroiden louhinta oli kivaa.

edit.
Vertailun vuoksi edellisessä Realmrama versiossa tarkistus tehtiin n. 3-5 pixelin välein eli jos nyt pärjätään esim 13pixelin väleillä per valonlähde niin tehon säästö on huomattava. Kaaviosta voi myös päätellä ettei säteeltään 13.25 ruutua suurempia valonlähteitä kannta juuri käyttää, koska tarkistus kerrat kasvavat exponentiaalisesti.

Alkuperäinen suunnitelma oli käyttää heron näkörangena 10 tai 11, mutta nyt ilmeni selvästi että 10.5 on järkevin. Testaan varmaan nyös muutamaa muuta desimaalia välistä.
1x
Tykkään
#11: 16. Kesäkuu 2017, 23:19Peukku ylös +0Peukku alas -0
Nopee kyssäri

Kumpi on tehollaampaa:
1. Piirtää musta ruutu draw_sprite_ext() ja laittaa alphaksi 0.5
2. Laittaa spriten alphaksi 0.5
Tykkään
#12: 17. Kesäkuu 2017, 13:28Peukku ylös +0Peukku alas -0
Jos on se mahdollisuus ilman kauheaa kikkailua, niin spriteen alphan laittaminen valmiiksi on tehokkaampaa.
En nyt satavarmaksi muista miten draw_sprite_ext() mahtoi käsitellä noita, mutta jos laitat koodilla draw_set_alpha() / draw_set_color() niin nämä on raskaita, sillä GM joutuu tekemään kokonaisen texture swapin jotta se saa värjättyä kaikki pelin kuvat tuohon sävyyn, vaikka sen tekisikin vain yhdelle spritelle. Tällöin siitä tulee jo kaksi "turhaa" texture page swappia.
Tykkään
Lainaus käyttäjältä: ElNinja -2015
Ei normaalit ihmiset yritä paeta.
http://www.facebook.com/stillrunninggame
http://www.stillrunning.fi
#13: 18. Kesäkuu 2017, 12:52Peukku ylös +0Peukku alas -0
Jees, näin tein. Game maker studio 2:ssa pystyy spriten layerille asettamaan opacityn eli käytännössä alpha asetus on silloin spritessä eikä sitä varmaan tarvitse laskea sen enempää sitten piirtäessä.
Tykkään

Sivuja: [1]
GameDev Suomi Pelinkehitys Apuosio
Valaistus käyttäen mp_gridiä
 

Powered by SMF 2.0.11 | SMF © 2006–2009, Simple Machines LLC