You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity异步程序化地形生成:如何保证世代生成顺序执行?

解决Unity世代程序化地形生成的顺序异步执行问题

针对你遇到的「前一世代未完成就启动新世代导致顺序混乱」的问题,核心是要实现异步任务的串行执行——每个新世代的生成任务必须等待前一世代完全结束后才能启动。以下是几种实用的实现方案:

方案一:异步任务链(Task Chaining)

维护一个记录当前/上一世代生成任务的变量,每次新请求生成时,先等待上一个任务完成,再启动新的异步任务。这种方式逻辑简洁,适合单线程触发生成的场景。

using System.Threading.Tasks;
using UnityEngine;

public class TerrainGenerationManager : MonoBehaviour
{
    // 初始化为已完成的任务,确保第一次调用无需等待
    private Task _currentGenerationTask = Task.CompletedTask;

    // 调用此方法触发下一世代生成
    public async Task GenerateNextGeneration(int generationNumber)
    {
        // 等待上一世代的生成任务完成
        await _currentGenerationTask;

        // 将当前世代的生成任务赋值给变量,供下一次调用等待
        _currentGenerationTask = Task.Run(() =>
        {
            // 这里执行耗时的地形生成逻辑(纯计算,避免Unity主线程API)
            GenerateSector(generationNumber);
            // 存储当前世代结果,作为下一世代的输入
            SaveGenerationData(generationNumber);
        });

        // 可选:等待当前世代完成后再返回(调用方可以选择await此方法)
        await _currentGenerationTask;
    }

    private void GenerateSector(int generation)
    {
        // 你的程序化地形生成逻辑(噪声、网格计算等)
        Debug.Log($"正在生成世代 {generation}");
    }

    private void SaveGenerationData(int generation)
    {
        // 存储当前世代数据到内存/磁盘
        Debug.Log($"已保存世代 {generation} 数据");
    }
}

方案二:异步信号量(SemaphoreSlim)

使用信号量控制并发数为1,强制所有生成任务排队执行。这种方式适合多入口触发生成的场景(比如UI按钮、游戏逻辑同时请求生成),能自动处理排队逻辑。

using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

public class TerrainGenerationManager : MonoBehaviour
{
    // 初始信号量计数设为1,同一时间仅允许一个任务执行
    private readonly SemaphoreSlim _generationSemaphore = new SemaphoreSlim(1, 1);

    public async Task GenerateNextGeneration(int generationNumber)
    {
        // 等待获取信号量(自动排队,前一个任务释放后才会执行)
        await _generationSemaphore.WaitAsync();

        try
        {
            // 后台执行耗时生成逻辑
            await Task.Run(() =>
            {
                GenerateSector(generationNumber);
                SaveGenerationData(generationNumber);
            });
        }
        finally
        {
            // 无论是否异常,都释放信号量,避免死锁
            _generationSemaphore.Release();
        }
    }

    // 省略GenerateSector、SaveGenerationData方法(同方案一)
}

方案三:自定义任务队列

维护一个请求队列,启动一个后台循环任务,持续从队列中取出请求并顺序执行。这种方式适合批量提交生成请求的场景,能清晰控制任务的排队与执行顺序。

using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

public class TerrainGenerationManager : MonoBehaviour
{
    private readonly Queue<int> _generationQueue = new Queue<int>();
    private bool _isProcessingQueue = false;

    // 调用此方法将生成请求加入队列
    public void EnqueueGeneration(int generationNumber)
    {
        lock (_generationQueue)
        {
            _generationQueue.Enqueue(generationNumber);
        }

        // 如果当前未在处理队列,启动处理循环
        if (!_isProcessingQueue)
        {
            _ = ProcessGenerationQueueAsync();
        }
    }

    private async Task ProcessGenerationQueueAsync()
    {
        _isProcessingQueue = true;

        try
        {
            while (true)
            {
                int currentGeneration;
                lock (_generationQueue)
                {
                    if (_generationQueue.Count == 0)
                        break;
                    currentGeneration = _generationQueue.Dequeue();
                }

                // 顺序执行生成任务
                await Task.Run(() =>
                {
                    GenerateSector(currentGeneration);
                    SaveGenerationData(currentGeneration);
                });
            }
        }
        finally
        {
            _isProcessingQueue = false;
        }
    }

    // 省略GenerateSector、SaveGenerationData方法(同方案一)
}

Unity专属注意事项

  • 地形生成的纯计算逻辑(比如噪声生成、网格顶点计算)可以放心放在后台线程,但如果涉及Unity的主线程API(比如创建GameObject、修改场景对象),需要在生成完成后切回主线程处理。可以自行实现UnityMainThreadDispatcher,或者通过await Task.Run(...)后在主线程执行后续操作。
  • 若需要支持任务取消,可以在Task.Run时传入CancellationToken,并在生成逻辑中定期检查取消状态,避免无效计算。

内容的提问来源于stack exchange,提问作者arcadeperfect

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:50:37