12 第1页 | 共2 页下一页
返回列表 发新帖
查看: 3325|回复: 16
打印 上一主题 下一主题

物体合并实现步骤及代码

[复制链接]

3795

主题

2

听众

5万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
53202
精华
32

活跃会员 优秀版主 推广达人 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2011-11-22 09:30:00 |只看该作者 |倒序浏览


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

           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
         
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

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

使用道具 举报

   

671

主题

1

听众

3247

积分

中级设计师

Rank: 5Rank: 5

纳金币
324742
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2012-3-6 23:27:41 |只看该作者
爱咋咋地!
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-4-3 13:13:50 |只看该作者
提醒猪猪,千万不能让你看见
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

5#
发表于 2012-4-8 23:27:33 |只看该作者
发了那么多,我都不知道该用哪个给你回帖了,呵呵
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-4-11 23:23:57 |只看该作者
其实楼主所说的这些,俺支很少用!
回复

使用道具 举报

markq    

511

主题

1

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
15839
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

7#
发表于 2012-4-12 22:48:38 |只看该作者
不错 非常经典 实用
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

8#
发表于 2012-4-26 23:27:57 |只看该作者
百度的叫度娘,网易的叫易娘,新浪内部还在为是叫新娘还是浪娘而争论不休!……不管你们是企鹅的额娘,豆瓣的伴娘,还是华为的伪娘,都要记得,淘宝才是你们的亲娘啊!亲!!
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

9#
发表于 2012-5-30 23:22:59 |只看该作者
不错不错,收藏了
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

10#
发表于 2012-6-12 23:18:57 |只看该作者
呵呵,很好,方便罗。
回复

使用道具 举报

12 第1页 | 共2 页下一页
返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-14 16:26 , Processed in 0.137525 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部