【问题标题】:Unity color wont assign to ball or what it should be painting统一颜色不会分配给球或它应该画什么
【发布时间】:2021-05-28 20:32:29
【问题描述】:
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);
        }

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

感谢您的宝贵时间

【问题讨论】:

    标签: c# unity3d colors


    【解决方案1】:

    在您提供的代码中,除了Start,您没有再设置球的材质颜色。如果你想让球后面的粒子留下不同的颜色,你需要实例化一个新的材质实例。这是因为 Unity 中的材质默认在该特定材质的所有实例之间共享。

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

    由于您使用的颜色大小是固定的,因此我将改为创建 6 种新材料并制作一组材料。现在,与其随机选择颜色,不如选择一种材料并将其分配给球或您的新实例绘画能力。我也很困惑为什么你将你的颜色数组放在你的 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。如果您希望实现更加动态,您可以改为创建材质实例并动态设置颜色,但由于您有固定大小的颜色,我认为您不需要这样做。

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

    您需要使用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 并让物理引擎处理碰撞的工作方式,然后在发生碰撞时更改颜色?

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

    在“[SerializeField] private List materials = new List();" 我需要将哪个部分替换为 材料和方法?

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

    会不会类似于在 () 中写“./Materials/Ball 1” 例子?

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

    我不确定如何使用“[SerializeField] 将其分配给我的球 私有游戏对象paintObject = null;"

    同样,这会出现在检查器中。但是,请删除此行,因为我误解了您的原始问题并不小心将其留在了其中。我认为您的绘画对象是您在球反弹后生成的预制件,而不是您要更改颜色的地面。

    我收到错误“参数 1:无法从 'UnityEngine.Material' 到 'UnityEngine.Color'"

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

    ground.Colored(meshRenderer.material);
    

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

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

    您想改为:

    public void Colored(Material mat{...}
    

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

    【讨论】:

    • 非常感谢您的所有建议,我通读了它和您提供的材料链接以及其他几个问题(对不起,如果它很简单,我只使用了 unity 和 c# 2天,所以我真的不确定)。在“[SerializeField] private List materials = new List();”这一行中我需要用材料替换哪个部分以及如何替换?例如在 () 中写“./Materials/Ball 1”之类的东西吗?而且我不确定如何使用“[SerializeField] private GameObject paintObject = null;”将它分配给我的球因为
    • 这个脚本被附加到球本身(它还控制它在滑动等时的移动)。我的最后一个问题是为什么我会收到错误“参数 1:无法从 'UnityEngine.Material' 转换为 'UnityEngine.Color'”。再次非常感谢您的所有帮助,如果这些是简单/明显的修复,我很抱歉。祝你有美好的一天!
    • 别担心!我将按顺序回答您的问题,作为我答案的更新部分。
    • 如果你不熟悉inspector,它看起来像this。单击下拉列表并增加计数后,您将能够拖入 Material 对其的引用。
    • 非常感谢您,如果没有您的帮助,我永远不会想到这一点。它现在完美运行,感谢您的耐心和解释,我真的很感激这正是我想要的!
    猜你喜欢
    • 2022-12-25
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2022-11-11
    • 2010-10-20
    • 2020-03-26
    相关资源
    最近更新 更多