统一颜色不会分配给球或它应该画的东西

Unity color wont assign to ball or what it should be painting

private Color solveColor;

void Start()
{
    Color[] colors = { Color.cyan, Color.red, Color.green, new Color(245, 195, 29), Color.yellow, Color.magenta };

    int lengthOfColors = colors.Length;
    int solveColor = UnityEngine.Random.Range(0, lengthOfColors);

}
private void start()
{
    GetComponent<MeshRenderer>().material.color = solveColor;
}

private void FixedUpdate()
{
    // Set the balls speed when it should travel
    if (isTraveling) {
        rb.velocity = travelDirection * speed;
    }

    // Paint the ground
    Collider[] hitColliders = Physics.OverlapSphere(transform.position - (Vector3.up/2), .05f);
    int i = 0;
    while (i < hitColliders.Length)
    {
        GroundPiece ground = hitColliders[i].transform.GetComponent<GroundPiece>();

        if (ground && !ground.isColored)
        {
            ground.Colored(solveColor);
        }

上面的代码应该从颜色数组中选择一种颜色并将其分配给球和球的绘画能力(每当球与地面碰撞时它会改变颜色)但是球离开的颜色总是黑色,球本身总是橙色(很确定球的颜色来自其默认值)。我不明白为什么会这样,非常感谢任何帮助。

感谢您的宝贵时间

在您提供的代码中,除了 Start 之外,您没有在任何地方再次设置球的 material 颜色。如果你想让小球后面的粒子留下不同的颜色,你需要实例化一个新的material实例。这样做的原因是因为 Unity 中的 materials 默认在该特定 material.

的所有实例之间共享

所有这些信息以及更多信息都可以在 Material 文档页面上找到。

由于您使用的颜色大小固定,因此我会改为创建 6 个新的 material 并制作一个 material 数组。现在,不是随机选择一种颜色,而是选择一个 material 并将其分配给球或您的新实例绘画能力。我也很困惑为什么要将颜色数组放在 Start 函数中。只有这样,它才会被本地化为该功能。您似乎还有两个 Start 函数,这很奇怪。一个是 Monobehaviour Start,另一个是 start。除非有意,否则你的第二个 start 不会是 运行 除非你调用它。

现在开始我所说的解决方案。

// assign these in the inspector to your new materials
[SerializeField] private List<Material> materials = new List<Material>();

private MeshRenderer meshRender;

private void Start()
{
    meshRenderer = GetComponent<MeshRenderer>();
    
    // set our first random Material
    SetNewMaterialColor();
}

private void SetNewMaterialColor()
{
    meshRenderer.material = GrabNewMaterial();
}

private void FixedUpdate()
{
    // Set the balls speed when it should travel
    if (isTraveling) {
        rb.velocity = travelDirection * speed;
    }
    
    // Paint the ground
    Collider[] hitColliders = Physics.OverlapSphere(transform.position - (Vector3.up/2), .05f);
    int i = 0;
    while (i < hitColliders.Length)
    {
        GroundPiece ground = hitColliders[i].transform.GetComponent<GroundPiece>();
    
        if (ground && !ground.isColored)
        {
            // change this from a color to a material instead
            ground.Colored(meshRenderer.material);
            
            // set a new material to your main object
            SetNewMaterialColor();
        }
    }
}

private Material GrabNewMaterial()
{
    return materials[UnityEngine.Random.Range(0, materials.Count)];
}

您需要更改 Colored 函数以接收 Material 而不是 Color。如果您希望实现更加动态,您可以改为创建 material 的实例并动态设置颜色,但由于您有固定大小的颜色,我认为您不需要这样做。

编辑:另一个涉及创建新着色器的选项是利用 [PerRendererData],这意味着 属性 字段的每个对象都是单独渲染的。我会选择前一个选项,因为使用着色器或实例化的选项 materials 有点复杂。

您需要使用 MaterialPropertyBlock 然后可以在需要时指定颜色。它看起来像

public void SetNewColor()
{
    // create a new material property block
    MaterialPropertyBlock tmpBlock = new MaterialPropertyBlock();
    
    // grab the current block from our renderer
    meshRender.GetPropertyBlock(tmpBlock);
    
    // set our changes to the block
    tmpBlock.SetColor("_Color", YourColorHere);
    
    // now apply our changes
    tmpRend.SetPropertyBlock(tmpBlock);
}

并且您需要创建一个新的着色器,通过使用 PerRendererData 属性晚于 Main Color 属性。

Properties
    {
        [PerRendererData]_Color("Main Color", Color) = (1,1,1,1)
...

此外,我还有一个问题是为什么您使用 Physics.OverlapSphere 而不是 OnCollisionEnter?或者,如果您的游戏是 2D 的,那么 OnCollisionEnter2D 并让物理引擎处理碰撞的工作方式,然后在碰撞发生时更改颜色?

编辑:这是您问题的答案 - 如果您有更多问题,请告诉我。

In the line "[SerializeField] private List materials = new List();" which section do I need to replace with the materials and how?

原样的线没问题。通过使用 [SerializeField] 它将此列表公开给编辑器。您将要创建几个使用 6 种不同颜色的新副本 material。您现在将设置 materials 而不是设置颜色。我所说的检查员和编辑器的意思是,您可以在 Unity 中找到带有此脚本的对象,select 它(它必须是预制件或在场景中),然后 Unity 编辑器的选项卡将填充关于这个对象的信息。找到脚本部分并找到字段 materials。应该有一个下拉箭头,单击它并将数字设置为 6(或您想要的任何 material 交换)。现在用您的颜色创建 6 个新的 material 并将它们拖到出现的框中。

Would it be something like writing "./Materials/Ball 1" in the () for example?

不!您将在检查器中分配此数据,因此数据将存储在列表中而无需在代码中引用它们。

And I'm not sure how to assign this to my ball using "[SerializeField] private GameObject paintObject = null;"

同样,这会出现在检查器中。但是,删除这一行,因为我误解了你原来的问题,不小心把它留在了里面。我假设你的油漆对象是你在球反弹后产生的预制件,而不是你改变颜色的地面。

I get the error "Argument 1: cannot convert from 'UnityEngine.Material' to 'UnityEngine.Color'"

是的!因此,正如我在评论中提到的,您对 paint 对象的函数调用当前很可能采用 Color 参数。当我将您的实现更改为直接设置 Material 时,您将需要更改该函数签名的方式。具体行:

ground.Colored(meshRenderer.material);

您有一些类型为 GroundPiece 的对象 ground,并且有一个名为 Colored 的函数。我假设它目前看起来像:

public void Colored(Color color){...}

您想将其更改为:

public void Colored(Material mat{...}

更改后,您无需在此脚本中更改地面颜色,而是直接更改其 material。如果您有更多问题,请告诉我。