[英]Coroutine causes crash in unity
我在我的腳本中添加了以下 function 並導致統一崩潰。
public void AddCurrentFrameToVideo()
{
_addFrameFunctionHasBeenCalled = true;
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
IEnumerator SetFrame()
{
yield return new WaitForSeconds(0.3f);
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
if (recordingButtonHasBeenPressed)
{
yield return StartCoroutine(SetFrame());
}
else
{
yield return null;
yield break;
}
}
IEnumerator mycoroutine;
mycoroutine = SetFrame();
if (recordingButtonHasBeenPressed)
{
StartCoroutine(mycoroutine);
}
else
{
StopCoroutine(mycoroutine);
}
}
}
我在更新 function 的 if 語句中將此稱為 function。 看:
void Update()
{
_currentsframe = Time.frameCount;
if (recordingButtonHasBeenPressed)
{
if (!videoBasicFileHasBeenCreated)
{
CreateVideoBasicFile();
}
if (!_addFrameFunctionHasBeenCalled)
{
AddCurrentFrameToVideo();
}
}
}
我還通過按鈕OnClick()
在另一個腳本中控制了recordingButtonHasBeenPressed
變量。 看:
public void RecordVideo_OnClick()
{
if (videoIsRecording)
{
videoIsRecording = false;
videoRecordButton.image.sprite = videoButtonIsNotRecordingSprite;
_myRecorderSc.recordingButtonHasBeenPressed = false;
_myRecorderSc.videoBasicFileHasBeenCreated = false;
}
else
{
videoRecordButton.image.sprite = videoButtonIsRecordingSprite;
_myRecorderSc.recordingButtonHasBeenPressed = true;
_myRecorderSc.videoBasicFileHasBeenCreated = false;
videoIsRecording = true;
}
}
我不知道為什么它會破壞團結。 我不認為這是一個無限循環。 我還測試了DO-While
循環而不是使用Croutine
。 看:
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
do
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
} while (recordingButtonHasBeenPressed);
}
它也會導致團結崩潰。
我應該怎么辦? 它出什么問題了?
這個
IEnumerator SetFrame()
{
yield return new WaitForSeconds(0.3f);
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
if (recordingButtonHasBeenPressed)
{
yield return StartCoroutine(SetFrame());
}
}
是一個遞歸調用,您在其中yield return
相同的例程(內部yield return
相同的例程等)所以它會等到所有嵌套的子例程都完成 => 所以在某些時候你會得到一個 StackOverflow!
這絕對是一個封閉的永無止境的while循環
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
do
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
} while (recordingButtonHasBeenPressed);
}
在循環中, recordingButtonHasBeenPressed
的值永遠不會改變,Unity/您的應用程序會立即永遠凍結!
你想要做的是一個協程,比如
IEnumerator SetFrame()
{
// initially wait once
yield return new WaitForSeconds(0.3f);
// simply continue to execute the routine until the record shall be stopped
while(recordingButtonHasBeenPressed)
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
// yield the next frames for 0.3 seconds before checking
// recordingButtonHasBeenPressed again
yield return new WaitForSeconds(0.3f);
}
}
然后,您甚至不需要主動阻止它。 您需要做的就是啟動它,然后為了中斷它只需將recordingButtonHasBeenPressed
設置為false
。
做它事件驅動
現在,通常不要使用Update
和多個 controller 標志bool
s,一旦在此處調用方法,您似乎會立即再次重置,我寧願在調用按鈕時驅動整個代碼事件並調用一次。 這將防止意外運行並發例程,並使整個事情更好地閱讀和維護。
我不知道你的完整代碼,但它可能看起來像
public void RecordVideo_OnClick()
{
// invert the toggle flag
videoIsRecording = !videoIsRecording;
// depending on the new flag value chose the sprite
videoRecordButton.image.sprite = videoIsRecording ? videoButtonIsRecordingSprite : videoButtonIsNotRecordingSprite;
if (!videoIsRecording)
{
_myRecorderSc.StopRecording();
}
else
{
_myRecorderSc.StartRecoring();
}
}
然后在記錄器腳本中你只需要
public void StartRecording()
{
if(!recording)
{
StartCoroutine(RecorderRoutine);
}
}
public void StopRecording()
{
recording = false;
}
// flag to interrupt running record
private bool recording;
private IEnumerator RecorderRoutine()
{
// Just in case prevent concurrent routines
if(recording) yield break;
recording = true;
// initialize your file
CreateVideoBasicFile();
// initially wait once
yield return new WaitForSeconds(0.3f);
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
// simply continue to execute the routine until the record shall be stopped
while(recording)
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
// yield the next frames for 0.3 seconds before checking
// recordingButtonHasBeenPressed again
yield return new WaitForSeconds(0.3f);
}
}
recording = false;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.