Jak sprawić, by ataki dobrych facetów trafiały tylko złych facetów i odwrotnie?

11

Moja gra ma wiele różnych rodzajów dobrych facetów i wiele różnych rodzajów złych facetów. Wszystkie będą strzelały do ​​siebie, ale nie chcę, aby przypadkowe obrażenia wystąpiły w obu liniach. Więc źli nie powinni być w stanie trafić / zranić innych złych, a dobrzy nie powinni być w stanie trafić / zranić innych dobrych.

Sposób, w jaki myślę o rozwiązaniu jest to przez co czyni go tak, że Unitinstancja (to jest javascript, btw), posiada alignmentwłaściwości, które mogą być goodalbo bad. I pozwolę na kolizję tylko wtedy, gdy

class Attack

    boolean didAttackCollideWithTarget(target)
        return attack.source.alignment != target.alignment and collisionDetected(attack.source, target)

Oczywiście jest to pseudo-kod.

Ale zadaję to pytanie, ponieważ mam wrażenie, że może istnieć o wiele bardziej elegancki sposób zaprojektowania tego, oprócz dodania jeszcze jednej właściwości do mojej Unitklasy.

Daniel Kaplan
źródło
5
Filtrowanie jest tutaj typowym podejściem. Zasadniczo tak właśnie opisałeś. Są też warstwy. Dwie warstwy, zła warstwa i dobra warstwa. Pociski złego faceta są wystrzeliwane w dobrą warstwę i odwrotnie.
MichaelHouse
@ Byte56 Czy możesz rozwinąć tę koncepcję „warstwy”? A przynajmniej link do czegoś na ten temat? Nigdy wcześniej o tym nie słyszałem.
Daniel Kaplan
Zasadniczo są to różne „światy”. Wszystkie obiekty w warstwie oddziałują na siebie, ale nie oddziałują na żadną inną warstwę. Można to zrobić za pomocą znaczników (takich jak filtrowanie) lub całkowicie różnych zestawów danych dla każdej warstwy.
MichaelHouse
3
Jednym słowem jest to grupowanie. Grupuj dobre pociski i sprawdzaj tylko kolizję ze złymi ludźmi. Flixel ma taką koncepcję.
ashes999
3
Jedna drobiazgowa uwaga dotycząca projektu: czy chcesz, aby strzały z przyjacielskim ogniem trafiały, ale nie zadawały obrażeń, czy też chcesz, aby całkowicie ignorowały sojuszników, prawdopodobnie przechodząc przez nie, by uderzyć wrogów?
Steven Stadnicki

Odpowiedzi:

6

Filtrowanie kolizji

Bardziej niezawodną sytuacją, która można skalować na wiele warstw, jest użycie filtrowania, co nie jest tym samym, co grupowanie.

Działa to najlepiej, dając każdemu obiektowi 2 maski bitowe .

Category
Mask

I wywołać kolizję tylko wtedy, gdy poniższe warunki są prawdziwe.

(filterA.maskBits & filterB.categoryBits) != 0 &&
(filterA.categoryBits & filterB.maskBits) != 0;

Najłatwiej jest ustawić domyślną maskę na 0xFFFF, co powoduje kolizję ze wszystkim. Domyślną kategorią jest 0x0001. obiekty zderzą się z kategoriami w masce pozostałych, czy nastąpi kolizja.

Innym sposobem, aby o tym myśleć, jest to, że każdy obiekt ma typ i listę wszystkich typów, z którymi może się kolidować. Tylko wtedy, gdy dwa obiekty zderzają się ze sobą, występuje kolizja. Możesz mieć takie samo zachowanie, mając listę wyliczeń zamiast maski, ale maskę o rząd wielkości szybciej.

Scenariusz, który opisujesz

W tej sytuacji lubię wykorzystywać wyliczenia.

Powiedzmy, że mamy.

enum Categories {
    GoodGuy =           0x0001,
    BadGuy =            0x0002,
    Bullet =            0x0004,
    GlassWall =         0x0008,
    Lazer =             0x0010,
    All =               0xFFFF
};

Kula zastrzelona przez dobrego faceta

 Category = Bullet
 Mask = BadGuy | GlassWall

Dobrzy ludzie

 Category = GoodGuy
 Mask = All

Źli chłopcy

 Category = BadGuy
 Mask = All

Co powoduje, że poniżej, gdy Kula trafiona przez dobrego faceta trafi innego dobrego faceta.

(All & GoodGuy) != 0 && <-- Passes
(GoodGuy & (BadGuy | GlassWall)) != 0; <-- This would fail

Ale trafi w złych facetów.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
ClassicThunder
źródło
Czy mógłbyś wyjaśnić to koncepcyjnie, zamiast wyjaśniać to na niskim poziomie szczegółów arytmetyki bitów?
Daniel Kaplan
@tieTYT na pewno sprawdź ponownie za 5 minut
ClassicThunder
2

Miałem ten sam problem w moim bieżącym projekcie (w Javie). Po kilku próbach rozwiązuje się go, tworząc cztery listy. To rozwiązanie jest tworzone w Javie i dla gry 2D, ale powinno również działać w podobny sposób w JavaScript

public static main (String [] args)
{
    private List<Bullets> bullets_GoodGuys = new LinkedList <Bullet>(); //List of all bullets fired by good guys
    private List<Bullets> bullets_BadGuys  = new LinkedList <Bullet>(); //List of all bullets fired by bad guys
    private List<Guys> goodGuys  = new LinkedList <Guys>(); //List of all good guys
    private List<Guys> badGuys  = new LinkedList <Guys>();  //List of all good guys

    init();
    ...
    while(game_is_running)
    {
        ... 
        for(int i=0;i>=goodGuys.length;i++)
        {
            for(int j=0;j>=bullets_BadGuys.length;i++)
            {
                if(goodGuys.get(i).getBounding().interacts(bullets_BadGuys.get(i).getBounding()))
                {// If a good guy was hit by a bullet from a bad guy
                    goodGuys.get(i).getDamage();
                    bullets_BadGuys.remove((bullets_BadGuys.get(i));
         }   }   }
       for(...) //same for the bad guys
       {...}
}

pseudo kod

class Guys
{
   private float xkoordinate;
   private float ykoordinate;
   private BufferedImage look;
   private Rectangle bounding = new Rectangle(xkoordinate,ykoordinate,look.getWith(),look.getHight())
   ...
}

pseudo-kod, taki sam dla klas Bullets

To może nie być najlepsze lub najszybsze rozwiązanie, ale pomoże ci w tej chwili. Przykro mi, że nie mogę dać ci rozwiązania w JavaScript, ale mam nadzieję, że mógłbym ci pomóc

Nawiasem mówiąc, mój angielski nie jest najlepszy, ale mam nadzieję, że posłuchasz mojego wyjaśnienia

Jonniy
źródło