Biały, konserwatywny losowy spacer

13

Mam duszka, który ma Velocityi Position, albo przechowywane jako Vector2. W każdym Updatecyklu prędkość jest dodawana do pozycji.

Chciałbym dać ikonki trzeci wektor, Target. Nowe cele mogą być podane w dowolnej iteracji. Chciałbym, aby duszek zasadniczo poruszał się w sposób losowy, jednak należy ujawnić dwa parametry:

  1. Typowy chód losowy może równie dobrze zwiększyć lub zmniejszyć odległość do dowolnej Target(plus niewielka szansa na ruch styczny). Muszę być w stanie przesunąć mój losowy spacer tak, aby, choć wciąż losowy, kierunek, w którym „duszek” decyduje, był bardziej prawdopodobne, aby zbliżyć go Target.
  2. Losowy spacer powinien być „gładki” - duszek nie powinien szybko zmieniać kierunku, ponieważ będzie to wyglądało, jakby „migotało” lub „drżało” dla gracza. Powinien stopniowo skręcać w tę lub inną stronę, poruszając się losowo, powoli zbliżając się po uśrednieniu.

Jaki jest dobry, prosty sposób to zrobić? Jeśli to możliwe, podaj odpowiedź jako Vector2 RandomWalk(Vector2 target)metodę.

Mam już NextGaussian(mean, stdev)dostępną metodę, jeśli jest to pomocne.

Superbest
źródło
Czy dajesz bardzo małą szansę zmiany kierunku każdej klatki? I czy ta szansa jest znacznie większa, jeśli nie idzie w kierunku, w którym chcesz?
BlueRaja - Danny Pflughoeft,
To miłe rozwiązanie. Wolałbym jednak unikać nagłej, gwałtownej zmiany kierunku, jeśli to możliwe.
Superbest
1
Po prostu dodaj współczynnik przyspieszenia, więc zamiast zmieniać prędkości, zmieniasz przyspieszenie, które z kolei zmienia prędkość. Powinno to usunąć jitter z ruchu i możesz po prostu dostosować przyspieszenie, aż uzyskasz gładki spacer
skeletalmonkey

Odpowiedzi:

4

Chciałbym wziąć „wędrowanie” zachowanie kierownicy (kod źródłowy można znaleźć tutaj ) i dostosować go w taki sposób, że liczby losowe są odchylane w kierunku swojego celu.

grzmot
źródło
Tak, myślę, że należy kierować się zachowaniami kierowniczymi. Po prostu wykonaj Wędrówkę + Poszukiwanie i dodaj małą wagę do zachowania poszukiwania.
krolth
6

Aby uzyskać płynny losowy spacer, możesz użyć splajnów Catmull-Rom . Ten rodzaj splajnu przyjmuje sekwencję punktów i generuje gładkie krzywe przechodzące przez każdy punkt. Możesz więc wygenerować losowe punkty, do których duszek może się poruszać, i animować je wzdłuż splajnu Catmull-Rom przez punkty. Aby splajn działał, potrzebujesz w sumie czterech punktów pośrednich: dwóch poprzednich i dwóch następnych. Kiedy duszek osiągnie punkt orientacyjny, wyrzuć najstarszy z czterech zestawów i wygeneruj nowy, a następnie kontynuuj animację wzdłuż splajnu.

Co do ewentualnego zbliżania się do celu, jednym z pomysłów byłoby zrównoważyć rozkład losowego spaceru w kierunku celu. Na przykład, jeśli zwykle wybierasz losowy punkt trasy za pomocą rozkładu Gaussa wyśrodkowanego na bieżącej pozycji twojego duszka, możesz zamiast tego przesunąć środek Gaussa o pewną zadaną odległość w kierunku celu. Względne rozmiary odsunięcia i standardowe odchylenie Gaussa określają, jak bardzo tendencyjny jest ruch.

Nathan Reed
źródło
Zastanawiałem się nad tym i chociaż zalecenie jest dobre, chciałbym, aby nastawienie było skierowane w stronę lokalizacji gracza. Ponieważ metoda splajnu wymaga ode mnie wcześniejszego wygenerowania ścieżki, opóźnienie w podążaniu za graczem będzie opóźnione.
Superbest
@Najlepszy, jeśli użyjesz krzywej Beziera, musisz wygenerować tylko dwa kolejne punkty - i możesz wykonać drugi punkt w przyszłości w kierunku gracza, który będzie się poruszał.
Jonathan Dickinson
2

Oto coś, co wymyśliłem w około 20 minut. Kierujemy się od chodzika do celu, wybieramy kierunek w określonej ilości stopni tego kierunku (ilość, która maleje, gdy piechur zbliża się do celu). Ten algorytm uwzględnia również odległość do celu, aby nie przekroczył celu. Krótko mówiąc, w zasadzie kołysze się w lewo i w prawo niewielką losową liczbę i trafia w cel, gdy się zbliża.

