2016-04-30 4 views
-1

Ich habe Spawner für Tiere über das Gelände in meinem Spiel verstreut. Die Idee ist, dass Tiere nur spawnen, wenn ein Spieler in Reichweite des Spawners ist, aber nicht, wenn zu viele Tiere in unmittelbarer Nähe des Spawners sind. Das was ich bisher gemacht habe aber jetzt bin ich ein wenig festgefahren. Könnte mir jemand eine Anleitung zu folgenden Dingen geben:C# Tier Spawner Logik - Beratung erforderlich

  • Werden die Spawn Odds korrekt berechnet? Wird das Setzen von zwei Tieren zum Beispiel mit einer Spawnchance von 10% und 90% tatsächlich dazu führen, dass TierA eine Chance von 10% hat zu spawnen, und animalB eine Chance von 90% haben oder ist meine Mathematik falsch?
  • Sind meine Radiusberechnungen korrekt?
  • Am wichtigsten: Kann ich es verbessern?

Der Code:

[System.Serializable] 
public class SpawnableAnimal 
{ 
public string AnimalName; 
public float spawnWeight; 

public float spawnPercentage; 
} 

public class AnimalSpawner : MonoBehaviour { 

public float maxSpawnRadius = 1000.0f; 
public float noSpawnRadius = 700.0f; 

public GameObject spawnedAnimal; 

public SpawnableAnimal[] spawnableAnimals; 

void Start() { 
    System.Random rand = new System.Random(); 
    int randInt = rand.Next(0, 100); 

    float startTime = randInt/100f; 
    float repeatTime = randInt/100f; 
    InvokeRepeating("ReadyToSpawn", startTime, (60.0f + repeatTime)); 
} 

void ReadyToSpawn() 
{ 
    Debug.Log("Ready to spawn"); 
    bool canSpawn = true; 

    GameObject[] players = GameObject.FindGameObjectsWithTag("Player"); 
    GameObject[] animals = GameObject.FindGameObjectsWithTag("Animal"); 
    for(int i = 0; i < players.Length; i++) 
    { 
     if (Vector3.Distance(this.transform.position, players[i].transform.position) > maxSpawnRadius) 
      canSpawn = false; 

     if (Vector3.Distance(this.transform.position, players[i].transform.position) < noSpawnRadius) 
      canSpawn = false; 
    } 

    if (players.Length < 1) 
     canSpawn = false; 

    if (spawnedAnimal != null) 
     canSpawn = false; 

    if (canSpawn) 
     SpawnAnimal(); 
} 

void SpawnAnimal() 
{ 
    System.Random rand = new System.Random(); 
    double x = rand.NextDouble(); 

    var totalWeight = spawnableAnimals.Select(a => a.spawnWeight).Sum(); 

    for(int i = 0; i < spawnableAnimals.Length; i++) 
    { 
     float spawnPercentage = spawnableAnimals[i].spawnWeight/totalWeight; 

     if(x < spawnPercentage) 
     { 
      InstantiateAnimal(i); 
      return; 
     } 

     x -= spawnPercentage; 
    } 
} 

void InstantiateAnimal(int animalToSpawn) 
{ 
    if (animalToSpawn != -1) 
     spawnedAnimal = GameObject.Find("AnimalManager").GetComponent<AnimalManager>().SpawnAnimal(spawnableAnimals[animalToSpawn].AnimalName, this.transform.position, this.transform.rotation); 
    else Debug.Log("No animal to spawn!"); 
} 

}

+0

sollten Sie dies auf http://codereview.stackexchange.com/, diese Art von Fragen sind Off-Thema hier – Stephen

+0

Vielen Dank! Wusste nicht einmal über codereview.stackexchange.com –

Antwort

1
Vector3.Distance(this.transform.position, players[i].transform.position) 

Sind diese Positionen im selben Raum? Bedeutet Vector3.Distance(x, y)|x - y|? Wenn ja, dann sieht die Berechnung gut für mich aus.

SpawnAnimal scheint ungerade. Ich bin mir nicht sicher, was es macht. Wenn Sie Ihr Denken dahinter erklären können, dann verstehe ich es vielleicht.

Ich würde jedem Tier ein Gewicht zuweisen. Diese Zahl ist beliebig, aber ihre relativen Größen sind wichtig. Wenn Katzen ein Gewicht von 100 haben und Hunde ein Gewicht von 1000 haben, sind Hunde 10-mal häufiger laichen als eine Katze.

