Упереджена, консервативна випадкова прогулянка


13

У мене спрайт, який має Velocityі Positionзберігається як Vector2. На кожному Updateциклі швидкість додається до положення.

Я хотів би дати спрайт третій вектор, Target. Нові цілі можуть бути задані на будь-якій ітерації. Я хотів би, щоб спрайт по суті рухався за випадковою схемою прогулянки, однак два параметри повинні бути відкриті:

  1. Типова випадкова хода однаковою мірою може збільшити або зменшити відстань до будь-якого даного Target(плюс малий шанс дотичного руху). Я повинен бути здатний упереджувати свою випадкову ходьбу таким чином, щоб, хоч і досі залишався випадковим, напрямок, за яким спрайт "вирішує", має більше шансів наблизити його Target.
  2. Випадкова хода повинна бути «плавною» - спрайт не повинен швидко змінювати напрямок, оскільки це виглядатиме так, що це «мерехтіння» або «тремтіння» гравця. Він повинен поступово переходити так чи інакше, рухаючись випадковим чином, при цьому повільно наближаючись при усередненні.

Який хороший, простий спосіб це зробити? Якщо можливо, дайте відповідь як Vector2 RandomWalk(Vector2 target)метод.

У мене вже є NextGaussian(mean, stdev)метод, якщо це корисно.


Дайте йому дуже маленький шанс змінити напрямок кожного кадру? І зробити цей шанс значно більшим, якщо він не рухається в тому напрямку, в якому ви хочете?
BlueRaja - Danny Pflughoeft

Це приємне рішення. Однак я вважаю за краще уникати різкої, ривкової зміни напрямку, якщо це можливо.
Супербест

1
Просто додайте коефіцієнт прискорення, тому замість швидкостей ви змінюєте прискорення, що в свою чергу змінює швидкість. Це повинно зняти тремтіння від руху, і ви можете просто налаштувати додаток прискорення, поки ви не отримаєте плавну ходьбу
скелетна

Відповіді:


4

Я б прийняв "блукаюче" поводження (вихідний код можна знайти тут ) і налаштувати його таким чином, щоб випадкові числа були упередженими до вашої цілі.


Так, я думаю, що рульова поведінка - це шлях. Просто зробіть Wander + Seek та додайте низьку вагу поведінці пошуку.
krolth

6

Для отримання плавної випадкової прогулянки ви можете використовувати сплайни Catmull-Rom . Цей вид сплайну займає послідовність точок і генерує плавні криві, які проходять через кожну точку. Таким чином, ви можете генерувати випадкові точкові точки для спрайту, щоб переміщатись та анімувати його вздовж сплайну Catmull-Rom через шляхові точки. Для того, щоб сплайн працював, вам знадобиться всього чотири точки: попередні дві та наступні дві. Коли спрайт досягне точкової точки, викиньте найстаріший із чотирьох наборів та генеруйте новий, а потім продовжуйте анімацію по сплайну.

Що стосується врешті-решт спрямування до цілі, однією ідеєю було б компенсувати розподіл випадкових кроків до цілі. Наприклад, якщо ви зазвичай обираєте випадкову точку маршруту, використовуючи розподіл Гаусса, орієнтований на поточне положення вашого спрайту, ви можете замість цього змістити центр Гаусса на деяку задану відстань до цілі. Відносні розміри зміщення та стандартне відхилення Гаусса визначали б наскільки упереджений рух.


Я думав про це, і хоча рекомендація є приємною, я хотів би, щоб упередження було спрямоване на розташування гравця. Оскільки метод сплайну вимагає від мене генерувати деяку частину шляху заздалегідь, у можливості відстежувати гравця буде відставати.
Супербест

@Superbest, якщо ви використовуєте криву Безьє, вам потрібно створити лише дві наступні точки - і ви зможете зробити другий пункт у майбутньому в напрямку гравця, коли він рухається.
Джонатан Дікінсон

2

Ось щось я збила приблизно за 20 хвилин. Ми беремо напрямок від пішохода до цілі, вибираємо напрямок в межах певної кількості градусів цього напрямку (сума, яка зменшується, коли ходок наближається до своєї мети). Цей алгоритм також враховує відстань до цілі, щоб він не проходив повз ціль. Якщо коротко розповісти, він, в основному, коливається ліворуч і праворуч на невелику випадкову кількість і входить у ціль, коли вона наближається.

Для перевірки цього алгоритму я розмістив ходок у (10, 0, 10), а ціль у (0, 0, 0). Перший раз, коли алгоритм запускав його випадковим чином, вибирав позицію для прогулянкової ходьби (3.73f, 0, 6.71f). Після того, як ходок досяг цієї позиції, він вибрав (2.11f, 0, 3.23), потім (0.96f, 0, 1.68f), потім (0.50f, 0, 0.79f), а потім пішов прямо до цілі, тому що знаходився в межах мінімальна відстань допуску.

Витягнута з пташиного польоту стежка виглядатиме як точки на зображенні нижче, починаючи з "W" (ходок) і закінчуючи на "T" (ціль). Якщо ви хочете більш природного руху, то слід заздалегідь підрахувати кілька очок перед часом і створити сплайн, даючи вам набагато більше очок, за якими ви можете ходити. Я підрахував, як виглядатиме цей шлях після того, як він перетворився на сплайн, і що зображено лінією на зображенні.

введіть тут опис зображення

І ось приклад коду:

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;
}

Виходячи з вашої конкретної гри, ви можете налаштувати відстань, FOV, випадковість та частоту, яку вона виконує, поки вона не відповідає вашим потребам. Я впевнений, що алгоритм можна було трохи очистити та оптимізувати, я на це не витрачав багато часу, просто хотів, щоб його було легко читати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.