我试图基于一些触发器和一些数据在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”标签名称。每当OnTriggerEnter2D
事件发生时,我将禁用触发器10秒钟,而OnTriggerExit2D
事件发生时将禁用0.1s触发器。
我在我的关卡中散布了一些固定的文本对象,并根据上述脚本尝试在其中填充文本。该脚本附加到每个此类文本对象。
借助这些事件,我可以检测播放器是否在文本对象附近。如果找到了玩家,则将从textMap
中填充一个随机密钥,前提是该密钥至少具有一个表示“不存在”的值。每个键都有一个值列表,可以是“不存在”,“存在”或“收集”。 “不存在”表示摄像机视图中不存在该键,因此可以将其分配给新的可收集文本对象。 “存在”表示该键存在于当前摄像机视图中,并且不适用于其他文本对象。 “已收集”表示密钥已被收集,也不可用。例如,在上面显示的textMap
的示例值中,映射中可以有4个键“ O2”的副本和3个键“ O3”的副本。其中,已经收集了3个“ O2”和2个“ O3”。只能将1个“ O2”副本分配给新触发的文本对象,而没有“ O3”副本可用于它们。该脚本的工作原理与预期的一样,除了一些我无法调试的时间。调试日志显示视图中已经存在“ O3”的一个副本,但是我去了我的场景,在任何地方都找不到“ O3”。恐怕可能会发生这种情况,因为所有触发的文本对象(上面的脚本已附加到该对象上)都试图同时修改textMap
。我浪费了很多时间试图解决这个问题,但是我只是在脑海里摸索。如果有人能指出我正确的方向,我将不胜感激。这些对象的场景如下所示:
编辑:我发现问题是DontDestroyOnLoad
。附着了SensePlayerProximity
脚本的所述gameobjest是名为DontDestroyOnLoad
的{{1}}游戏对象的所有子对象。仅当我在玩家死亡时重新加载场景时,才会出现问题。重新加载场景时,新的ScenePersist
将被加载到场景中,并且在它被销毁之前在子对象上调用triggerentry方法之前。因此,ScenePersist
被调用两次,而不是一次。我该如何解决这个问题?
解决此问题的一种方法是使所有这些对象都远离播放器生成点,以免触发发生,但这不是修复它的好方法。另一种方法是在start方法中运行协程OnTriggerEnter2D
,即默认情况下禁用触发器,但这也不是一个好的解决方案。
enableTriggers
这是我的场景层次结构的样子:
此处void Start () {
disableEntry=true;
disableExit = true;
StartCoroutine(enableTriggers());
}
IEnumerator enableTriggers()
{
yield return new WaitForSeconds(0);
disableEntry = false;
disableExit = false;
}
设置为ScenePersist
,并且它具有许多附加了DontDestroyOnLoad
的子子对象(突出显示为可收藏)。
答案 0 :(得分:1)
问题是因为禁用了触发器,所以Enter和Exit方法不是成对调用的。但是没有代码可以保护它。
Enter -> present +1, absent -1 Exit -> present -1, absent +1
如果两次调用Enter方法,但是跳过Exit方法,则现在词典中出现了2个元素,但是场景中只有一个对象(文本为O2 / O3)。
Enter -> present +1, absent -1 Left without trigger Exit Wait 10 seconds Enter -> present +1, absent -1 Exit -> present -1, absent +1
答案 1 :(得分:0)
我通过使用OnDestroy
方法解决了它。在销毁对象之前,该对象正在触发OnTriggerEnter2D
方法。因此,在被销毁后,我做了与OnTriggerExit2D
类似的事情,如下所示。
void OnDestroy()
{
string key = gameObject.GetComponent<TextMeshProUGUI>().text;
Debug.Log("destroed with key "+ key);
if (!textMap.ContainsKey(key))
return;
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 = "";
}
}