Как сделать так, чтобы после исчезновения объекта, он появлялся снова через некоторое время?

Всем привет. Столкнулся с такой проблемой, что при соприкосновении с "Игроком", "Монетка" должна исчезнуть, но через некоторое время снова появиться на этом же месте. Никак не получается это реализовать. Пробовал через корутину не работает:(

public GameObject coinEffect;
public int coinsCount;
public Text coins;
void Start()
{
    
}

// Update is called once per frame
void Update()
{
    
}

public void OnTriggerEnter2D(Collider2D other) 
{
    if(other.CompareTag("Player"))
    {
        StartCoroutine(coinsTake());
        coinsCount += 1;
        coins.text = " " + coinsCount.ToString();
        Instantiate(coinEffect, gameObject.transform.position, Quaternion.identity);
        gameObject.SetActive(false);
    }
}
IEnumerator coinsTake() 
{
    yield return new WaitForSeconds(3f);
    gameObject.SetActive(true);
}

Ответы (3 шт):

Автор решения: Вячеслав Бородин

Смог реализовать это с помощью Invoke.

public GameObject coinEffect;
public int coinsCount;
public Text coins;
void Start()
{
    
}

void Update()
{
    
}

public void OnTriggerEnter2D(Collider2D other) 
{
    if(other.CompareTag("Player"))
    {
        coinsCount += 1;
        coins.text = " " + coinsCount.ToString();
        Instantiate(coinEffect, gameObject.transform.position, Quaternion.identity);
        gameObject.SetActive(false);
        Invoke("SpawnCoin", 2f);
    }
}

public void SpawnCoin() 
{
    gameObject.SetActive(true);
}
→ Ссылка
Автор решения: Алексей Шиманский

Вы не сможете стартовать корутину из скрипта который прикреплен к неактивному объекту. Ну, почти...

StartCoroutine - метод, который прикреплён к классу MonoBehaviour. Когда вам нужно стартова корутину на деактивированном объекте, вам нужно сослаться на MonoBehaviour объекта, который имеет активный GameObject

Парочка способов сделать это:

1. Использовать существующий объект, который вряд ли будет деактивирован. Например можно использовать камеру. Например вот так:

// Деактивировать текущий GameObject
gameObject.SetActive(false);
// Найти камеру
MonoBehaviour camMono = Camera.main.GetComponent<MonoBehaviour>();
// Использовать её для запуска корутины
camMono.StartCoroutine(Load());

2. Прикрепить скрипт к пустому GameObject и этот скрипт будет контролировать (или будет способен активировать/деактивировать) другие объекты, в числе которых ваш.

Пример: скрипт с корутиной, которую вы планируете запустить на неактивном объекте (прикрепите её к объекту)

public class YourDeactivatableScript: MonoBehaviour
{
    public IEnumerator coinsTake()
    {
       yield return new WaitForSeconds(3f);
        gameObject.SetActive(true);
    }
}

Теперь, предположим, вы хотите деактивировать GameObject по имени "Cube", который содержит YourDeactivatableScript. Создайте пустой GameObject и прикрепите к нему скрипт:

public class LoadFuncCallerScript: MonoBehaviour
{
    GameObject targetObject;

    public void Start()
    {
         // Найти GameObject, который надо деактивировать
        targetObject = GameObject.Find("Cube");
        // Деактивировать его
        targetObject.SetActive(false);
        // Взять его компонент/скрипт
        YourDeactivatableScript script = targetObject.GetComponent<YourDeactivatableScript>();
        // Сделать старт корутины за счёт его MonoBehaviour
        StartCoroutine(script.coinsTake());
    }
}

Корутина теперь запустится за счёт другого скрипта на другом объекте ( LoadFuncCallerScript).


3. Ещё вариант содержать какой-нибудь общий менеджер объектов с общим скриптом. Где есть словарь или список, в который добавляются объекты при инстанициировании и удаляются при уничтожении. Т.к. он будет общий для объектов, то и некоторые методы можно расположить в нём (активацию/деактивацию). В нужный момент там запускается метод temporaryDisable(gameObject, time), в который передаётся объект и время. Дальше этот объект ищется скриптом в словаре/списке и делает с ним что хочется, в данном случае: деактивация -> реактивация через установленное время

→ Ссылка
Автор решения: Yaroslav

Вместо gameObject.SetActive(...);, используй SetVisible(...); и корутина заработает.

private void SetVisible (bool visible) {
    GetComponent<Renderer>().enabled = visible;
    GetComponent<Collider>().enabled = visible;
}
→ Ссылка