Loputtomat viholliset, yksilöinti ja MAVit (ratkaistu)

Voit pyytää apua ohjelmointiongelmiin täältä.
Post Reply
User avatar
Cebez
Newcomer
Posts: 3
Joined: Thu Sep 08, 2011 8:24 pm

Loputtomat viholliset, yksilöinti ja MAVit (ratkaistu)

Post by Cebez » Thu Sep 08, 2011 10:30 pm

Iltaa.

Aloittelin tässä noin kahden vuoden tauon jälkeen taas jonkinlaista CoolBasic-ohjelmointiharrastusta, suhteellisen hyvin
vielä muistan ne silloin opetellut asiat, joten en kuitenkaan ihan tyhjiltä aloittele, siitä sitten asiaan.

Lyhyesti sanottuna, tein räiskintäpelipohjan jossa liikutaan WASD-näppäimillä ja ohjataan hiirellä (hiirikursorin tilalla tähtäin).
Ampumisjärjestelmä toimii lähes moitteettomasti, viholliset syntyvät satunnaisiin pisteisiin kartalla muutaman sekunnin välein.

Ongelmaksi on nyt muodostunut sellainen asia, että en osaa yksilöidä niitä kloonivihollisia jotka sinne kartalle syntyvät "päävihusta", eli toisin sanoen,
kun saan ohjelman poistamaan "vihu\obj" in, se poistaa samalla kaikki kartalla olevat klooniviholliset. Tosin yleensä en saa tätä tapahtumaan, vaan kokeiluyrityksilläni
oli suurimmalla osalla tuloksena vihollisen ampumisesta seuraava MAV.

Ymmärrän MAVin käsitteen, sen että yritetään käyttää jotain objektia joka on poistettu jo muistista, mutta en millään keksi miten tämän saisi sivuutettua.
Apua olen jo etsinyt näiltä foorumeilta, mutta kaikissa tapauksissa niissä annetut vastaukset eivät toimineet minulla.

Toinen ongelma yksilöintiin liittyen on se, että en osaa luoda kloonivihollisten välile törmäystunnistusta. Paras mitä keksin oli suurinpiirtein tämännäköinen:

Code: Select all

SetupCollision vihu\obj, vihu\obj, 2, 2, 2
Ylläoleva ei tietenkään toimi, koska siinähän yritetään luoda törmäystunnistus objektin itsensä kanssa.

Eli loppuun lyhyesti tiivistettynä: Kuinka yksilöin tyyppikirjastosta (<-- oikea nimitys?) luotuja kloonivihollisia?

Liitin koodin, että voitte halutessanne tarkistella sitä:

Code: Select all

SCREEN 1280, 800
FrameLimit 60

Gosub LoadData

Type LUODIT
    Field obj
End Type

Type VIHUT
    Field obj
    Field health
End Type

mSpeed = 2
gPower = 5

SetupCollision pHahmo, kartta, 2, 4, 2

'PlaySound Music

Repeat
    
    RotateObject pHahmo, -GetAngle(ObjectX(pHahmo), ObjectY(pHahmo), MouseWX(), MouseWY())
    
    Gosub CheckControls
    Gosub SpawnEnemies
    Gosub GiveAI
    Gosub CheckBullets
    
    CloneCameraPosition pHahmo
    
    DrawScreen 
    
    
Until EscapeKey()  



LoadData:

    kartta = LoadMap("Media/cdm2.til","Media/tileset.bmp")
    PlayObject kartta, 0, 0, 1

    Global pHahmo
    pHahmo = LoadObject("Media/soldier.bmp", 72)

    Global pääVihu
    pääVihu = LoadObject("Media/guy.bmp", 72)
    ShowObject pääVihu, OFF
    PositionObject pääVihu, -200, 0

    Global pati
    pati = LoadObject("Media/bullet.bmp")
    ShowObject pati, OFF
    
    Global shot
    shot = LoadSound("Media/gun 1.wav")
    music = LoadSound("Media/Sk_Battle2.mp3")
    huuto = LoadSound("Media/scream1.wav")

    tähtäin = LoadImage("Media/crosshair.bmp")
    ShowMouse tähtäin
    HotSpot tähtäin, ImageWidth(tähtäin) / 2, ImageHeight(tähtäin) / 2
    
