纳金网

标题: 物体合并实现步骤及代码 [打印本页]

作者: 驰骋的风    时间: 2011-11-22 09:30
标题: 物体合并实现步骤及代码


           有用的一个小功能实现方法,可以将两个物体合并为一个物体,当然,也是通过代码来实现的,具体步骤请看下文:
           

           I made a simple (but effective) object pooling system that I want to share. If you're after code, scroll down a bit, because here is where I put in the obligatory "what I understand of the topic" spiel, in my own noobish words:
         

           Let's say that in my game I have a turret which shoots missiles. Each of those missiles is a GameObject, and over the course of a single gameplay session that turret might shoot thousands of missiles, each of which is only 'active' for less than a second before it hits its target and is destroyed. The missiles are small, they don't take up a lot of memory, and we can have hundreds of them on-screen without impacting on performance. Woot.
         

           The act of creating and destroying GameObjects, however, is expensive.
         

           To prevent each of those missiles sitting around in memory forever and taking up unnecessary space, Unity will perform a process called Garbage Collection, where it scans all of the GameObjects in memory and figures out which of those missiles is no longer being used before clearing their allocated memory. Garbage Collection can cause noticeable hickups in the framerate of a game. To make matters worse, Unity decides when to perform a Garbage Collection based on how many GameObjects have been created (or memory allocated). So by rapidly firing hundreds and thousands of missiles from our turret, Unity is going to want to Garbage Collect frequently.
         

           Object-pooling aims to rectify the problem through a couple of simple practices. Firstly, if we can pre-allocate a number of objects before gameplay begins, then we can hide the performance hickup caused by GameObject creation in a loading screen (or mission debriefing, or similar non-active screen). Also, rather than destroying a GameObject when it is no longer needed, we can just turn it off (i.e. make it invisible and move it out of the way somewhere) until we need another one.
         

           A robust object-pooling system should include some control over how many of a particular object should be pre-allocated, and how long they should be kept in the pool for. We might only need 10 to 20 missiles for our turret, as that may be the maximum number of missiles that can be in the air at any one time, so pre-allocating a thousand missiles would make no sense. Similarly, some objects might take up a lot of memory, and those we might prefer to only allocate when needed, but keep around for a while as they may be needed again within a short time frame.
         

           The following object-pooling system I've created is simple. I'm sure there are better, more robust options out there, and ways in which to improve the performance of this one. But it works!
         

           Currently, it allows you to define how many of a particular GameObject should be pre-allocated, the maximum number which should be kept in memory indefinitely, and how often the pool should be checked for GameObjects exceeding that maximum number which should be destroyed. So, using the turret example: We could pre-allocate 20 missiles which are created on level load. The turret will use those 20 missiles, grabbing them from the pool when firing, and returning them to the pool when they hit the target. If suddenly our rate of fire changes and the pool becomes empty, new missiles will be created as needed. Every 'n' seconds, the pool will be checked for excess missiles which are no longer being used and destroy them. This allows me to optimise my game to find a balance between memory use and performance.
         

           To use this system:
         

           1. Create two new prefabs (containing empty GameObjects) called GOPool and PoolObject.
         

           2. Assign the two scripts below to the corresponding prefabs.
         

           3. Drag-and-drop a GOPool to the hierarchy view. This is your pool manager. You can pull an object from the pool using GOPool.Instance.Pop(string nameOfPrefab). You return an object to the pool using GOPool.Instance.Push(GameObject reference).
         

           4. To create a pool of objects, drag-and-drop a PoolObject to the hierarchy view. Assign a Prefab directly from the project view, and define the pre-allocation count, maximum storage, and destroy frequency. Then drag-and-drop the PoolObject onto the GOPool's pool collection in the inspector. Repeat as necessary.
         

           That should do it! There may be errors depending on how you use it. I haven't spent much time making sure it's robust or scenario independent. But hopefully someone can make some use of it. It works perfectly for me!
           

           下面为两段代码:
         

           /// <summary>
         

           /// ? Boon Cotter
         

           /// You are granted non-exclusive license to do whatever
         

           /// you want with this code.
         

           /// </summary>
         

           public class GOPool : MonoBehaviour
         

           {
         

           #region Static
         

           /// <summary>
         

           /// Static GOPool instance.
         

           /// </summary>
         

           public static GOPool Instance;
         

           #endregion
         

           #region Fields
         

           /// <summary>
         

           /// The PoolObject collection.
         

           /// </summary>
         

           public List<oolObject> PoolCollection;
         

           /// <summary>
         

           /// The post-build collection.
         

           /// </summary>
         

           private Dictionary<string, PoolObject> Pool;
         

           #endregion
         

           #region Methods
         

           /// <summary>
         

           /// Local initialization.
         

           /// </summary>
         

           private void Awake()
         

           {
         

           if (Instance != null)
         

           Destroy(this);
         

           Instance = this;
         

           Pool = new Dictionary<string, PoolObject>();
         

           foreach (PoolObject po in PoolCollection)
         

           Pool.Add(po.Prefab.name, po);
         

           // Free memory
         

           PoolCollection = null;
         

           }
         

           /// <summary>
         

           /// Get a GameObject from the Pool. Returns null if the Pool does not contain
         

           /// any GameObjects with the specified name.
         

           /// </summary>
         

           public GameObject Pop(string prefabName)
         

           {
         

           PoolObject po;
         

           if (Pool.TryGetValue(prefabName, out po))
         

           return po.Pop();
         

           else
         

           return null;
         

           }
         

           /// <summary>
         

           /// Return a GameObject to the Pool.
         

           /// </summary>
         

           public void Push(GameObject gameObject)
         

           {
         

           PoolObject po;
         

           if (Pool.TryGetValue(gameObject.name, out po))
         

              po.Push(gameObject);
         

           else
         

              Debug.LogError("Trying to push a game object into the GOPool when no collection exists for the type " + gameObject.name + ".");
         

           }
         

           #endregion
         

           }
           

           第二段代码:
         

           /// <summary>
         

           /// ? Boon Cotter
         

           /// You are granted non-exclusive license to do whatever
         

           /// you want with this code.
         

           /// </summary>
         

           public class PoolObject : MonoBehaviour
         

           {
         

           #region Fields
         

           /// <summary>
         

           /// The Prefab to be pooled.
         

           /// </summary>
         

           public GameObject Prefab;
         

           /// <summary>
         

           /// The number of Prefab instances to pre allocate.
         

           /// </summary>
         

           public int PreAlloc = 10;
         

           /// <summary>
         

           /// The maximum number of Prefab instances to maintain.
         

           /// </summary>
         

           public int MaxStore = 10;
         

           /// <summary>
         

           /// The frequency at which unwanted Prefabs exceeding the maximum are destroyed.
         

           /// </summary>
         

           public float DestroyDelay = 5f;
         

           /// <summary>
         

           /// Stores a collection of recycleable GameObjects.
         

           /// </summary>
         

           private Stack<GameObject> Pool;
         

           #endregion
         

           #region Methods
         

           /// <summary>
         

           /// Global Initialize.
         

           /// </summary>
         

           private void Awake()
         

           {
         

           if (Prefab == null)
         

           Debug.LogError("ERROR: PoolObject can not have a null reference for Prefab.");
         

           Pool = new Stack<GameObject>();
         

           for (int n = 0; n < PreAlloc; n++)
         

           {
         

           GameObject go = Instantiate(Prefab, Vector3.zero, Quaternion.identity) as GameObject;
         

           go.name = Prefab.name;
         

           Disable(go);
         

           Pool.Push(go);
         

           }
         

           InvokeRepeating("oll", DestroyDelay, DestroyDelay);
         

           }
         

           /// <summary>
         

           /// Get a GameObject from the stack, or create a new one if the stack is empty.
         

           /// </summary>
         

           public GameObject Pop()
         

           {
         

           GameObject go;
         

           if (Pool.Count > 0)
         

           {
         

           go = Pool.Pop();
         

           Enable(go);
         

           }
         

           else
         

           {
         

           go = Instantiate(Prefab, Vector3.zero, Quaternion.identity) as GameObject;
         

           go.name = Prefab.name;
         

           }
         

           return go;
         

           }
         

           /// <summary>
         

           /// Return a Unit to the stack.
         

           /// </summary>
         

           public void Push(GameObject gameObject)
         

           {
         

           Pool.Push(gameObject);
         

           Disable(gameObject);
         

           }
         

           /// <summary>
         

           /// Disable the specified GameObject.
         

           /// </summary>
         

           private void Disable(GameObject gameObject)
         

           {
         

           gameObject.GetComponentInChildren<Renderer>().enabled = false;
         

           gameObject.SetActiveRecursively(false);
         

           }
         

           /// <summary>
         

           /// Enable the specified GameObject.
         

           /// </summary>
         

           private void Enable(GameObject gameObject)
         

           {
         

           gameObject.SetActiveRecursively(***e);
         

           gameObject.GetComponentInChildren<Renderer>().enabled = ***e;
         

           }
         

           /// <summary>
         

           /// Poll the PoolObject collection for unecessary GameObjects which can be culled.
         

           /// </summary>
         

           private void Poll()
         

           {
         

           for (int n = 1; n <= Pool.Count - MaxStore; n++)
         

           {
         

           GameObject go = Pool.Pop();
         

           Destroy(go);
         

           }
         

           }
         

           #endregion
         

           }
           

           本文转自:http://blog.booncotter.com/?p=240
         

