c# - 生成随机颜色并排除旧颜色的最佳方法

标签 c# unity3d random colors

不太确定如何表述标题,但我想每秒在一个对象上生成一种随机颜色。我还希望这种颜色与对象已有的旧颜色不相似。如果当前随机颜色与对象已有的颜色相同,则再次重新生成随机颜色。该对象只是一个 Text 组件。

这是我用来生成颜色的函数:

public Color genRandomColor()
{
    float r, g, b;
    r = UnityEngine.Random.Range(0f, 1f);
    g = UnityEngine.Random.Range(0f, 1f);
    b = UnityEngine.Random.Range(0f, 1f);

    return new Color(r, g, b);
}

为了比较颜色是否相似,我移植并使用了this中的函数回答 C#。

public double ColourDistance(Color32 c1, Color32 c2)
{
    double rmean = (c1.r + c2.r) / 2;
    int r = c1.r - c2.r;
    int g = c1.g - c2.g;
    int b = c1.b - c2.b;
    double weightR = 2 + rmean / 256;
    double weightG = 4.0;
    double weightB = 2 + (255 - rmean) / 256;
    return Math.Sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
}

我将随机颜色生成器放在协程函数内的 while 循环中,一遍又一遍地运行,直到生成的颜色不相似。每次生成随机颜色时,我都使用 yield return null; 等待一个帧,这样它就不会卡住程序。

const float threshold = 400f;
bool keepRunning = true;

while (keepRunning)
{
    Text text = obj.GetComponent<Text>();

    //Generate new color but make sure it's not similar to the old one
    Color randColor = genRandomColor();
    while ((ColourDistance(text.color, randColor) <= threshold))
    {
        Debug.Log("Color not original. Generating a new Color next frame");
        randColor = genRandomColor();
        yield return null;
    }

    text.color = randColor;
    yield return new WaitForSeconds(1f);
}

一切似乎都在解决一个小问题。

问题是有时需要 13 秒来重新生成与旧颜色不相似的颜色。我删除了 yield return null; 以防止它等待每一帧,它现在似乎可以工作,但我冒着卡住整个游戏的风险,因为我现在使用随机函数来控制 while循环。我已经注意到微小的卡住,这并不好。

在不卡住游戏或等待几秒钟的情况下生成与对象的新颜色不相似的随机颜色的更好方法是什么?

最佳答案

我会采取不同的方法:

  • 生成一个在[0; 2]代表红、绿、蓝
  • 第一步刚确定的颜色加0.5,大于1则减-1
  • 生成2个独立的随机 float ,范围在[0; 1] 用于剩余的两个颜色分量

示例:假设我们有 C1 = (R1; G1; B1) = (0.71; 0.22; 0.83)

  • 假设第 1 步产生索引 0,即红色
  • 所以我们取 R1 + 0.5 = 0.71 + 0.5f = 0.21f
  • 我们创建 G2 和 B2 作为新的绿色和蓝色分量并得到 (0.21f; G2; B2)

即使 G2 和 B2 与其前身相同,新颜色也会随着 R2 的移动而明显不同

更新代码

public static class RandomColorGenerator
{
    public static Color GetNextPseudoRandomColor(Color current)
    {
        int keep = new System.Random().Next(0, 2);
        float red = UnityEngine.Random.Range(0f, 1f);
        float green = UnityEngine.Random.Range(0f, 1f);
        float blue = UnityEngine.Random.Range(0f, 1f);
        Color c = new Color(red, green, blue);
        float fixedComp = c[keep] + 0.5f;
        c[keep] = fixedComp - Mathf.Floor(fixedComp);
        return c;
    }
}

测试:

public class RandomColorTest
{
    [Test]
    public void TestColorGeneration()
    {
        Color c = Color.magenta;
        for (int i = 0; i < 100; i++)
        {
            Vector3 pos = new Vector3(i / 20f, 0f, 0f);
            c = RandomColorGenerator.GetNextPseudoRandomColor(c); 
            Debug.Log(i + " = " + c);
            Debug.DrawRay(pos, Vector3.up, c);
        }
    }
}

运行编辑器测试后,场景 View 在 (0; 0; 0) 附近 enter image description here

关于c# - 生成随机颜色并排除旧颜色的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47617199/

相关文章:

c# - PageSize 和 MaxTop 的区别

c# - RestSharp Deserialize 返回空属性,但 xml.deserialize 测试有效

C# Mono aot 与 protobuf-net 获取 ExecutionEngineException

c# - 如何在 C# 中的 XML 文件中添加 XML 属性

c# - ASP.Net Core - 在哪里可以找到项目中已安装的 Nuget 包列表

c# - 如何从必须留在主线程上的方法统一调用异步方法

c# - 玩家在与标记对象碰撞时消失

javascript - 需要一个 Java 生成器(如果可能的话,使用正则表达式)

c - 生成一个长度为25的随机数

python - 如何在python中生成随机数字序列?