Return
    
  
    
CheckControls:

    If KeyDown(cbKeyW) Then MoveObject pHahmo, mSpeed
    If KeyDown(cbKeyS) Then MoveObject pHahmo, -mSpeed
    If KeyDown(cbKeyA) Then MoveObject pHahmo, 0, -mSpeed
    If KeyDown(cbKeyD) Then MoveObject pHahmo, 0, mSpeed
    If KeyDown(cbKeyLShift) Then mSpeed = 5 Else mSpeed = 2
    If KeyHit(cbKeyT) Then TeleportObject(pHahmo)
    
    If MouseHit(1) And reload=0 Then
       Shoot(pHahmo)
       'PlaySound shot
       reload=5
    EndIf
    If MouseDown(2) And reload=0 Then
        Shoot(pHahmo)
        reload=2
    EndIf
    
    If reload>0 Then reload = reload-1 
    
Return
    
  
    
CheckBullets:
    For vihu.VIHUT = Each VIHUT
        tuhoaVihu = 0
        For luoti.LUODIT = Each LUODIT
            MoveObject luoti\obj, gPower
            If ObjectsOverlap(vihu\obj, luoti\obj) Then
                tuhoaVihu = 1
                DeleteObject luoti\obj
                Delete luoti
            ElseIf GetMap(2, ObjectX(luoti\obj), ObjectY(luoti\obj)) Then
                DeleteObject luoti\obj
                Delete luoti
            EndIf
        Next luoti
        If tuhoaVihu = 1 Then
            DeleteObject vihu\obj
            Delete vihu
        EndIf
    Next vihu
Return



SpawnEnemies:

    If vihuAjastin = 0 Then
        vihu.VIHUT = New(VIHUT)
        vihu\obj = CloneObject(pääVihu)
        'vihu\health = 100
        SetupCollision vihu\obj, kartta, 2, 4, 2
        SetupCollision vihu\obj, pHahmo, 2, 2, 2    
        TeleportObject(vihu\obj)
        vihuAjastin = 120
    EndIf

    If vihuAjastin>0 Then vihuAjastin = vihuAjastin - 1

Return


GiveAI:

    For vihu.VIHUT = Each VIHUT
        'If vihu\health >= 0 Then
            If ObjectSight(vihu\obj, pHahmo) Then
                PointObject vihu\obj, pHahmo
                MoveObject vihu\obj, 2
            EndIf  
       'EndIf
    Next vihu 
    
Return



Function Shoot(_obj)

    luoti.LUODIT = New(LUODIT)
    luoti\obj = CloneObject(pati)
    CloneObjectPosition luoti\obj, _obj
    CloneObjectOrientation luoti\obj, _obj
    MoveObject luoti\obj, 15

End Function



Function TeleportObject(_obj)

        X = Rand(1, MapWidth())
        Y = Rand(1, MapHeight())
        tausta = GetMap2(0, x, y)
        törmäys = GetMap2(2, x, y)
        
        If tausta > 0 And törmäys = 0 Then
            WX = (X * 32 - 16) - ((MapWidth() * 32) / 2)
            WY = ((Y * 32 - 16) - ((MapHeight() * 32) / 2)) * -1
            PositionObject _obj, WX, WY
            RotateObject _obj, Rand(0, 360)
        EndIf 
    
End Function
Kiitos jo näin etukäteen.
Last edited by Cebez on Fri Sep 09, 2011 3:35 pm, edited 6 times in total.
Aloittelija

User avatar
Latexi95
Guru
Posts: 1164
Joined: Sat Sep 20, 2008 5:10 pm
Location: Lempäälä

Re: Loputtomat viholliset, yksilöinti ja MAVit

Post by Latexi95 » Thu Sep 08, 2011 11:38 pm

Cebez wrote:Iltaa.

Aloittelin tässä noin kahden vuoden tauon jälkeen taas jonkinlaista CoolBasic-ohjelmointiharrastusta, suhteellisen hyvin
vielä muistan ne silloin opetellut asiat, joten en kuitenkaan ihan tyhjiltä aloittele, siitä sitten asiaan.

