One of the challenges of procedural development is that it - TopicsExpress



          

One of the challenges of procedural development is that it requires a lot of number crunching and this is expensive. Number crunching is the antithesis of frame-rate and Unity is architected so that your scripts all run on the main thread. The more you do, the more you impact frame-rate :( You can implement your code as a co-routine, but even this still limits you to running on the main thread in a single core, and this leaves all the power of the other cores on your device idle. Even basic phones these days usually have at least two cores. Here is a simple technique i use to leverage the power of the entire processor to do the number crunching. Not so sure of FB is the best place to share this but will see how it goes. //General structures public delegate void TerrainCompletionTask(); private Queue m_taskCompletionQueue = new Queue(); private object m_taskCompletionQueueLock = new object(); //Passed into the static worker to be executed background thread public class TerrainTask { public enum TerrainTaskCommand { GeneratAll, GenerateHeightMaps, GenerateTextures, GeneratePlants }; public WorldManager m_manager; public string m_taskId; public TerrainTaskCommand m_command; public Dictionary m_parameters; public bool m_isCompleted; public TerrainTask(WorldManager manager, string taskId, TerrainTaskCommand command, Dictionary parameters) { m_manager = manager; m_taskId = taskId; m_command = command; m_parameters = parameters; m_isCompleted = false; } } /// /// Adds a delegate to the task queue for later execution on the foreground thread /// public void ScheduleCompletionTask(TerrainCompletionTask newTask) { lock (m_taskCompletionQueueLock) { if (m_taskCompletionQueue.Count < 100) { m_taskCompletionQueue.Enqueue(newTask); } else { Debug.LogError(Task was not added because queue is full.); } } } /// /// Removes and and executes the delegate on foreground thread /// private int ProcessTaskCompletionQueue() { lock (m_taskCompletionQueueLock) { if (m_taskCompletionQueue.Count > 0) { m_taskCompletionQueue.Dequeue()(); } } return m_taskCompletionQueue.Count; } //Run world update as a BG Task TerrainTask t = new TerrainTask(this, Update world + DateTime.Now.ToShortTimeString(), TerrainTask.TerrainTaskCommand.GeneratAll, new Dictionary()); ThreadPool.QueueUserWorkItem(UpdateWorldBG, t); /// /// Updates the world on a background thread. /// /// Task parameters. private static void UpdateWorldBG(object taskParams) { Debug.Log(UpdateWorldBG); TerrainTask t = taskParams as TerrainTask; //Do background processing t.m_manager.m_world.UpdateWorld(); //Schedule a completion task to run in foreground t.m_manager.ScheduleCompletionTask(new TerrainCompletionTask(delegate { t.m_isCompleted = true; Debug.Log(Threaded update complete); //t.m_manager.ApplyResultsInFGThread(); })); } And then to make sure that the delegate you added to the completion queue is executed on the foreground thread add a call to ProcessCompletionTask() into your Update(). Because Unity disables access to operations on gameobjects, terrain etc from background threads I use the completion tasks to apply the result of the calculation into the game world. I will create and share some simple sample code if there is any interest in the technique. Feedback and comments welcome :)
Posted on: Tue, 25 Nov 2014 21:16:21 +0000

Trending Topics



Recently Viewed Topics




© 2015