Цвет единства не будет присваиваться мячу или тому, что он должен рисовать

#c# #unity3d #colors

Вопрос:

 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 amp;amp; !ground.isColored)
        {
            ground.Colored(solveColor);
        }
 

Приведенный выше код должен выбрать один цвет из массива цветов и назначить его как способности к рисованию мяча, так и шаров (всякий раз, когда мяч сталкивается с землей, он меняет свой цвет), однако краска, которую оставляет мяч, всегда черная, а сам мяч всегда оранжевый (почти уверен, что цвет шара по умолчанию). Я не могу понять, почему это происходит, любая помощь очень ценится.

Спасибо, что уделили мне время

Ответ №1:

В предоставленном вами коде вы нигде больше не указываете цвет материала шара, кроме Start как . Если вы хотите, чтобы частицы за шаром оставляли разные цвета, вам нужно будет создать новый экземпляр материала. Причина этого в том, что материалы в Unity по умолчанию являются общими для всех экземпляров этого конкретного материала.

Всю эту информацию и немного больше можно найти на странице Material документов.

Поскольку у вас есть фиксированный размер используемых цветов, я бы вместо этого создал 6 новых материалов и вместо этого создал массив материалов. Теперь вместо того, чтобы случайным образом выбирать цвет, выберите материал и назначьте его мячу или вашей новой способности к рисованию. Я также не понимаю, почему вы размещаете свой массив цветов внутри своей Start функции. Только тогда он будет локализован для этой функции. У вас также, похоже, есть две Start функции, что странно. Одно из 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 amp;amp; !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 функцию, чтобы использовать a Material вместо a Color . Если вы хотите, чтобы реализация была более динамичной, вы можете вместо этого создать экземпляр вашего материала и динамически задать цвет, но поскольку у вас фиксированный размер цветов, я не думаю, что вам нужно это делать.

Изменить: Еще один вариант, который включает в себя создание нового шейдера, — использовать [PerRendererData] значение, означающее, что каждый объект для поля свойств отображается индивидуально. Я бы выбрал предыдущий вариант, так как любой из вариантов с использованием шейдеров или экземпляров материалов немного сложнее.

Вам нужно будет использовать a 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);
}
 

И вам нужно будет создать новый шейдер, который позже Main Color будет использовать свойство с помощью PerRendererData атрибута.

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

Кроме того, у меня есть еще один вопрос: почему вы используете Physics.OverlapSphere вместо просто an OnCollisionEnter ? Или если ваша игра 2D, то OnCollisionEnter2D и пусть физический движок обрабатывает, как работают столкновения, а затем просто меняет цвета при столкновении?

Редактировать: Вот ответы на ваши вопросы — дайте мне знать, если у вас есть еще.

В строке «[SerializeField] материалы частного списка = новый список();» какой раздел мне нужно заменить материалами и как?

Линия как есть в порядке. С его помощью [SerializeField] этот список открывается редактору. Вам понадобится создать несколько новых дубликатов материалов, в которых будут использованы ваши 6 различных цветов. Вместо того, чтобы задавать цвета, теперь вы будете задавать материалы. Что я подразумеваю под инспектором и редактором, так это то, что вы можете найти объект, на котором есть этот сценарий, в Unity, выбрать его (он должен быть сборным или в сцене), затем вкладка редактора Unity заполнится информацией об этом объекте. Найдите часть сценария и найдите поле materials . Там должна быть стрелка раскрывающегося списка, нажмите на нее и установите значение 6 (или сколько бы материалов вы ни поменяли местами). Теперь создайте 6 новых материалов с вашими цветами и перетащите их в появившиеся поля.

Было бы это что-то вроде написания «./Материалы/Мяч 1» в (), например?

Нет! Вы будете назначать эти данные в инспекторе, поэтому данные будут храниться в списке без ссылок на них в коде.

И я не уверен, как назначить это моему мячу, используя «[SerializeField] частный игровой объект paintObject = null;»

Аналогично, это будет отображаться в инспекторе. Однако удалите эту строку, так как я неправильно понял ваш первоначальный вопрос и случайно оставил это. Я предположил, что ваш объект рисования был сборным, который вы создавали после того, как мяч отскочил, а не землей, цвет которой вы меняли.

Я получаю ошибку «Аргумент 1: не удается преобразовать из ‘UnityEngine.Материал» для «UnityEngine.Цвет»»

Да! Итак, как я уже упоминал в комментариях, ваш вызов функции для объекта paint, скорее всего, в настоящее время принимает Color параметр. Поскольку я изменил вашу реализацию на вместо этого напрямую Material , вам нужно будет изменить способ подписи этой функции. В частности, линия:

 ground.Colored(meshRenderer.material);
 

У вас есть некоторый объект ground , который имеет тип GroundPiece и имеет вызываемую функцию Colored . Я предполагаю, что в настоящее время это выглядит примерно так:

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

Вы хотите изменить это вместо этого на:

 public void Colored(Material mat{...}
 

После его изменения вместо изменения цвета грунта в этом сценарии вы бы изменили его материал напрямую. Дайте мне знать, если у вас возникнут еще вопросы.

Комментарии:

1. Большое вам спасибо за все ваши советы, я прочитал их и ссылки на материалы, которые вы предоставили, и еще несколько вопросов (извините, если это просто, я использую unity и c# только около 2 дней, так что я все еще не уверен в этом). В строке «[SerializeField] закрытый список<Материал> материалы = новый список<Материал><Материал>();» какой раздел мне нужно заменить материалами и как? Было бы это что-то вроде написания «./Материалы/Мяч 1» в (), например? И я не уверен, как назначить это моему мячу, используя «[SerializeField] частный игровой объект paintObject = null;», потому что

2. этот скрипт прикрепляется к самому мячу (он также управляет его движением при свайпе и т. Д.). Мой последний вопрос: почему я получаю ошибку «Аргумент 1: не удается преобразовать из ‘UnityEngine. Материал» для «UnityEngine. Цвет». Еще раз большое вам спасибо за всю вашу помощь, и мне жаль, если это простые/очевидные исправления. Хорошего вам дня!

3. Не беспокойтесь! Я отвечу на ваши вопросы по порядку в качестве обновленной части моего ответа.

4. Если вы не знакомы с инспектором, это выглядит примерно так . Как только вы нажмете на раскрывающийся список и увеличите количество, вы сможете перетащить Material ссылки на него.

5. Спасибо тебе огромное, я бы никогда не догадался об этом без твоей помощи. Теперь это работает отлично, спасибо вам за ваше терпение и объяснения, я действительно ценю это, это именно то, что я искал!