Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取给定泛型数组c的浮点变量#_C#_Unity3d_Random - Fatal编程技术网

C# 获取给定泛型数组c的浮点变量#

C# 获取给定泛型数组c的浮点变量#,c#,unity3d,random,C#,Unity3d,Random,我正在创建一个经常使用加权繁殖的RPG。许多职业,如怪物、战利品或地下城世代,都有一个叫做“繁殖几率”的变量,该值为0-100,决定了繁殖率 我以前一直使用这种选择方式从数组中获取随机加权成员 var weights = enemy.Select(e => e.spawnChance); var index = weights.GetRandomWeightedIndex(); return enemy[index]; 这是分机 public static int GetRand

我正在创建一个经常使用加权繁殖的RPG。许多职业,如怪物、战利品或地下城世代,都有一个叫做“繁殖几率”的变量,该值为0-100,决定了繁殖率

我以前一直使用这种选择方式从数组中获取随机加权成员

 var weights = enemy.Select(e => e.spawnChance);
 var index = weights.GetRandomWeightedIndex();
 return enemy[index];
这是分机

 public static int GetRandomWeightedIndex(this IEnumerable<float> weights)
{
    int count = weights.Count();
    if (weights == null || count == 0)
    {
        Debug.LogWarning($"Weights are invalid");

        return -1;
    }
    else if (count == 1)
        return 0;
    float w;
    float t = 0;
    int i;
    for (i = 0; i < count; i++)
    {
        w = weights.ElementAt(i);

        if (float.IsPositiveInfinity(w))
        {
            return i;
        }
        else if (w >= 0f && !float.IsNaN(w))
        {
            t += weights.ElementAt(i); ;
        }
    }

    float r = UnityEngine.Random.value;
    float s = 0f;

    for (i = 0; i < count; i++)
    {
        w = weights.ElementAt(i); ;
        if (float.IsNaN(w) || w <= 0f) continue;

        s += w / t;
        if (s >= r) return i;
    }

    return -1;
}
public static int GetRandomWeightedIndex(此IEnumerable weights)
{
int count=weights.count();
如果(权重==null | |计数==0)
{
Debug.LogWarning($“权重无效”);
返回-1;
}
否则如果(计数=1)
返回0;
浮动w;
浮动t=0;
int i;
对于(i=0;i=0f&&!float.IsNaN(w))为else
{
t+=权重。元素at(i);
}
}
float r=UnityEngine.Random.value;
浮点数s=0f;
对于(i=0;i
但是,我想减少这段代码,因为通过linq选择所有浮点值,然后将其传递到扩展中,然后再返回的方法相当繁琐,并且使用了几十次

我曾想过使用反射在泛型类中查找一个名为“spawnChance”的变量,但由于所有内容都是在运行时生成的,因此速度相当慢

我是否可以将一个简单的浮点转换成一个类,然后以某种方式编写一个linq方法,该方法将能够有效地提取该类的值?由于项目设置的原因,这些类无法从spawnChance类继承。
思想?谢谢你的时间

您可以定义一个接口,然后让公开繁殖机会的类实现它。然后很容易测试对象是否实现了它

public interface ISpawnable
{
    float SpawnChance { get; }
}
SpawnChance
必须是属性。没有必要为这个用例声明setter(因为您只需要阅读它);但是,实现仍然可以提供一个

然后你可以测试

if (obj is ISpawnable spawnable) {
    float w = spawnable.SpawnChance;
    ...
}
如果有混合对象列表,也可以使用LINQ

var weights = mixedTypeObjects
    .OfType<ISpawnable>()         // Filters objects implementing it and casts to it.
    .Select(x => x.SpawnChance);
看看你跟谁一起去

public class Spawner : MonoBehaviour
{
    [System.Serializable]
    public class WeightedItem
    {
        public GameObject Prefab; // Or whatever you're randomising
        public float Weight;
    }

    public WeightedItem[] Items;

    private float TotalWeight;

    public void Start() {
        // If your lists don't change, pre-calc TotalWeight here.
        // If they do change, you'll have to recalculate it when it does.
        TotalWeight = Items.Sum(m => m.Weight);
    }

    public object RandomItem() 
    {
        // Get your 'random' selection.
        var selectionWeight = Random.Range(0, TotalWeight);

        // Parse over the array to find it
        for (var i = 0; i < Items.Length; i++) {
            selectionWeight -= Items[i].Weight;

            if (selectionWeight <= 0)
                return Items[i].Prefab;
        }

        // Should never reach here unless your TotalWeight is wrong
        throw new System.ApplicationException("Randomised Weight exceeded Total Weight!");
    }
}
公共类生成程序:单行为
{
[系统可序列化]
公共类WeightedItem
{
公共游戏对象预制;//或任何你正在随机化的东西
公众浮力;
}
公共物品【】项;
私人浮动总重量;
公开作废开始(){
//如果您的列表没有更改,请在此预先计算总重量。
//如果它们确实发生了变化,那么当它发生变化时,您必须重新计算它。
总重量=项目总重量(m=>m.Weight);
}
公共对象项()
{
//获取您的“随机”选择。
var selectionWeight=随机范围(0,总重量);
//对数组进行分析以找到它
对于(变量i=0;iif(selectionWeight如果我是你,我会实现生成概率,而不是浮点数,而是整数百分比。请记住,C#中的
float
s不是小数,而是基2数(特别是二进制中的二进制32数,如0.010101)。将二进制数视为小数有时会导致令人惊讶的结果。或者,C#的
System.Decimal
Decimal
)可以使用,这是一种十进制数字格式。如果正确处理浮点数,也就是说,将其用作求和的“距离”而不是离散度量值,则浮点数是可以使用的。接口可能不理想,但泛型会很理想。谢谢!修改此方法是可行的。看起来接口可以工作,但它们不能很好地使用统一,因为它们不是在inspector中没有解决方法也不会暴露,也不会序列化。@SkylarStickley我一直推荐的“资产”实际上只有两种,DOTween和Odin inspector。Odin为inspector的显示和序列化添加了大量的生活质量改进。绝对值得一试。(但不会改变这个答案=)
public static int GetRandomWeightedIndex(this IEnumerable<GameObjects> gameObjects)
{
    var weights = gameObjects
        .OfType<ISpawnable>()
        .Select(g => g.SpawnChance);
    ...
}
public class Spawner : MonoBehaviour
{
    [System.Serializable]
    public class WeightedItem
    {
        public GameObject Prefab; // Or whatever you're randomising
        public float Weight;
    }

    public WeightedItem[] Items;

    private float TotalWeight;

    public void Start() {
        // If your lists don't change, pre-calc TotalWeight here.
        // If they do change, you'll have to recalculate it when it does.
        TotalWeight = Items.Sum(m => m.Weight);
    }

    public object RandomItem() 
    {
        // Get your 'random' selection.
        var selectionWeight = Random.Range(0, TotalWeight);

        // Parse over the array to find it
        for (var i = 0; i < Items.Length; i++) {
            selectionWeight -= Items[i].Weight;

            if (selectionWeight <= 0)
                return Items[i].Prefab;
        }

        // Should never reach here unless your TotalWeight is wrong
        throw new System.ApplicationException("Randomised Weight exceeded Total Weight!");
    }
}