Дорогой вызов GetComponent (), не уверен, как кэшировать

#c# #unity3d

Вопрос:

Я получаю предупреждение о производительности от своей среды разработки о том, что вызов GetComponent() является дорогостоящим, особенно с учетом того, что я вызываю MoveCards() в Update(). Я понимаю, почему это дорого, и обычно знаю, как исправить кэширование в Awake (), но поскольку оно имеет префикс[i], я не уверен, как это сделать.

 private void MoveCards()
        {
            // This loop moves the cards.
            for (var i = 0; i < cards.Length; i  )
            {
                cards[i].localPosition = Vector3.Lerp(cards[i].localPosition, cardPositions[i   cardArrayOffset],
                    Time.deltaTime * cardMoveSpeed);
                if (!(Mathf.Abs(cards[i].localPosition.x - cardPositions[i   cardArrayOffset].x) < 0.01f)) continue;
                cards[i].localPosition = cardPositions[i   cardArrayOffset];

                // This disables interaction with cards that are not on top of the stack.
                cards[i].gameObject.GetComponent<CanvasGroup>().interactable = cards[i].localPosition.x == 0;
            }
        }
 

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

1. Вы можете хранить ссылки в словаре и захватывать группу canvas по объекту. Таким образом, у вас будет <GameObject, CanvasGroup>. Чтобы расширить эту функциональность, просто измените CanvasGroup на класс и сохраните в нем несколько ссылок. Класс будет просто хранить данные и больше ничего не делать. Кроме того, почему вы используете группу canvas для одного объекта? Имеют ли карты больше взаимодействий, чем сама карта?

2. Что это за тип cards ?

3. @Ruzihm Преобразование[]

4. cards[i].localPosition.x == 0 При сравнении поплавков лучше проводить приблизительное сравнение в случае ошибок округления. Mathf.Approximately(0f, cards[i].localPosition.x);

5. Спасибо @Ruzihm, я ценю вашу помощь.

Ответ №1:

Что бы я сделал, так это сделал так, чтобы у карточного игрового объекта было собственное монообъектное поведение для хранения ссылки на эти компоненты. Затем измените коллекцию карт, чтобы сохранить ссылку на монопод карты.

Ответ №2:

Вы бы хранили cards[] как a CanvasGroup вместо a GameObject .

Вы бы объявили это так в Awake() :

  GameObject[] cardObjects = new GameObject[10];
 CanvasGroup[] cards = new CanvasGroup[cardObjects.Length];

 for (int i = 0; i < cardObjects.Length; i  )
 {
     cards[i] = cardObjects[i].GetComponent<CanvasGroup>();
 }
 

Мы перебираем все объекты карты и назначаем этот компонент определенному объекту в массиве.

В вашей функции, которую вы показали в вопросе, вы изменили бы ее на эту:

 private void MoveCards()
{
    for (int i = 0; i < cardObjects.Length; i  )
    {
        cardObjects[i].transform.localPosition = Vector3.Lerp(cardObjects[i].transform.localPosition, cardPositions[i   cardArrayOffset], Time.deltaTime * cardMoveSpeed);
        if (!(Mathf.Abs(cardObjects[i].transform.localPosition.x - cardPositions[i   cardArrayOffset].x) < 0.01f)) continue;
            cardObjects[i].localPosition = cardPositions[i   cardArrayOffset]
            cards[i].interactable = cardObjects[i].transform.localPosition.x == 0;
        }
    }
 

Мы меняем все cards переменные на cardObjects . На GetComponent<>() линии мы сохраняем cards и удаляем .gameObject.GetComponent<CanvasGroup>() .

Важно: Вы не показали нам, где были созданы некоторые переменные. Нравится cardPositions . Если это создано с помощью cards , обязательно используйте cardObjects переменную.

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

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