Jakiego rodzaju kierowania lub logiki mogę użyć, aby telefony komórkowe otoczyły kogoś innego?

10

Korzystam ze znajdowania ścieżek w mojej grze, aby poprowadzić tłum do innego gracza (aby go wykonać). Działa to tak, aby przesłonić odtwarzacz, ale chcę, aby zatrzymali się nieco przed miejscem docelowym (więc wybranie przedostatniego węzła działa dobrze).

Jednak gdy wiele mobów ściga telefon komórkowy, czasami „kładą się jeden na drugim”. Jak najlepiej tego uniknąć? Nie chcę traktować mobów jako nieprzezroczystych i zablokowanych (ponieważ nie są, można przez nie przejść), ale chcę, aby moby miały pewne wyczucie struktury.

Przykład:

Wyobraź sobie, że każdy wąż kierował się do mnie i powinien otaczać „Setsunę”. Zwróć uwagę, jak oba węże wybrały mnie? To nie jest ścisły wymóg; nawet niewielkie przesunięcie jest w porządku. Ale powinni „otoczyć” Setsunę.

wprowadź opis zdjęcia tutaj

Vaughan Hilts
źródło
1
Czy układanie w stosy stanowi jedynie problem w miejscu docelowym, czy też podczas transportu? Zgaduję to drugie.
SpartanDonut
To ten ostatni, @SpartanDonut
Vaughan Hilts,
@KromStern Dodałem zdjęcie, mam nadzieję, że to pomoże.
Vaughan Hilts

Odpowiedzi:

15

Daj swoim agentom słaby „ładunek elektrostatyczny”, aby zmusili się do odpychania się nawzajem, zgodnie z prawem Coulomba .

Zakładając dla uproszczenia, że ​​moby powinny odpychać się z równoważną siłą, powinno wystarczyć zastosowanie siły między każdą parą mobów o wielkości some_constant / distance^2, gdzie some_constantjest konfigurowalna siła odpychania i distanceodległość między nimi.

Siły odpychania spadają następnie z kwadratem odległości.

Charakter kodeksu ma wielką Przykład (demo) na żywo tutaj . To wygląda tak:

połączone obserwuj i oddzielne zachowania

Dopasowywanie każdego elementu do siebie to O(n^2)operacja z czasem kwadratowym ( ). Jeśli masz naprawdę dużo agentów, możesz zoptymalizować obliczenia siły za pomocą aproksymacji Barnesa-Huta , która sprowadza się do log-linear ( O(n log n)), ale wymaga kwadratu .

Anko
źródło
Świetny link, Anko. Bardzo mile widziane! Z pewnością będę musiał przeczytać całą tę stronę.
Vaughan Hilts,
Starcraft (przynajmniej 1) robi coś podobnego ze swoimi latającymi jednostkami. Ale dzieje się tak tylko wtedy, gdy przestają się poruszać, tj. Kiedy są w ruchu, klepią się jedna nad drugą (całkowicie ignorują się jako przeszkody), ale kiedy przestają, wszyscy zaczynają się rozchodzić od czegoś, co wygląda jak lokalne centrum jakiegoś regularnego obszaru (prawdopodobnie kwadrat / okrąg), który je obejmuje. Nie wygląda to tak ładnie, jak przykład w odpowiedzi, ale prawdopodobnie zużywa mniej zasobów procesora i prawdopodobnie łatwiej jest też kodować ...
Shivan Dragon,
@ShivanDragon SC2 prezentuje to samo zachowanie, wszyscy zbiegają się do miejsca docelowego w tłumie, a następnie szukają realistycznego i estetycznego wyglądu (aby ich części się nie zacinały).
Kroltan
2
Pewna siła odpychająca może być dobrym pomysłem, ale szczegóły są trudne. Eksperymentowałem z nimi w kosmicznym RTS-ie i nie zalecam zbyt ścisłego podążania za fizyką, a raczej modelowania jej tak, by zachowywała się ładnie. Kilka obserwacji: 1) Ponieważ nie jest to symulacja fizyczna, zastosowałbym siłę tylko na krótkie odległości. 2) Nie może to zapobiec nakładaniu się ciał skończonych 3) Twardy potencjał łatwo powoduje błędy numeryczne, takie jak załamywanie cząstek przy dużych prędkościach. 4) Kiedy masz znaczną liczbę cząstek i ciśnienie w środkowych wzlotach, rzeczy stają się brzydkie.
CodesInChaos
1

Moje podejście jest podobne do @ Anko, ale oparte na pracy Millingtona i Funge z Artificial Intelligence for Games .

Tak wyglądałoby zachowanie separacji, ale należy wziąć pod uwagę, że prędkość ta powinna być obliczona na podstawie prędkości agenta w funkcji aktualizacji.

public Vector3 GetSeparationVel (float threshold, float decayCoefficient)
{
    threshold = threshold * threshold;
    Vector3 separationVelocity = Vector3.Zero;
    for (int i = 0; i < enemies.Length; i++) {
        if (enemies[i] == this) {
            continue;
        }
        Vector3 direction = this.position - enemies[i].position;
        float distance = direction.LengthSquared();
        float strenght = 0.0f;
        if (distance < (threshold)) {
            strenght = Math.Min(decayCoefficient / distance, this.maxAccel);
            direction.Normalize();
            separationVelocity += strenght * direction;
        }
    }
}
reefaktor
źródło