2017-11-09 8 views
-1

私はスクリーンショットをとり、ファイルシステムに保存するコルーチンを持っています。しかし、コルーチンが実行されると、ゲームは一時的にフリーズし、event onFinishedScreenShotは時期尚早に発火します。コルーチンがメインスレッドをブロックしています

私は、コルーチンは、「バックグラウンドスレッド上で」あったと思いました。

私のコードが終了すると、メインスレッドをブロックせずにスクリーンショットを保存し、event onFinishedScreenShot火書き込みファイルAFTER を持って調整する方法はありますか?またはゲーム用のスクリーンショットを保存するより良い方法がありますか?あなたは、スクリプト内の循環参照を持っているので

MySingleton.cs

public event Action<string> onFinishedScreenShot; 

public IEnumerator TakeScreenshot(string filename) { 

    Texture2D areaImage = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); 

    yield return new WaitForEndOfFrame(); 

    areaImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0, false); 
    areaImage.Apply(); 

    byte[] bytes = areaImage.EncodeToPNG(); 
    File.WriteAllBytes(filename, bytes); 

    if (onFinishedScreenShot != null) { 
     onFinishedScreenShot(filename); 
    } 
} 

AnotherClass.cs

private void Start() { 
    LoadTexture(someFileName); 
} 


public void SomeMethodInAnotherClass() { 
     StartCoroutine(MySingleton.TakeScreenshot(someFileName)); 
} 


public void LoadTexture(string filename) { 

    if (!filename.Equals("NOT SET")) { 

     byte[] bytes = File.ReadAllBytes(GetSaveFilename(filename)); 

     Texture2D texture = new Texture2D(500, 500, TextureFormat.DXT5, false); 
     texture.filterMode = FilterMode.Trilinear; 
     texture.LoadImage(bytes); 

     RectTransform rt = locationSnapShot.rectTransform; 

     Sprite sprite = Sprite.Create(texture, new Rect(0, 0, rt.rect.width, rt.rect.height), new Vector2(0.5f, 0.0f), 16.0f); 
     locationSnapShot.sprite = sprite; 

     Debug.Log("Removing event listener."); 
     MySingleton.onFinishedScreenShot -= LoadTexture; 
    } else { 
     Debug.Log("No screen shot. Listening for a change."); 
     MySingleton.onFinishedScreenShot += LoadTexture; 
    } 
} 

答えて

2

ユニティコルーチンと「スレッド」は、2つの全く異なる機能です。 Coroutinesはコードが実行されてもスレッドとは何も関係がないときにを管理する方法です。このように二つの考え:

コルーチン:"DO X、Y行われるのを待ち、その後、Z.を行います"

スレッド:"XとYを同時に実行してからZを実行する"

自分のスレッドを開こうとするなら、C#はSystem.Threadingでそれを行うことができますが、注意する必要があります。 Unity APIのほぼ100%(UnityEngine名前空間から来るもの)は、がメインスレッド上で実行されていない場合にアサートされます()。あなたは、ファイルを書き込み、新しいスレッドを開いて、あなたの生のバイトのデータを取得する必要があります:イベントの発火についてあなたの最後の質問については

... 
byte[] bytes = areaImage.EncodeToPNG(); 

// Start a new thread here 
File.WriteAllBytes(filename, bytes); 

if (onFinishedScreenShot != null) { 
    onFinishedScreenShot(filename); 
} 

File.WriteAllBytesは同期呼び出しであるので、あなたのイベントには絶対にを解雇されていますの後にファイルが書き込まれます(質問に記載されていない他の場所からそのイベントを発生させない限り)。

+1

もう一度、あなたは私を理解して助けました!ありがとうございました! @Foggzie –

+0

@ user-44651いつもお世話になります。 – Foggzie

0

は、多分それはです。

MySingleton.onFinishedScreenShot += LoadTexture; 

ハンドラ関数にハンドラを登録しています。 Start() - 関数でこれを試してください。 これで問題が解決する可能性があります。

0

これはコルーチンとは何の関係もありません。他のスレッドのFile.WriteAllBytes関数をThreadPool.QueueUserWorkItemと呼びます。まず、それが簡単に別のThreadからメインThread上の関数を呼び出すことが可能thisポストからUnityThreadクラスを取得します。あなたのコードは次のようになっています。

public event Action<string> onFinishedScreenShot; 

//Data to pass to the Thread function 
public class SaveData 
{ 
    public string fileName; 
    public byte[] imgByteArray; 
} 

void Awake() 
{ 
    //Enable the Thread callback API 
    UnityThread.initUnityThread(); 
} 

public IEnumerator TakeScreenshot(string filename) 
{ 

    Texture2D areaImage = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); 

    yield return new WaitForEndOfFrame(); 

    areaImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0, false); 
    areaImage.Apply(); 

    SaveData saveData = new SaveData(); 
    saveData.fileName = filename; 
    saveData.imgByteArray = areaImage.EncodeToPNG(); 

    //Save on a new Thread 
    WriteAllBytes(saveData); 
} 

void WriteAllBytes(SaveData saveData) 
{ 
    ThreadPool.QueueUserWorkItem(new WaitCallback(saveFile)); 
} 

private void saveFile(object state) 
{ 
    SaveData saveData = (SaveData)state; 
    File.WriteAllBytes(saveData.fileName, saveData.imgByteArray); 

    //Invoke the event on the MainThread 
    UnityThread.executeInUpdate(() => 
    { 
     if (onFinishedScreenShot != null) 
     { 
      onFinishedScreenShot(filename); 
     } 
    }); 
} 
関連する問題