Lyhyesti sanottuna, tein räiskintäpelipohjan jossa liikutaan WASD-näppäimillä ja ohjataan hiirellä (hiirikursorin tilalla tähtäin).
Ampumisjärjestelmä toimii lähes moitteettomasti, viholliset syntyvät satunnaisiin pisteisiin kartalla muutaman sekunnin välein.

Ongelmaksi on nyt muodostunut sellainen asia, että en osaa yksilöidä niitä kloonivihollisia jotka sinne kartalle syntyvät "päävihusta", eli toisin sanoen,
kun saan ohjelman poistamaan "vihu\obj" in, se poistaa samalla kaikki kartalla olevat klooniviholliset. Tosin yleensä en saa tätä tapahtumaan, vaan kokeiluyrityksilläni
oli suurimmalla osalla tuloksena vihollisen ampumisesta seuraava MAV.

Ymmärrän MAVin käsitteen, sen että yritetään käyttää jotain objektia joka on poistettu jo muistista, mutta en millään keksi miten tämän saisi sivuutettua.
Apua olen jo etsinyt näiltä foorumeilta, mutta kaikissa tapauksissa niissä annetut vastaukset eivät toimineet minulla.

Toinen ongelma yksilöintiin liittyen on se, että en osaa luoda kloonivihollisten välile törmäystunnistusta. Paras mitä keksin oli suurinpiirtein tämännäköinen:

Code: Select all

SetupCollision vihu\obj, vihu\obj, 2, 2, 2
Ylläoleva ei tietenkään toimi, koska siinähän yritetään luoda törmäystunnistus objektin itsensä kanssa.

Eli loppuun lyhyesti tiivistettynä: Kuinka yksilöin tyyppikirjastosta (<-- oikea nimitys?) luotuja kloonivihollisia?

Voin liittää lähdekoodini, jos haluatte.

Kiitos jo näin etukäteen.
No oikeastaan ne ovat jo yksittäisiä eikä klooni objektin poistamisen pitäisi poistaa kaikkia muita objekteja. Joten veikkaan, että sinun koodissasi on jossain kohti virhe joka aiheuttaa kaikkien vihollisten poistamisen.

Jos haluat törmäystunnistuksen vihollisten välille tee tälläinen silmukka:

Code: Select all

if uusivihu then
   uv.vihut = new(vihut)
   uv\obj = CloneObject(master_vihu)

   For vv.vihut = Each vihut
       if vv <> uv then
            SetupCollision uv\obj,vv\obj,2, 2, 2
            SetupCollision vv\obj,uv\obj,2, 2, 2
       endif
   next vv
endif

Ja tervetuloa foorumeille. :D

Awaclus
Forum Veteran
Posts: 2939
Joined: Tue Aug 28, 2007 2:50 pm

Re: Loputtomat viholliset, yksilöinti ja MAVit

Post by Awaclus » Fri Sep 09, 2011 9:26 am

Cebez wrote: kun saan ohjelman poistamaan "vihu\obj" in, se poistaa samalla kaikki kartalla olevat klooniviholliset. Tosin yleensä en saa tätä tapahtumaan, vaan kokeiluyrityksilläni oli suurimmalla osalla tuloksena vihollisen ampumisesta seuraava MAV.
On top of my head:

Code: Select all

For ivihu.vihut = Each vihut 'käydään kaikki vihut läpi
    tuhoavihu = 0 'oletuksena on, että vihua ei tuhota
    For iammus.ammukset = Each ammukset 'käydään kaikki ammukset läpi
        If ObjectsOverlap (ivihu\obj, iammus\obj) Then 'jos vihu osuu ammukseen
            tuhoavihu = 1 
            DeleteObject iammus\obj
            Delete iammus 'myös tyyppikokoelman jäsen täytyy muistaa poistaa
        EndIf
    Next iammus
    If tuhoavihu Then
        DeleteObject ivihu\obj
        Delete ivihu 'ja edelleen se jäsen pitää poistaa
    EndIf
Next ivihu
En jaksa nyt alkaa kokeilemaan, pitäisi toimia. Ja tervetuloa foorumille.

User avatar
Cebez
Newcomer
Posts: 3
Joined: Thu Sep 08, 2011 8:24 pm

