Önyargılı, muhafazakar rastgele yürüyüş


13

Ben Velocityve Positionsaklanan bir sprite var Vector2. Her Updatedöngüde hız konuma eklenir.

Sprite'a üçüncü bir vektör vermek istiyorum Target. Herhangi bir yinelemede yeni hedefler verilebilir. Sprite esasen rastgele bir yürüyüş deseninde hareket etmesini istiyorum, ancak iki parametrenin maruz kalması gerekiyor:

  1. Tipik rastgele bir yürüyüşün, verilen herhangi bir mesafeyi Target(artı küçük teğetsel hareket şansını) arttırması veya azaltması da eşit derecede olasıdır . Rastgele yürüyüşümü önyargılı tutabilmeliyim ki, hala rastgele olsa da, hareketli grafiğin "karar verdiği" yön, onu daha yakın hale getirme olasılığı daha yüksek olmalıdır Target.
  2. Rastgele yürüyüş "pürüzsüz" olmalıdır - sprite hızlı bir şekilde yön değiştirmemelidir, çünkü bu oyuncuya "titriyor" veya "titriyor" gibi görünecektir. Ortalama olarak yavaş yavaş yaklaşırken, bu şekilde veya rastgele hareket ederek kademeli olarak sapmalıdır.

Bunu yapmanın iyi ve basit bir yolu nedir? Mümkünse, cevabı bir Vector2 RandomWalk(Vector2 target)yöntem olarak verin .

Zaten NextGaussian(mean, stdev)yararlı bir yöntem zaten var .


Her karenin yönünü değiştirme şansı çok mu düşük? Ve eğer istediğiniz yönde hareket etmiyorsa bu şansı önemli ölçüde arttırır mı?
BlueRaja - Danny Pflughoeft

Güzel bir çözüm. Ancak mümkünse ani, sarsıntılı yön değişikliğinden kaçınmayı tercih ederim.
Superbest

1
Sadece bir ivme faktörü ekleyin, böylece hızları değiştirmek yerine, hızı değiştirirsiniz, bu da hızı değiştirir. Bu, hareketten titremeyi kaldırmalıdır ve pürüzsüz bir yürüyüş elde edene kadar hızlanma uygulamasını düzenleyebilirsiniz
skeletalmonkey

Yanıtlar:


4

Ben alacaktı "gezme" direksiyon-davranışı (kaynak kodu bulunabilir burada ) ve rasgele numaralar hedefe doğru yönlendirilmiş bulunmaktadır böylece bir bakıma değiştiririz.


Evet, bence yönlendirme davranışları bir yol. Sadece Wander + Seek yapın ve arama davranışına düşük bir ağırlık ekleyin.
krolth

6

Yumuşak bir yürüyüş için Catmull-Rom kamalarını kullanabilirsiniz . Bu tür spline bir dizi nokta alır ve her noktadan geçen yumuşak eğriler üretir. Böylece, hareketli grafiğin geçiş noktaları boyunca bir Catmull-Rom eğri boyunca hareket etmesi ve hareketlendirilmesi için rastgele ara noktalar oluşturabilirsiniz. Spline'ın çalışması için toplam dört yol noktasına ihtiyacınız olacak: önceki iki ve sonraki iki. Hareketli grafik bir ara noktaya ulaştığında, dörtlü setinizin en eskisini atın ve yeni bir tane oluşturun, ardından hareketli çizgi boyunca animasyon yapmaya devam edin.

Sonunda hedefe doğru ilerlerken, fikirlerden biri rastgele yürüyüşün hedefe doğru dağılımını dengelemek olacaktır. Örneğin, hareketli grafiğinizin geçerli konumuna odaklanmış bir Gauss dağıtımı kullanarak genellikle rastgele bir yol noktası seçerseniz, bunun yerine Gauss'un merkezini hedefe doğru önceden belirlenmiş bir mesafeyle dengeleyebilirsiniz. Ofsetin göreceli boyutları ve Gauss'un standart sapması, hareketin ne kadar önyargılı olduğunu belirleyecektir.


Bunu düşündüm ve tavsiye güzel olsa da, önyargıların oyuncunun bulunduğu yere doğru olmasını istiyorum. Spline yöntemi, yolun bazılarını önceden oluşturmamı gerektirdiğinden, oynatıcıyı takip etme yeteneğinde gecikme olacaktır.
Superbest

@Superbest bir Bezier eğrisi kullanırsanız, yalnızca sonraki iki noktayı oluşturmanız gerekir - ve ileride ikinci noktayı oyuncuya doğru hareket ederken doğru hareket ettirebilirsiniz.
Jonathan Dickinson

2

İşte 20 dakika içinde çırptığım bir şey. Yönü yürüteçten hedefe götürüyoruz, o yönün belirli bir derecesinde bir yön seçiyoruz (yürüteç hedefine yaklaştıkça azalan bir miktar). Bu algoritma ayrıca hedefe olan mesafeyi de hesaba katar, böylece hedefin ötesine geçmez. Uzun lafın kısası, temelde sola ve sağa küçük rastgele bir miktar sallıyor ve yaklaştıkça hedefe ev sahipliği yapıyor.

Bu algoritmayı test etmek için yürüteç (10, 0, 10) ve hedefi (0, 0, 0) olarak yerleştirdim. Algoritma ilk kez çalıştırıldığında, walker'ın yürümesi için bir pozisyon seçti (3.73f, 0, 6.71f). Yürüteç bu konuma ulaştıktan sonra (2.11f, 0, 3.23), sonra (0.96f, 0, 1.68f), sonra (0.50f, 0, 0.79f) seçti, çünkü içeride olduğu için doğrudan hedefe yürüdü minimum tolerans mesafesi.

Bir kuşbakışı görünümünden grafik çizilen yol, 'W' (yürüteç) ile başlayan ve 'T' (hedef) ile biten aşağıdaki görüntüdeki noktalara benzeyecektir. Daha doğal bir hareket istiyorsanız, birkaç noktayı önceden hesaplar ve bir spline yaratırsınız, size daha fazla puan vererek yürüteçten takip edebilirsiniz. Bir spline haline getirildikten sonra bu yolun nasıl görüneceğini tahmin ettim ve bu görüntüdeki çizgi ile temsil ediliyor.

resim açıklamasını buraya girin

İşte örnek 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;
}

Özel oyununuza dayanarak, ihtiyaçlarınıza uygun olan mesafeleri, FOV, rastgelelik ve frekansı değiştirebilirsiniz. Eminim algoritma biraz temizlenebilir ve optimize edilebilir, bunun için fazla zaman harcamadım, sadece okunması kolay olmasını istedim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.