Unity 2D 粒子模擬系統 — 今日更新總結

郭俊鑫郭俊鑫
2 min read

已思考 2 秒鐘

在本次更新中,我們從架構、效能、物理到 UI,都進行了大規模的優化與功能擴充,包含:

  1. 模組化重構

  2. 效能優化五部曲

  3. 互動式 UI 強化

  4. Collider2D 碰撞檢測

  5. 動態縮放與顏色漸變

  6. 邊界管理

以下依序詳述每個部分。


1. 模組化重構

  • ParticleManager.cs:集中管理粒子與標籤,採用物件池(Pool)技術。

  • GravitationalSystem.cs:只負責萬有引力計算,碰撞行為改由 HandleCollision 處理。

  • ParticleCollisionHandler.cs:掛載於粒子預製體上,透過 OnCollisionEnter2D 把碰撞事件送入 GravitationalSystem

  • EnergyTracker.cs:動能統計與能量柱圖,改用 Coroutine + 物件池更新。

  • LogExporter.cs:粒子狀態與事件日誌輸出,重用 StringBuilder 避免 GC。

  • SimulationController.cs:流程調度、啟動/暫停/重置、定時日誌輸出、FixedUpdate 節流。

  • SimulationUIBindings.cs:開始前、開始後 UI 分頁顯示,加入「暫停時開啟資料夾」按鈕。

  • BoundaryManager.cs:在主攝影機視野自動生成靜態牆,限制粒子不飛出畫面。


2. 效能優化五部曲

  1. 物理運算節流

     // SimulationController.FixedUpdate()
     private int physicsFrameCounter;
     public int physicsFrameThreshold = 2;
     private void FixedUpdate() {
       if (!hasStarted || isPaused) return;
       if (++physicsFrameCounter % physicsFrameThreshold == 0)
         gravitationalSystem.ApplyForces();
     }
    
  2. 全面物件池化

     // ParticleManager.Awake()
     for (int i = 0; i < poolSize; i++) {
       var p = Instantiate(particlePrefab);
       p.SetActive(false);
       particlePool.Enqueue(p);
     }
    
  3. GC 分配優化

     // LogExporter.cs
     private StringBuilder sbScreen = new();
     private StringBuilder sbFile   = new();
     public void LogParticleStates() {
       sbScreen.Clear(); sbFile.Clear();
       // … AppendLine …
       logOutputText.text = sbScreen.ToString();
       File.AppendAllText(path, sbFile.ToString());
     }
    
  4. 尾部交換移除法

     // ParticleManager.RemoveParticle(int idx)
     int last = activeParticles.Count - 1;
     if (idx != last) {
       activeParticles[idx] = activeParticles[last];
       activeLabels  [idx] = activeLabels  [last];
     }
     activeParticles.RemoveAt(last);
     activeLabels  .RemoveAt(last);
    
  5. Coroutine 定時更新

     // EnergyTracker.cs
     private IEnumerator EnergyLoop() {
       while (true) {
         yield return new WaitForSeconds(energyLogInterval);
         LogTotalKineticEnergy();
       }
     }
    

3. 互動式 UI 強化

  • 延遲啟動:按下「開始」前,只顯示兩個輸入框與開始鍵。

  • 開始後:自動切換到完整控制介面(暫停/重置/速度滑桿/圖表/日誌)。

  • 暫停時:顯示「開啟資料夾」按鈕,一鍵打開 Application.persistentDataPath

// SimulationUIBindings.cs 節錄
startButton.onClick.AddListener(OnStartClicked);
pauseButton.onClick .AddListener(OnPauseClicked);
openFolderButton .onClick .AddListener(OpenFolder);

private void OpenFolder() {
  Application.OpenURL("file://" + Application.persistentDataPath);
}

4. Collider2D 碰撞檢測

將粒子預製體加上 CircleCollider2DIsTrigger=false)和以下腳本,即可利用 Unity 物理自動偵測:

// ParticleCollisionHandler.cs
void OnCollisionEnter2D(Collision2D col) {
  // 找到兩者索引 i, j …
  gravSystem.HandleCollision(i, j, rb, otherRb);
}

並在 GravitationalSystem.HandleCollision 中,以「系統總動能」判斷後續行為。


5. 動態縮放與顏色漸變

// ParticleManager.CreateParticle()
float scale = baseParticleScale * Mathf.Pow(mass, 1f/3f);
p.transform.localScale = Vector3.one * scale;

// 顏色漸變 (Gradient)
float t = Mathf.Clamp01(mass / maxMassForGradient);
sr.color = massColorGradient.Evaluate(t);
  • 尺寸 ∝ 質量^(1/3)

  • 顏色 由 Inspector 設定的 Gradient 控制,質量越大顏色越深/越亮


6. 邊界管理

// BoundaryManager.cs
private void CreateBoundaries() {
  float vert = cam.orthographicSize;
  float horz = vert * cam.aspect;
  CreateWall("Top",    new Vector2(0, vert+th/2), new Vector2(horz*2+th*2, th));
  // … Bottom / Left / Right …
}

自動在 Orthographic 相機四周生成 2D 靜態牆,防止粒子飛出畫面。


結語

這一輪更新,從底層演算法到使用者互動都做了全面優化:

  • 流暢度:FPS 增加 2–3 倍,GC 幾乎清零

  • 可擴充:模組化架構,易於添加新功能(如不同分裂策略、特效)

  • 體驗:清爽 UI、明確操作流程、不需手動編輯程式碼即可調參

0
Subscribe to my newsletter

Read articles from 郭俊鑫 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

郭俊鑫
郭俊鑫