c# - 线程化依赖于 C# 中另一个类的函数 (Unity)

标签 c# multithreading unity3d game-engine procedural-generation

我正在尝试构建一个无尽的地形生成器(遵循 Sebastian Lague 的教程:Tutorial Source),他在其中实现了用于生成地形和网格的线程。我更进一步并创建了一个工具来将 Gameobjects 放置在地形(树木,岩石等)上,现在我无法弄清楚我将如何在那里使用线程......我已经尝试了几天,但达到了一个地步我想寻求帮助。希望某种专业人士可以帮助我解决这个问题。

这是注释代码和我为解决我的问题所做的尝试:

public GameObject grasGeneratorPrefab;
public GameObject physicsSimulatorPrefab;
public bool updateGras = false;
private bool allowGrasUpdate = false;

// Check if instance at this point already exists --> if YES, don't instantiate another.
HashSet<Transform> alreadyGeneratedObjectAtThisChunkTransform = new HashSet<Transform>();

Queue<AssetDataInfoThread<AssetData>> assetDataInfoQueue = new Queue<AssetDataInfoThread<AssetData>>();

// Use this for initialization
void Start () 
{
    allowGrasUpdate = false;
    StartCoroutine (WaitForFirstObjectPlacement ());
}

// First time instantiating Gameobjects on terrain
IEnumerator WaitForFirstObjectPlacement()
{
    yield return new WaitForSeconds (3);
    foreach (Transform t in this.transform) 
    {
        PlaceObjectsOnChunks ();
    }
    allowGrasUpdate = true;

}

// I WANT THIS FUNCTION TO BE THREADED --> To prevent freezes during execution
public void PlaceObjectsOnChunks()
{
    foreach (Transform t in this.transform) 
    {
        // If the Transform-object has a collider and the TRansform is yet not in the List...
        if (t.GetComponent<MeshCollider> ().sharedMesh != null && !alreadyGeneratedObjectAtThisChunkTransform.Contains(t)) 
        {
            // ...execute this function
            AssetPlacement.SpawnGrassGeneratorAtChunkPosition (t.transform.position, grasGeneratorPrefab);

            // THE FUNCTION THAT IS PICKED FROM AssetPlacement class is:

  //                public static void SpawnGrassGeneratorAtChunkPosition(Vector3 centre, GameObject grasGeneratorPrefab)
  //                {
  //                    GameObject grasG = Object.Instantiate (grasGeneratorPrefab, new Vector3 (centre.x, 0, centre.z), Quaternion.identity);
  //                }

            AssetPlacement.SpawnPhysicsSimulatorsAtChunkPosition (t.transform.position, physicsSimulatorPrefab);

            // same function as SpawnGrassGeneratorAtChunkPosition with other prefab

            alreadyGeneratedObjectAtThisChunkTransform.Add (t); // Add Transform to the List (to be checked in next iteration)
        }
    }
}

void Update()
{
    if (allowGrasUpdate && AssetPlacement.updateGras)
    {

        PlaceObjectsOnChunks();

        // Triggers the Stop for the Function
        AssetPlacement.StopGrasUpdate ();
    }

    // /// // // // // // // //  // // // 
    //  // TRYING OUT WITH THREADING // //  __> Need help here
    // /// // // // // // // //  // // //


    if(assetDataInfoQueue.Count > 0)
    {
        for (int i = 0; i < assetDataInfoQueue.Count; i++) 
        {
            AssetDataInfoThread<AssetData> threadInfo = assetDataInfoQueue.Dequeue();
            threadInfo.callback (threadInfo.parameter);
            Debug.Log ("Reached crucial threading point");
        }
    }
}



public void RequestAssetToPlaceData(Action<AssetData> callback)
{
    ThreadStart threadStart = delegate {

        AssetDataThread(callback);
    };

    new Thread (threadStart).Start ();
}

void AssetDataThread(Action<AssetData> callback)
{
    AssetData assetData = PlaceObjectsOnChunks();
    lock (assetDataInfoQueue) {
        assetDataInfoQueue.Enqueue (new AssetDataInfoThread<AssetData> (callback, assetData));
    }
}

// DO I NEED THIS STRUCT (?)
public struct AssetData
{
    public  Vector3 centre; // These values are used in AssetPlacement-Script
    public readonly GameObject prefab; // These values are used in AssetPlacement-Script

    public AssetData (Vector3 centre, GameObject prefab)
    {
        this.centre = centre;
        this.prefab = prefab;
    }

}

struct AssetDataInfoThread<T>
{
    public readonly Action<T> callback;
    public readonly T parameter;
    public AssetDataInfoThread (Action<T> callback, T parameter)
    {
        this.callback = callback;
        this.parameter = parameter;
    }
}

最佳答案

当我按照 Sebastian Lague 的教程进行操作时,我发现开始进行地 block 生成真的很棒,但我发现它在扩展其功能时受到限制。这是我对您尝试做的事情的经验。我希望它能为您的项目提供一些见解、帮助、想法或避免。

我的解决方案

我发现我可以在主网格生成之上添加一个新的generation layer 的唯一方法是在我为下一个 block 生成地形时。然后我将启动一个新线程并根据 heightangle 为对象获取 suitable locationslist > 地形。

一旦我在列表中找到合适的位置,我就有一个函数可以随机分配对象来定位这些对象,就像这样:

  • 树木
  • 石头
  • 箱子

线程结束后,我会将对象放置在玩家观看距离 即将位于对象的LOS 中。

Video of the suitable locations script in chunk

这个片段强化了我所说的内容。不幸的是我没有代码了。

这是生成相机所在 map block 时的菜单示例。

Example of generation

Terrain Object Generation

否定:

  • 缺乏完美的物体放置
  • 生成大量对象时,可扩展性可能会出现问题
  • 对象放置缺乏一致性

我打算做的改进:

  • 多线程每个对象层
  • 在以一次性生成性能成本生成 block 时实现合适的位置
  • 在 block 级别实现对象层,这样每次加载时每个 block 看起来都一样

关于c# - 线程化依赖于 C# 中另一个类的函数 (Unity),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48186811/

相关文章:

c# - 如何处理(国家)代码列表中的弃用值

c# - 如何在图像上写XAML控件?

c# - 如何获得实例化泛型的参数类型?

Java线程更新jProgressBar在再次调用线程时不会更新

c - 将数据广播到 n 个具有不同生命周期的线程

.net - 如何在ASP.NET MVC应用程序中的线程上放置代码?

c# - 更改粒子系统 Material Unity 3D脚本

c# - ObjectDisposedException when .Show( )'ing a form that shouldn' t 被处理

c# - Unity - 任意角度之间的夹具旋转

c# - 无法创建静态类的实例 'Random'