Я пытаюсь заполнить различные объекты в Unity, основываясь на некоторых триггерах и некоторых данных.Данные, которые я использую, выглядят примерно так Key === O2 Values are ==== { collected, collected, collected, absent}Key === O3 Values are ==== { collected, collected, present }
, которые хранятся в объекте Dictionary Dictionary<string, List<string>> textMap
.Следующий скрипт прикреплен к этим объектам:
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class SensePlayerProximity : MonoBehaviour {
bool disableEntry = false;
bool disableExit = false;
public bool isCollected = false;
//List<Collider2D> triggerList = new List<Collider2D>();
// Use this for initialization
static Dictionary<string, List<string>> textMap = new Dictionary<string, List<string>>
{
{ "O2", new List<string>() { "present", "absent", "absent", "absent" }},
{ "O3",new List<string>() { "absent", "absent", "absent" }}
};
private void OnTriggerEnter2D(Collider2D collision)
{
if (disableEntry || isCollected)
return;
StartCoroutine(disableTriggersForThisCollectible(10));
List<String> values;
foreach (KeyValuePair<string, List<string>> kvp in textMap)
{
values = kvp.Value;
int foundAtIndex = values.IndexOf("absent");
if (foundAtIndex > -1)
{
gameObject.GetComponent<TextMeshProUGUI>().text = kvp.Key;
values[foundAtIndex] = "present";
textMap.Remove(kvp.Key);
textMap.Add(kvp.Key, values);
logTextMap();
return;
}
}
// if nothing is found, then default the text to empty, since nothing left to be collected now
gameObject.GetComponent<TextMeshProUGUI>().text = "";
}
//called when something exits the trigger
private void OnTriggerExit2D(Collider2D collision)
{
if (disableExit || isCollected)
return;
//Debug.Log("Player is leaving me.. :(");
string key = gameObject.GetComponent<TextMeshProUGUI>().text;
StartCoroutine(disableTriggersForThisCollectible(0.1f));
List<string> values = textMap[key];
int index = -1;
if (values != null)
index = values.IndexOf("present");
if(index >= 0)
{
values[index] = "absent";
textMap.Remove(key);
textMap.Add(key, values);
gameObject.GetComponent<TextMeshProUGUI>().text = "";
logTextMap();
}
}
IEnumerator disableEntryTrigger(float t)
{
disableEntry = true;
// disable the trigger collider for t seconds
yield return new WaitForSeconds(t);
disableEntry = false;
}
IEnumerator disableExitTrigger(float t)
{
disableExit = true;
// disable the trigger collider for t seconds
yield return new WaitForSeconds(t);
disableExit = false;
}
void logTextMap()
{
string debugString = "";
foreach (KeyValuePair<string, List<string>> kvp in textMap)
{
debugString += "Key === " + kvp.Key + " Values are ==== { " + String.Join(", ", kvp.Value.ToArray()) + " }";
}
Debug.Log(debugString);
}
}
Скрипт обнаруживает столкновения триггеров с BoxCollider2D, прикрепленным к моему плееру, и к нему прикреплено имя тега «Sensor».Я отключаю триггеры на 10 с при возникновении события OnTriggerEnter2D
и на 0,1 с при возникновении события OnTriggerExit2D
.
У меня есть несколько фиксированных текстовых объектов, разбросанных по моему уровню, и пытающихся заполнить текст в них на основе этого сценария выше.Этот скрипт прикреплен к каждому такому текстовому объекту.С помощью этих событий я обнаруживаю, находится ли игрок вблизи текстового объекта.Если игрок найден, то случайный ключ будет заполнен от textMap
при условии, что ключ имеет хотя бы одно значение, которое говорит «отсутствует».Каждый ключ имеет список значений, которые могут быть «отсутствующими», «присутствующими» или «собранными».«отсутствует» означает, что ключ отсутствует в поле зрения камеры и, следовательно, может быть назначен новым объектам коллекционирования текста.«присутствует» означает, что ключ присутствует в текущем виде с камеры и недоступен для других текстовых объектов.«собранный» означает, что ключ уже был собран и недоступен.Например, в приведенном выше примере значения textMap
может быть 4 копии ключа «O2» на карте и 3 копии ключа «O3».Из них 3 "O2" и 2 "O3" уже были собраны.Только 1 копия «O2» может быть назначена вновь запущенным текстовым объектам, и копия «O3» для них недоступна.Сценарий работает в основном так, как ожидалось, за исключением некоторого времени, которое я не могу отладить.Журнал отладки показывает, что одна копия «O3» уже присутствует в представлении, но я пошел на свою сцену и нигде не смог найти «O3».Я боюсь, что это может произойти, потому что все триггерные текстовые объекты (к которым прикреплен вышеуказанный скрипт) пытаются изменить textMap
одновременно.Я потратил впустую много времени, пытаясь понять это, но я просто бьюсь головой о стену.Я был бы очень признателен, если бы кто-то указал мне правильное направление.Моя сцена с этими объектами показана ниже: 
Редактировать: я обнаружил, что проблема DontDestroyOnLoad
.Все упомянутые gameobjest, к которым прикреплен скрипт SensePlayerProximity
, являются потомками DontDestroyOnLoad
gameobject, называемого ScenePersist
.Проблема возникает только тогда, когда я перезагружаю сцену, после смерти игрока.Когда сцена перезагружается, в сцену загружается новый ScenePersist
и непосредственно перед тем, как вызывать метод triggerentry для дочерних элементов перед его уничтожением.Из-за этого OnTriggerEnter2D
вызывается дважды, а не один раз.Как мне решить эту проблему?Один из способов исправить это - держать все эти объекты подальше от точки появления игрока, чтобы триггеры не возникали, но это не очень хороший способ исправить это.Другой способ - запустить сопрограмму enableTriggers
в методе запуска, т.е. отключить триггеры по умолчанию, но это тоже не очень хорошее решение.
void Start () {
disableEntry=true;
disableExit = true;
StartCoroutine(enableTriggers());
}
IEnumerator enableTriggers()
{
yield return new WaitForSeconds(0);
disableEntry = false;
disableExit = false;
}
Вот так выглядит моя иерархия сцен:

Здесь ScenePersist
установлен на DontDestroyOnLoad
, и у него есть много дочерних объектов (выделенных как коллекционные), к которым SensePlayerProximity
прилагается.