c# - Unity:附加到 DontDestroyOnLoad 对象的子对象的脚本被调用两次
问题描述
我正在尝试根据一些触发器和一些数据填充 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 发生的触发碰撞,并且附加了“传感器”标签名称。每当事件发生时我禁用触发器 10 秒,每当OnTriggerEnter2D
事件发生时禁用触发器 0.1 秒OnTriggerExit2D
。
我有一些固定的文本对象分散在我的关卡中,并试图根据上面的这个脚本填充其中的文本。此脚本附加到每个此类文本对象。在这些事件的帮助下,我检测玩家是否在文本对象附近。如果找到了玩家,那么将填充一个随机密钥,textMap
前提是该密钥具有至少一个“不存在”的值。每个键都有一个值列表,可以是“不存在”、“存在”或“已收集”。“缺席”意味着该键不在相机视图中,因此可以分配给新的可收藏文本对象。“present”表示该键存在于当前相机视图中,并且不可用于其他文本对象。“集” 表示密钥已被收集,也不可用。在示例值中textMap
例如,我在上面显示的地图中可以有 4 个键“O2”的副本,以及 3 个键“O3”的副本。其中,已经收集了 3 个“O2”和 2 个“O3”。只能将 1 个“O2”副本分配给新触发的文本对象,并且没有“O3”副本可供它们使用。该脚本主要按预期工作,但有几次我无法调试。调试日志显示视图中已经存在“O3”的一份副本,但我去了我的场景,在任何地方都找不到“O3”。我担心这可能会发生,因为所有触发的文本对象(上面的脚本所附加的)都试图修改textMap
同时。我浪费了很多时间试图弄清楚这一点,但我只是把头撞在墙上。如果有人能指出我正确的方向,我将不胜感激。我的带有这些对象的场景如下所示:
编辑:我发现问题是DontDestroyOnLoad
. SensePlayerProximity
附加脚本的上述游戏对象都是DontDestroyOnLoad
名为的游戏对象的子对象ScenePersist
。只有当我重新加载场景时,玩家死亡时才会出现问题。当场景重新加载时,newScenePersist
被加载到场景中,并且在它被销毁之前调用 children 的 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
解决方案
问题是因为您禁用了触发器,Enter 和 Exit 方法没有成对调用。但是没有代码可以保护它。
输入 -> 存在 +1,不存在 -1 退出 -> 在场 -1,不在场 +1
如果方法 Enter 被调用两次,但方法 Exit 被跳过,现在字典中的 2 个元素出现,但场景中只有一个对象(带有文本 O2/O3)。
输入 -> 存在 +1,不存在 -1 离开没有触发退出 等待 10 秒 输入 -> 存在 +1,不存在 -1 退出 -> 在场 -1,不在场 +1
推荐阅读
- c# - C# 字符串转字节数组(带预设字符串格式)
- filter - 在 Tableau 上隐藏整个筛选器
- r - 离散随机变量的“一个接一个”实现
- python - ResolvePackageNotFound 错误:创建 Conda 环境时
- java - Android 错误:无法找到明确的活动类
- c - 具有可变长度的字符串的数组问题(可能未初始化可变大小的对象)
- three.js - 如何在反应三纤维中渲染另一个物体的发射材料的反射?
- image - 为什么我的所有图像都显示为问号?
- javascript - HTML/JS - 在页面加载时播放音频文件
- wordpress - Wordpress 登录重定向循环