作者: 晃晃    时间: 2012-1-22 23:28
2011就要离去,生活的碎片拼凑起又一个过去,记得打开心灵的瓶塞,把压力和不快释放出去,把幸福和快乐的种子装进瓶里,愿你2012一切如意!

作者: 奇    时间: 2012-3-6 23:27
爱咋咋地!

作者: C.R.CAN    时间: 2012-4-3 13:13
提醒猪猪,千万不能让你看见

作者: 晃晃    时间: 2012-4-8 23:27
发了那么多,我都不知道该用哪个给你回帖了,呵呵

作者: tc    时间: 2012-4-11 23:23
其实楼主所说的这些,俺支很少用!

作者: markq    时间: 2012-4-12 22:48
不错 非常经典 实用
作者: 菜刀吻电线    时间: 2012-4-26 23:27
百度的叫度娘,网易的叫易娘,新浪内部还在为是叫新娘还是浪娘而争论不休!……不管你们是企鹅的额娘,豆瓣的伴娘,还是华为的伪娘,都要记得,淘宝才是你们的亲娘啊!亲!!

作者: tc    时间: 2012-5-30 23:22
不错不错,收藏了

作者: C.R.CAN    时间: 2012-6-12 23:18
呵呵,很好,方便罗。

作者: C.R.CAN    时间: 2012-8-26 00:01
都闪开,介个帖子,偶来顶

作者: C.R.CAN    时间: 2012-9-5 23:37
很经典,很实用,学习了!

作者: yeu1233    时间: 2012-9-6 09:19
内容很详细,但英文看起来有点吃力,呵
作者: 晃晃    时间: 2012-9-27 23:18
发了那么多,我都不知道该用哪个给你回帖了,呵呵

作者: tc    时间: 2012-11-29 23:24
再看一看,再顶楼主

作者: 菜刀吻电线    时间: 2012-11-29 23:24
很有心,部分已收录自用,谢谢

作者: 奇    时间: 2013-2-12 23:22
已阵亡的 蝶 随 风 舞 说过  偶尔按一下 CTRL A 会发现 世界还有另一面





欢迎光临 纳金网 (http://go.narkii.com/club/) Powered by Discuz! X2.5