Как сделать так, чтобы хорошие парни атаковали только плохих парней и наоборот?

11

В моей игре много разных хороших парней и много разных плохих парней. Все они будут обстреливать друг друга снарядами, но я не хочу, чтобы какой-либо случайный побочный ущерб был нанесен для любого выравнивания. Поэтому плохие парни не должны быть в состоянии ударить / повредить других плохих парней, а хорошие парни не должны быть в состоянии ударить / повредить других хороших парней.

Я думаю о том, как решить эту проблему, сделав так, чтобы Unitэкземпляр (это javascript, кстати) обладал alignmentсвойством, которое может быть как goodили bad. И я только позволю столкновению произойти, если

class Attack

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

Это псевдокод, конечно.

Но я задаю этот вопрос, потому что у меня есть ощущение, что может быть гораздо более элегантный способ создать это, кроме добавления еще одного свойства в мой Unitкласс.

Даниэль Каплан
источник
5
Фильтрация является типичным подходом здесь. По сути, это то, что вы описали. Там также слои. Два слоя, плохой слой и хороший слой. Снаряды плохих парней попадают в хороший слой и наоборот.
MichaelHouse
@ Byte56 Можете ли вы уточнить эту концепцию «слоя»? Или хотя бы ссылку на что-то об этом? Я никогда не слышал об этом раньше.
Даниэль Каплан
По сути, это разные "миры". Все объекты в слое взаимодействуют друг с другом, но не взаимодействуют ни с каким другим слоем. Это можно сделать с помощью тегов (например, фильтрация) или с помощью совершенно разных наборов данных для каждого слоя.
MichaelHouse
3
Одним словом, это группировка. Сгруппируйте хорошие пули и проверяйте только столкновения с плохими парнями. У Flixel есть такая концепция.
ashes999
3
Один nitpicky дизайн Примечания: вы хотите «дружественную огнь» выстрелы ударить , но не делать никаких повреждений, или вы хотите, чтобы полностью игнорировать союзник, возможно , проходя через них , чтобы ударить враг вместо этого?
Стивен Стадницкий,

Ответы:

6

Фильтрация столкновений

Более надежная ситуация, которая масштабируется на многие уровни, - это использование фильтрации, которая отличается от группировки.

Это работает лучше всего, давая каждому объекту 2 битовые маски .

Category
Mask

И только вызовите столкновение, если ниже верно.

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

Проще всего по умолчанию установить маску на 0xFFFF, что приведет к ее столкновению со всем. И по умолчанию Категория для 0x0001. объекты сталкиваются с категориями в маске других, будет ли столкновение.

Еще один способ думать об этом - каждый объект имеет тип и список всех типов, с которыми он может столкнуться. Только когда два объекта сталкиваются с типами друг друга, происходит столкновение. Вы могли бы иметь такое же поведение, имея список перечислений вместо маски, но маска на порядок быстрее.

Сценарий, который вы описываете

Мне нравится использовать перечисления в этой ситуации.

Так сказать, у нас есть.

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

Пуля, застреленная хорошим парнем

 Category = Bullet
 Mask = BadGuy | GlassWall

Хорошие ребята

 Category = GoodGuy
 Mask = All

Плохие парни

 Category = BadGuy
 Mask = All

Это приводит к тому, что пуля, выпущенная хорошим парнем, попадает в другого хорошего парня.

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

Но это ударит плохих парней.

(All & BadGuy) != 0 && <- Passes
(BadGuy & (BadGuy | GlassWall)) != 0; <-- Passes
ClassicThunder
источник
Не могли бы вы объяснить это концептуально вместо того, чтобы объяснять это на низком уровне детализации битовой арифметики?
Даниэль Каплан
@tieTYT обязательно проверь еще раз через 5 минут
ClassicThunder
2

У меня была такая же проблема в моем текущем проекте (на Java). После пары попыток это решается путем создания четырех списков. Это решение создано на Java и для 2D-игр, но также должно работать аналогичным образом на 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
       {...}
}

псевдокод

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

псевдокод, то же самое для класса Bullets

Возможно, это не лучшее или самое быстрое решение, но оно поможет вам в данный момент. Мне жаль, что я не могу дать вам решение в JavaScript, но я надеюсь, что смогу помочь вам

Кстати, мой английский не самый лучший, но я надеюсь, что вы могли бы следовать моим объяснениям

Jonniy
источник