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

时间:2018-01-10 11:47:58

标签: 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;
    }
}

1 个答案:

答案 0 :(得分:3)

当我跟随Sebastian Lague的教程时,我发现开始研究陆地生成非常棒,但我发现它在扩展它的功能时受到限制。这是我对你要做的事情的体验。我希望它可能为您的项目提供一些见解,帮助,想法或避免。

我的解决方案

我发现在主网格生成之上添加新generation layer的唯一方法是我为下一个块生成了地形。然后,我会根据地形的listsuitable locations触发一个新线程并获取height angle个对象。

一旦我在列表中有合适的位置,我就有了一个函数,可以将对象随机分配到这些对象的位置,如下所示:

  • 岩石
  • 衣橱
  • 罗茨

线程完成后,我将对象放置为view distance玩家即将进入对象的LOS

Video of the suitable locations script in chunk

这个片段强化了我所谈论的内容。不幸的是,我不再拥有代码了。

这是生成相机所在地图块的菜单示例。

Example of generation

Terrain Object Generation

否定:

  • 缺乏完美的物品摆放
  • 在生成大量对象时可能会出现可伸缩性问题
  • 缺少对象放置的一致性

我要做的改进:

  • 多线程每个对象层
  • 实施suitable locations时,一次性生成块的性能成本
  • 在块级别实施Object Layers,以便每次加载时每个块看起来都相同