Unity(角色移動和當前游戲場景中的所有內容)在從 Web url 下載紋理時停止。我正在使用Socket.IO
在線多人游戲。
- 使用 socket.emit 請求“地圖資訊”
void Start()
- 獲取“地圖資訊”并創建地圖物體
Instantiate()
- 從 url 獲取組態檔影像(紋理)并更改地圖物體的紋理
IEnumerator DownloadImage(string MediaUrl, SpriteRenderer spr) {
// check if url is malformed
if (MediaUrl == null || MediaUrl.Contains("Null")) {
yield break;
}
UnityWebRequest request = UnityWebRequestTexture.GetTexture(MediaUrl);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.DataProcessingError || request.result == UnityWebRequest.Result.ProtocolError)
Debug.Log(request.error);
else {
Texture2D tex = ((DownloadHandlerTexture)request.downloadHandler).texture;
spr.sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), tex.width / 2f);
}
}
有沒有辦法在下載紋理時通過用戶互動(角色移動或按鈕操作)保持游戲運行?
uj5u.com熱心網友回復:
Unity 協同例程 (CR) 是一種入門級形式,有時是在Unity 主執行緒上的一系列幀上執行作業的危險形式。它們對于lerp
跨越一系列幀本質上是合乎邏輯的內容很有用,例如褪色、5 秒后爆炸我的宇宙飛船或推遲駕駛艙顯示更新。
CR 在主執行緒上被分割和多路復用,因此游戲中最慢的部分將是單幀中對時間需求最大的 CR。在每幀中執行任何冗長的yield
操作都會減慢您的游戲速度,尤其是I/O 操作。
替代方案 - Unity 作業
相反,考慮使用 Unity 'IJob',它允許在作業執行緒上執行操作,從而釋放 Unity 執行緒來做它最擅長的事情,而不是冗長的 I/O 操作。
統一:
使用 IJob 調度與其他作業和主執行緒并行運行的單個作業。調度作業時,會在作業執行緒上呼叫作業的 Execute 方法。更多的...
現在浪費一個可能會花費一生等待 I/O 完成的執行緒可以說是浪費了一個非常好的執行緒,但它肯定比阻塞主執行緒更好。
協程... thar be dragons
所以之前我提到了關于 CR 的“危險”,原因有三個:
- 當以每秒呼叫多次的方法啟動 CR 時,例如
Update()
確保充分保護else 時,最終可能會導致StartCoroutine()
數以萬計的它們運行但記憶體不足。這個在 Stack Overflow 上很常見 - 不要誤以為它們是作業執行緒或其他不會減慢主執行緒速度的魔法
- 在許多方面,CR 就像
DoEvents
分別Application.DoEvents
在Visual Basic和.NET中一樣,并且都導致了令人討厭的重新進入情況(其中狀態被破壞且不可預測,就像在多執行緒應用程式中一樣,但沒有執行緒)
還有一個整體是 Unity 促進了一個奇怪的使用IEnumerator
and yield
?辯論。
我的另一個提示是,如果您需要一些 lerped 或延遲的東西并且沒有進行 I/O,請考慮只創建一個類并使用Time
.
例如,在我的飛行模擬中,我只想每 100 毫秒左右更新一次駕駛艙顯示。為此,我定義了一個Delay
類:
public class Delay
{
private float _lastInterval;
/// <summary>
/// The timeout in seconds
/// </summary>
/// <param name="timeout"></param>
private Delay(float timeout)
{
Timeout = timeout;
_lastInterval = Time.time;
}
public float Timeout { get; }
public bool IsTimedOut => Time.time> _lastInterval Timeout;
public void Reset()
{
_lastInterval = Time.time;
}
public static Delay StartNew(float delayInSeconds)
{
return new Delay(delayInSeconds);
}
}
.
.
.
private void Update()
{
if (!_delay.IsTimedOut)
{
return;
}
// Do something time consuming
_delay.Reset();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/485844.html