Re: Loputtomat viholliset, yksilöinti ja MAVit

Post by Cebez » Fri Sep 09, 2011 12:08 pm

Kiitokset kummallekin avusta.

En vielä ehtinyt perehtymään tuohon törmäystunnistukseen, mutta kuitenkin sain nyt korjattua ne objektien
poistamisen aiheuttamat MAVit, ja näyttäisi siltä, että vihollisten tappaminen ja seiniin ampuminen toimii nyt moitteettomasti.

Sain sen toimimaan kirjoittamalla uudestaan koko CheckBullets-aliohjelman käyttäen tuota Chaoswormin tekemää koodinpätkää (että kiitokset siitä!).
Ilmeisesti vanhassa koodissani oli jonkinlainen ristiriita, joka niitä MAVeja aiheutti, otin sen vielä talteen, että joskus kun on aikaa niin voin sitä tarkastella
ja miettiä mikä siinä oli vialla.

Sen verran vielä, että nyt olen ilmeisesti antanut luodeille jonkinlaisen kiihtyvyyden, koska huomasin että välillä kun ammuin, luotien nopeus kasvoi
välillä noin kaksinkertaiseksi (ja välillä ne myös pysähtyivät täysin, muu peli tosin jatkui normaalisti) mutta uskon että tämä ongelma ratkeaa pian.

Kunhan palaan takaisin alan työstämään tuota törmäyksentunnistusta, että kiitokset Latexi95:lle tuosta koodinpätkästä.

EDIT: Näyttäisi siltä, että mitä enemmän vihollisia kentällä, sitä nopeampaa luodit kulkevat. Mielenkiintoista.
Aloittelija

User avatar
valscion
Moderator
Moderator
Posts: 1587
Joined: Thu Dec 06, 2007 8:46 pm
Location: Espoo
Contact:

Re: Loputtomat viholliset, yksilöinti ja MAVit

Post by valscion » Fri Sep 09, 2011 1:43 pm

Cebez wrote:EDIT: Näyttäisi siltä, että mitä enemmän vihollisia kentällä, sitä nopeampaa luodit kulkevat. Mielenkiintoista.
Tuo taitaa johtua siitä, että sinulla on sisäkkäisessä silmukassa vihollisten ja ammusten päivitys. Ammusten liikuttaminen täytyy suorittaa vihollisten päivittämisen silmukan ulkopuolella, ettei vihollisten määrä vaikuttaisi ammusten nopeuteen.

Koodiesimerkki:

Code: Select all

// EI NÄIN:

For iVihu.VIHUT = Each VIHUT
    // Vihollisten päivittelyä tässä...
    // -----

    For iAmmus.AMMUKSET = Each AMMUKSET
        MoveObject iAmmus\obj, 2
    Next iAmmus
Next iVihu


// VAAN NÄIN:
For iVihu.VIHUT = Each VIHUT
    // Vihollisten päivittelyä tässä...
    // -----
Next iVihu

For iAmmus.AMMUKSET = Each AMMUKSET
    // Ammusten siirto, For...Each VIHUT silmukan ulkopuolella
    MoveObject iAmmus\obj, 2
Next iAmmus 
cbEnchanted, uudelleenkirjoitettu runtime. Uusin versio: 0.4.1 — Nyt myös sorsat GitHubissa!
NetMatch - se kunnon nettimättö-deathmatch! Avoimella lähdekoodilla varustettu
vesalaakso.com

User avatar
Cebez
Newcomer
Posts: 3
Joined: Thu Sep 08, 2011 8:24 pm

Re: Loputtomat viholliset, yksilöinti ja MAVit

Post by Cebez » Fri Sep 09, 2011 3:33 pm

Aivan, kiitos VesQ. Eipäs tullutkaan ajateltua, että tuli laitettua tuohon silmukkaan se MoveObject.
Noniin, nyt sitä saakin taas nauttia jonkin aikaa melkeinpä virheettömästä koodista, jospa alkaisin
viimeinkin työstämään sitä törmäyksentunnistusta ja muita ominaisuuksia.

Pistänpä tähän vielä lopullisen ratkaisun tuosta CheckBullets-aliohjelmasta, jos se jotakuta
sattuu kiinnostamaan:

Code: Select all