Aby przetestować ten algorytm, ustawiłem walker na (10, 0, 10), a cel na (0, 0, 0). Przy pierwszym uruchomieniu algorytmu losowo wybrał pozycję, do której walker ma przejść (3.73f, 0, 6.71f). Po tym, jak piechur osiągnął tę pozycję, wybrał (2.11f, 0, 3.23), następnie (0.96f, 0, 1.68f), a następnie (0.50f, 0, 0.79f), a następnie podszedł prosto do celu, ponieważ był w zasięgu minimalna odległość tolerancji.

Na wykresie z lotu ptaka ścieżka wygląda jak punkty na obrazku poniżej, zaczynając od „W” (piechur) i kończąc na „T” (cel). Jeśli chcesz bardziej naturalnego ruchu, musisz wcześniej obliczyć kilka punktów wcześniej i utworzyć splajn, dając ci o wiele więcej punktów, za którymi piechur może podążać. Oszacowałem, jak ta ścieżka wyglądałaby po przekształceniu w splajn i jest reprezentowana przez linię na obrazie.

wprowadź opis zdjęcia tutaj

A oto przykładowy kod:

Vector3 WalkerPosition = new Vector3(10, 0, 10);
Vector3 TargetPosition = Vector3.Zero;

public Game1()
{
    // Each time you reach the next walk-to position, call this again.
    // Eventually you'll reach your target, assuming the target isn't moving away
    // from the walker faster than the walker can reach them.
    Vector3 NextWalkToPosition = PickRandomTarget();
}

public Vector3 PickRandomTarget()
{
    // For this code sample we'll assume that our two targets are on
    // the same horizontal plane, for simplicity.

    Vector3 directionToTarget = ( TargetPosition - WalkerPosition );
    float distance = directionToTarget.Length();
    directionToTarget.Normalize();

    float distanceThisIteration = distance * 0.5f;

    // We should never walk too little or too far, to make this more realistic
    // you could randomize the walking distance each iteration a bit.
    distanceThisIteration = MathHelper.Clamp(distanceThisIteration, 1.0f, 10.0f);

    // We're within minimum distance to the target, so just go straight to them
    if (distanceThisIteration > distance)
    {
        return TargetPosition;
    }

    directionToTarget *= distanceThisIteration; // Walk roughly halfway to the target            

    // Now we pick a new walking direction within an FOV that gets smaller as
    // we get closer to the target. We clamp the FOV between 0 and 90 degrees (45 degrees in either direction).
    const float walkerAggroRadius = 30.0f; // Walker aggros when within 30 units of target

    // Any distance outside of 30 we'll just treat as 30.
    float distanceMod = MathHelper.Clamp(distance, 0.0f, walkerAggroRadius);

    // We need a percentage value representing the current distance between the min 0, and max, 30
    float percentageAlongDistance = distanceMod / walkerAggroRadius;

    // We want FOV from center, so we cut the final FOV result in half
    float maxFOVAtThisDistance = MathHelper.Lerp(0.0f, MathHelper.PiOver2, percentageAlongDistance) * 0.5f;

    // Now we pick a random FOV from center within our maxFOV based on how far we are
    // from the target
    Random rand = new Random(System.DateTime.Now.Second);
    float randFOV = (float)(rand.NextDouble() * maxFOVAtThisDistance);

    // Right now our FOV value is an FOV from a vector pointing directly at our target, we now
    // need to randomly choose if we're going to aim to the left or right of the target. We'll
    // treat a result of 0 as left, and 1 as right
    int randDirection = rand.Next(2);
    if (randDirection == 0) // Left
    {
        // Rotate our direction vector left by randFOV radians
        return WalkerPosition + RotateAroundPoint(directionToTarget, Vector3.Zero, Vector3.UnitY, -randFOV);
    }
    else // Right
    {
        return WalkerPosition + RotateAroundPoint(directionToTarget, Vector3.Zero, Vector3.UnitY, randFOV);
    }
}

// Generic helper function to rotate a vector by a specific amount of degrees
public Vector3 RotateAroundPoint( Vector3 point, Vector3 originPoint, Vector3 rotationAxis, float radiansToRotate )
{
    Vector3 diffVect = point - originPoint;

    Vector3 rotatedVect = Vector3.Transform(diffVect, Matrix.CreateFromAxisAngle(rotationAxis, radiansToRotate));

    rotatedVect += originPoint;

    return rotatedVect;
}

W zależności od konkretnej gry możesz modyfikować odległości, pole widzenia, losowość i częstotliwość uruchamiania, tak aby odpowiadały Twoim potrzebom. Jestem pewien, że algorytm można trochę wyczyścić i zoptymalizować, nie spędziłem na tym dużo czasu, chciałem tylko, aby był łatwy do odczytania.

Nic Foster
źródło