【问题标题】:C# Animal Spawner Logic - Advice RequiredC# Animal Spawner Logic - 需要建议
【发布时间】:2016-04-30 20:39:57
【问题描述】:

我的游戏中有散布在地形上的动物生成器。这个想法是只有当玩家在产卵器范围内时才会产生动物,但如果在产卵器附近有太多动物则不会。这是我到目前为止所做的,但现在我有点卡住了。谁能给我一些关于以下事情的指导:

  • 是否正确计算了生成几率?例如,设置两只动物的生成几率分别为 10% 和 90% 是否实际上会使动物 A 有 10% 的几率生成而动物 B 有 90% 的几率,还是我的数学错误?
  • 我的半径计算是否正确?
  • 最重要的是:我可以改进它吗?

代码:

[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!");
}

}

【问题讨论】:

标签: c# unity3d logic unity5


【解决方案1】:
Vector3.Distance(this.transform.position, players[i].transform.position)

这些位置是否在同一个空间中? Vector3.Distance(x, y) 是指|x - y| 吗?如果是这样,那么计算对我来说看起来不错。

SpawnAnimal 看起来很奇怪。我不确定它在做什么。如果你能解释一下你背后的想法,那我可能会理解。

我会给每只动物分配一个重量。这个数字是任意的,但它们的相对大小很重要。如果猫的体重为 100,狗的体重为 1000,那么狗产卵的可能性是猫的 10 倍。

除此之外:为什么是重量而不是百分比?如果你定义猫有 10% 的产卵机会,狗有 90% 的产卵机会,然后你添加沙鼠,那么剩下多少百分比来分配沙鼠?百分比必须加到 1,因此您必须调整所有其他动物的百分比以腾出空间。如果我们使用权重,猫是 100,狗是 1000,那么我们可以加上体重 500 的沙鼠,我们知道沙鼠的产卵量是猫的 5 倍,是狗的一半——无需调整。

假设您在[0,1) 中生成一个随机数x(这可以通过NextDouble() 完成)。

我们想在[0,1) 中为每只动物分配一个与其体重成正比的区间。先求总重量。

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

据此,我们可以为每只动物指定一个百分比为a.Weight / totalWeight。这些百分比相加为 1,因此您可以在间隔 [0,1) 上分配这些百分比。 Pi 是从被索引的一组动物A 中产生动物Ai 的概率,其中0 &lt;= i &lt; nn|A|(即动物的数量)。

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

现在您只需确定x 位于哪个区间,即生成的动物。这是执行此操作的程序算法。

  1. 初始化A = the set of animalsi = 0x = NextDouble()n = |A|
  2. 如果i &lt; n
    • 那么:如果x &lt; Pi
      • 然后:停止并生成 Ai
      • 其他:
        1. x 中减去Pi
        2. 递增i
        3. 转到 (2)。
    • 否则:在没有动物生成的情况下停止。

ith 区间 (0 &lt;= i &lt; n),其中总和由 0 &lt;= j &lt; i 索引是:

  1. ΣP(j-1) &lt;= x &lt; ΣP(j-1) + Pi(见示例表)
  2. ΣP(j-1) - ΣP(j-1) &lt;= x - ΣP(j-1) &lt; ΣP(j-1) + Pi - ΣP(j-1)(减去ΣP(j-1)
  3. 0 &lt;= x - ΣP(j-1) &lt; Pi(简化)

    • x - ΣP(j-1)是通过累加减法实现的。
    • 0 &lt;= x0 &lt;= NextDouble() &lt; 1 实现,如果 x &gt;= Pi 然后是 x - Pi &gt;= 0(循环不变量)。
    • 因此,我们只需要测试x &lt; Pi即可。

注意:这依赖于具有均匀分布的随机数生成器。

【讨论】:

  • 我非常感谢这样的答案!像这样的答案有助于我理解和学习处理这些事情的新方法,而不仅仅是给我复制和粘贴的代码。根据您的解释,我尝试用新方法替换 SpawnAnimal 方法。上面的调整大致是你的意思吗?
  • @MinganBeyleveld 不太好。当我说“暂停”时,您需要结束算法,这意味着循环中的break 或函数中的return 或任何适当的。我还用算法中的几个缺失部分修复了我的答案(边界检查i &lt; ni 的增量)。
  • 非常感谢您的帮助!我再次更新了代码(希望做得正确)?
  • @MinganBeyleveld 看起来不错。确保spawnableAnimals[i].spawnWeight / totalWeight 是浮点除法而不是整数除法。
【解决方案2】:

你在这里做整数除法:

float startTime = randInt / 100

我想你想要的是:

float startTime = randInt / 100f

你的生成机会“反转”了:

if(randInt <= spawnableAnimals[i].spawnChance

应该是:

if(randInt >= spawnableAnimals[i].spawnChance

但是,这并不能完全解决问题,因为:

arraySum += randInt;

做同样的事情:

break;

因此,如果 spawnableAnimals 中的第一个元素的 spawnChance 为 10%,而 spawnableAnimals 中的第二个元素的 spawnChance 为 90%,那么您最终将得到第一个元素的 10% 和 90% * 90 的分布% = 81% 对于第二个,因为只有在第一个失败时才会尝试第二个元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多