CheckBullets:
    For luoti.LUODIT = Each LUODIT
        MoveObject luoti\obj, gPower
    Next luoti
    For vihu.VIHUT = Each VIHUT
        tuhoaVihu = 0
        For luoti.LUODIT = Each LUODIT
            If ObjectsOverlap(vihu\obj, luoti\obj) Then
                tuhoaVihu = 1
                DeleteObject luoti\obj
                Delete luoti
            ElseIf GetMap(2, ObjectX(luoti\obj), ObjectY(luoti\obj)) Then
                DeleteObject luoti\obj
                Delete luoti
            EndIf
        Next luoti
        If tuhoaVihu = 1 Then
            DeleteObject vihu\obj
            Delete vihu
        EndIf
    Next vihu
Return
Kiitokset vielä lopuksi kaikille auttajille, neuvonne ovat todellisesti valaisseet minua.
Aloittelija

User avatar
JATothrim
Tech Developer
Tech Developer
Posts: 606
Joined: Tue Aug 28, 2007 6:46 pm
Location: Kuopio

Re: Loputtomat viholliset, yksilöinti ja MAVit (ratkaistu)

Post by JATothrim » Sun Sep 11, 2011 6:35 pm

Yllä oleva tapa on varsin raskas (mutta helppo) menetelmä käsitellä törmäykset kokoelmien kesken. Kompleksisuus on luokkaa O(N^2). Ezbe:n type-tutoriaalissa pohjustetaan kehittyneempää tapaa selata törmäykset läpi: linkki

Vieläkin nopeampi tapa on oikeastaan hyljätä tuo vihujen selaus sisäkkäisessä looppissa kokonaan. Kyllä, tämä on mahdollista, mutta paljon haastavampaa. Kun luoti-instanssi tehdään, se linkitetään "ObjectInteger obj, ConvertToInteger(luoti_instanssi)":lla suoraan objektiin. Tämän linkityksen avulla "ConvertToType(ObjectInteger(GetCollision(obj, i)))" palauttaa sen tyyppi-instanssin, johon objekti törmäsi - vältymme kokoelmien selaamiselta jossa objekti mahdollisesti oli. Pitää olla kuitenkin tarkkana sen kanssa mitä GetCollision() on palauttamassa: Onko objektilla ylipäätään edes kokoelmaa, eli se on esim. kartta tai jokin muu objekti. Ja jos on kokoelma, niin mistä kokoelmasta? (Väärään kokoelmaan muuntaminen kaataa ohjelman)

Parasta tässä menetelmässä on se, että yhden kokoelman jokainen tyyppi-instanssi voidaan käsitellä kokonaan kahdessa loopissa. Ei yhtään enempää, eikä vähempää. Ensimmäinen silmukka päivittää instansseja ja tarkistaa törmäykset ja jälkimmäinen looppi tuottaa vasteen mahdolliselle törmäykselle (esim. räjäyttää ohjuksen ja poistaa padin pysyvästi). Instanssien ja objektien poisto on turvallisempaa: vihu objektilla tarkistetaan, että törmääkö se johonkin objektiin. Selvitetään objekti johon törmättiin (luoti), ja jos mahdollista tästä edelleen sen instanssi kokoelmassa. Merkataan instanssi tuhotavaksi asettamalla siitä jokin flagi päälle esim: "ibullet\destroy = true". Luoti ja vihu instanssi poistetaan sitä myöhemmin käsittelevässä loopissa, tällöin voidaan lisäksi triggeröidä mm. efektejä tuhoutuvalle objektille. Tämän menetelmä on kompleksisuudessaan linearinen O(N), mikä on valtava parannus sisäkkäisiin silmukoihin!

Hmm.. taisin asiasta innostua niin, että teempä cb-->f8->18 tutoriaalista toisen version.. :P Se ei ole koskaan selittänyt miten kahden kokoelman tapauksessa kannataa toimia. :|
-On selkeästi impulsiivinen koodaaja joka...
ohjelmoi C++:lla rekursiivisesti instantioidun templaten, jonka jokainen instantiaatio instantioi sekundäärisen singleton-template-luokan, jonka jokainen instanssi käynistää säikeen tulostakseen 'jea'.

Post Reply