Neben: Warum Gewichte und keine Prozentsätze? Wenn Sie festlegen, dass Katzen eine Chance von 10% haben und Hunde eine Chance von 90% haben, und Sie dann Rennmäuse hinzufügen, welchen Prozentsatz müssen Sie dann Rennmäusen zuweisen? Die Prozentsätze müssen zu 1 addiert werden, so dass Sie die Prozentsätze aller anderen Tiere anpassen müssen, um Platz zu schaffen.Wenn wir Gewichte verwenden, bei Katzen mit 100 und Hunden bei 1000, dann können wir Rennmäuse mit einem Gewicht von 500 hinzufügen und wir wissen, dass Rennmäuse 5 Mal mehr als Katzen und halb so oft wie Hunde spawnen - keine Anpassungen erforderlich.

Nehmen wir an, Sie generieren eine Zufallszahl x in [0,1) (dies kann mit NextDouble() getan werden).

Wir wollen jedem Tier ein Intervall in [0,1) zuweisen, das proportional zu ihrem Gewicht ist. Finde zuerst das Gesamtgewicht.

var totalWeight = spawnableAnimals.Select(a => a.Weight).Sum(); 

Daraus können wir einen Prozentsatz für jedes Tier als a.Weight/totalWeight zuweisen. Diese Prozentsätze addieren sich zu 1, so dass Sie diese Prozentsätze über das Intervall [0,1) verteilen können. Pi ist die Wahrscheinlichkeit des Laichens des Tieres Ai aus dem indizierten Satz von Tieren A, wobei 0 <= i < n und n|A| ist (d. H. Die Anzahl der Tiere).

0.0 0.1 0.2 0.3 … 1.0 
[ P1 )[  P2 )[ … Pn) 

Jetzt müssen Sie nur noch die in x liegt bestimmen Intervall und das ist das Tier, um zu laichen. Hier ist ein prozeduraler Algorithmus, um das zu tun.

  1. initialisieren A = the set of animals, i = 0, x = NextDouble(), n = |A|.
  2. Wenn i < n
    • Dann: Wenn x < Pi
      • Dann: halt und laichen Ai. Else
      • :
        1. subtrahieren Pi von x
        2. Zuwachs i
        3. gehe zu (2).
    • Else: Halt ohne Tier, um zu laichen.

Das ith Intervall (0 <= i < n), in denen Summierungen von 0 <= j < i indiziert ist:

  1. ΣP(j-1) <= x < ΣP(j-1) + Pi (siehe Beispieltabelle)
  2. ΣP(j-1) - ΣP(j-1) <= x - ΣP(j-1) < ΣP(j-1) + Pi - ΣP(j-1) (subtrahieren ΣP(j-1))
  3. 0 <= x - ΣP(j-1) < Pi (vereinfachen)

    • x - ΣP(j-1) wird durch die akkumulative Subtraktion erreicht.
    • 0 <= x wird erreicht durch 0 <= NextDouble() < 1 und wenn x >= Pi dann x - Pi >= 0 (eine Schleifeninvariante).
    • Daher müssen wir nur x < Pi testen.

Hinweis: Dies beruht auf dem Zufallszahlengenerator eine gleichmäßige Verteilung.

+0

Ich schätze wirklich solche Antworten! Eine Antwort wie diese hilft mir, neue Wege zu verstehen und zu lernen, um diesen Dingen näher zu kommen, anstatt mir einfach Code zum Kopieren und Einfügen zu geben. Ich habe versucht, die SpawnAnimal-Methode durch eine neue Methode zu ersetzen, die auf Ihrer Erklärung basiert. Sind die obigen Anpassungen ungefähr das, was du meinst? –

+0

@MinganBeyleveld nicht ganz. Wenn ich "Halt" sage, müssen Sie den Algorithmus beenden, was "Pause" in der Schleife oder "Rückkehr" von der Funktion oder was auch immer angemessen ist. Ich habe auch meine Antwort mit ein paar fehlenden Teilen im Algorithmus korrigiert (die Grenzen überprüfen 'i erisco

+0

Vielen Dank für Ihre Hilfe! Ich habe den Code erneut aktualisiert (hoffentlich richtig). –

0

Sie tun Integer-Division hier:

float startTime = randInt/100 

Ich denke, was Sie wollen, ist:

float startTime = randInt/100f 

Sie bekommen Laich Chance "umgekehrt":

if(randInt <= spawnableAnimals[i].spawnChance 

sollte sein:

if(randInt >= spawnableAnimals[i].spawnChance 

jedoch, dass nicht recht löst alles, denn:

arraySum += randInt; 

ist macht das gleiche wie:

break; 

Wenn also das erste Element in spawnableAnimals einen SpawnChance von 10% hat und das zweite Element in spawnableAnimals einen spawnChance von 90%, erhalten Sie am Ende eine Verteilung von 10% für den ersten und 90% * 90% = 81% für die Sekunde, weil das zweite Element nur versucht wird, wenn das erste fehlgeschlagen ist.