我必须做一些基于时间的任务(模拟),例如, 游戏开始时:
但是请记住,如果我想快速查看仿真,则计时器应该具有速度能力。
现在我正在考虑两种方法(也欢迎采用其他方法,这也是问题的原因)
每个对象(火车)脚本管理其时间:
void Start()
{
StartCoroutine("MyEvent");
}
private IEnumerator MyEvent()
{
yield return new WaitForSeconds(120f); // wait two minutes
//Launch Train
}
就像这种脚本会在特定时间后附加到需要操作的每个对象上一样:
问题:
一个“计时器全局”脚本:
function Update ()
{
Timer += Time.deltaTime; //Time.deltaTime will increase the value with 1 every second.
if (timer>= 120){
//launch train, an so one conditions
//Or get timer variable in other script and compare time on update
}
}
现在使用上述脚本,我可以在其他脚本中获取Timer变量,并可以根据更新方法中的时间执行任务。
现在,问题是如何管理它?是第一路,第二路还是第三路(由您)? 因为我也想加快时间,一旦注册,这在协同例程中似乎是不可能的。乡亲们需要您的帮助!
答案 0 :(得分:3)
您可以使用两种方式中的任一种,如果要在示例中更快/更慢地查看Time.timescale,只需按 Space :
public class Example : MonoBehaviour
{
// Toggles the time scale between 1 (normal) and 0.5 (twice as fast)
// whenever the user hits the Space key.
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (Time.timeScale == 1.0f)
{
Time.timeScale = 0.5f;
}
else
{
Time.timeScale = 1.0f;
}
// Also adjust fixed delta time according to timescale
// The fixed delta time will now be 0.02 frames per real-time second
Time.fixedDeltaTime = 0.02f * Time.timeScale;
}
}
}
对于协程,此方法无需更改任何内容,因为WaitForSeconds受Time.timescale
的影响:
实际的暂停时间等于给定时间乘以Time.timeScale。
Time.deltaTime
afaik受Time.timescale
的影响不,因此为了允许更快地重播,您必须这样做
private void Update ()
{
Timer += Time.deltaTime * (1 / Time.timescale);
if (timer >= 120)
{
//launch train, an so one conditions
//Or get timer variable in other script and compare time on update
}
}
一个Update
或多个协程的性能更高,在很大程度上取决于特定的用例。 Afaik直到您可能要运行10.000个协程时才真正注意到(不要在这里给我钉数字;))。
对于仅引发一个或多个事件的情况,最好使用一个Update()
方法而不是调用一个事件或类似的方法。
但是-为什么不仅仅拥有一个协程而不是一个Update
:
public class GlobalTimer : MonoBehaviour
{
public float Delay = 2.0f;
public UnityEvent onTimerDone;
// Unity allows to use Start as IEnumerator instead of a void
private IEnumerator Start()
{
yield return new WaitforSeconds(delay);
onTimerDone.Invoke();
}
}
您只有一个被调用的方法,并且可以向该计时器添加回调,例如
globalTimerReference.onTimerDone.AddListener(() => {
Debug.LogFormat("Timer of {0} seconds is done now.", globalTimerReference.Delay);
});
或通过检查器(例如在UI.Button.onClick
中)。
对于多个事件,我只是想出了一个快速而肮脏的解决方案,因此您可以通过检查器简单地定义多个事件并添加各种回调和内容:
public class GlobalTimer : MonoBehaviour
{
public List<UnityEvent> events;
public List<float> delays;
private void Start()
{
var validPairs = Mathf.Min(events.Count, delays.Count);
for (int i = 0; i < validPairs; i++)
{
StartCoroutine(InvokeDelayed(events[i], delays[i]));
}
}
private IEnumerator InvokeDelayed(UnityEvent unityEvent, float delay)
{
yield return new WaitForSeconds(delay);
unityEvent.Invoke();
}
}
只需确保每个事件在列表中都有延迟。将来,您可能需要编写适当的CustomEditor,以便在检查器中对其进行更精美的编辑。
更新
或者您也可以选择:D
public class ExampleScript : MonoBehaviour
{
[SerializeField] private List<EventDelayPair> EventDelayPairs;
private void Start()
{
foreach (var eventDelayPair in EventDelayPairs)
{
StartCoroutine(InvokeDelayed(eventDelayPair.unityEvent, eventDelayPair.Delay));
}
}
private IEnumerator InvokeDelayed(UnityEvent unityEvent, float delay)
{
yield return new WaitForSeconds(delay);
unityEvent.Invoke();
}
[Serializable]
private class EventDelayPair
{
public UnityEvent unityEvent;
public float Delay;
}
}
[CustomEditor(typeof(ExampleScript))]
public class ExampleInspector : Editor
{
private SerializedProperty EventDelayPairs;
private ReorderableList list;
private ExampleScript _exampleScript;
private void OnEnable()
{
_exampleScript = (ExampleScript)target;
EventDelayPairs = serializedObject.FindProperty("EventDelayPairs");
list = new ReorderableList(serializedObject, EventDelayPairs)
{
draggable = true,
displayAdd = true,
displayRemove = true,
drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "DelayedEvents");
},
drawElementCallback = (rect, index, sel, act) =>
{
var element = EventDelayPairs.GetArrayElementAtIndex(index);
var unityEvent = element.FindPropertyRelative("unityEvent");
var delay = element.FindPropertyRelative("Delay");
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), delay);
rect.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUI.GetPropertyHeight(unityEvent)), unityEvent);
},
elementHeightCallback = index =>
{
var element = EventDelayPairs.GetArrayElementAtIndex(index);
var unityEvent = element.FindPropertyRelative("unityEvent");
var height = EditorGUI.GetPropertyHeight(unityEvent) + EditorGUIUtility.singleLineHeight;
return height;
}
};
}
public override void OnInspectorGUI()
{
DrawScriptField();
serializedObject.Update();
list.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
private void DrawScriptField()
{
// Disable editing
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour(_exampleScript), typeof(ExampleScript), false);
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
}
}
示例
或带有调试延迟预览
public class ExampleScript : MonoBehaviour
{
public List<EventDelayPair> EventDelayPairs;
private void Start()
{
foreach (var eventDelayPair in EventDelayPairs)
{
StartCoroutine(InvokeDelayed(eventDelayPair));
}
}
private IEnumerator InvokeDelayed(EventDelayPair pair)
{
var timer = pair.Delay;
do
{
timer -= Time.deltaTime * (1 / Time.timeScale);
pair.Delay = timer;
yield return null;
} while (timer > 0);
pair.Delay = 0;
pair.unityEvent.Invoke();
}
[Serializable]
public class EventDelayPair
{
public UnityEvent unityEvent;
public float Delay;
}
}
顺便说一句
// Time.deltaTime将每秒增加1。
的格式不正确。相反,它应该是:
Time.deltaTime
将在渲染最后一帧以来经过的时间(以秒为单位)中每帧增加该值。
编辑-减少之后的延迟
从这个问题中我了解到您想speed up
进行整个播放。
从我现在的评论中得知,相反,您想减少以后的延迟。因此,您不能使用Time.timescale
。
为此,您可以使用第二个示例进行一些更改:
[Serializable]
public class EventDelayPair
{
public UnityEvent unityEvent;
public float Delay;
// add a time multiplicator for each delay with default 1
public float TimeMultiplicator = 1.0f;
}
注意:如果要使用它,还必须将其添加到EditorScript中-我将其作为作业;)
private IEnumerator InvokeDelayed(EventDelayPair pair)
{
var timer = pair.Delay;
do
{
timer -= Time.deltaTime * pair.TimeMultiplicator;
pair.Delay = timer;
yield return null;
} while (timer > 0);
pair.Delay = 0;
pair.unityEvent.Invoke();
}
因此您可以在检查器中或通过脚本
exampleScriptReference.EventDelayPairs[0].TimeMultiplicator = 2;
更快地减少延迟。
您可能还想添加一个总体乘法器,例如
// Again you have to add it to the inspector if you use it
public float overallMultiplicator = 1.0f;
//...
timer -= Time.deltaTime * pair.TimeMultiplicator * overallMultiplicator;