天下性能 唯池不破

文章名字是我杜撰的,之前一直在做服务器开发,上周有机会接触了客户端,发现很多资源没有有效管理起来,甚至有资源泄露的发生,我就先针对特效做了pool,结果在一定程度上纠正之前一直很难解决的位置同步问题。

总结上来客户端的资源有:模型、特效、音频、动画等。

音频怎么管理起来呢,http://answers.unity3d.com/questions/482218/best-practices-for-playing-a-lot-of-audio.html这个链接的撸主也提出同样问题:大概是项目有大量音频,如果都是运行时加载,开销太大,怎么解决呢?

这个是下周我的一个私人课题,哈哈,毕竟是业余客户端,首先了解Audio的相关API,如果播放音频,停止播放,暂停,重新播放等,如果在某个地点或者某个对象上播放;基本上控制好这几个操作就可以写一个简单的AudioPool了。

网上也找到一个简单的AudioMgr:

// /////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Audio Manager.
//
// This code is release under the MIT licence. It is provided as-is and without any warranty.
//
// Developed by Daniel Rodríguez (Seth Illgard) in April 2010
// http://www.silentkraken.com
//
// /////////////////////////////////////////////////////////////////////////////////////////////////////////

using UnityEngine;
using System.Collections;

public class AudioManager : MonoBehaviour
{
    public AudioSource Play(AudioClip clip, Transform emitter)
    {
        return Play(clip, emitter, 1f, 1f);
    }

    public AudioSource Play(AudioClip clip, Transform emitter, float volume)
    {
        return Play(clip, emitter, volume, 1f);
    }

    /// <summary>
    /// Plays a sound by creating an empty game object with an AudioSource
    /// and attaching it to the given transform (so it moves with the transform). Destroys it after it finished playing.
    /// </summary>
    /// <param name="clip"></param>
    /// <param name="emitter"></param>
    /// <param name="volume"></param>
    /// <param name="pitch"></param>
    /// <returns></returns>
    public AudioSource Play(AudioClip clip, Transform emitter, float volume, float pitch)
    {
        //Create an empty game object
        GameObject go = new GameObject ("Audio: " +  clip.name);
        go.transform.position = emitter.position;
        go.transform.parent = emitter;

        //Create the source
        AudioSource source = go.AddComponent<AudioSource>();
        source.clip = clip;
        source.volume = volume;
        source.pitch = pitch;
        source.Play ();
        Destroy (go, clip.length);
        return source;
    }

    public AudioSource Play(AudioClip clip, Vector3 point)
    {
        return Play(clip, point, 1f, 1f);
    }

    public AudioSource Play(AudioClip clip, Vector3 point, float volume)
    {
        return Play(clip, point, volume, 1f);
    }

    /// <summary>
    /// Plays a sound at the given point in space by creating an empty game object with an AudioSource
    /// in that place and destroys it after it finished playing.
    /// </summary>
    /// <param name="clip"></param>
    /// <param name="point"></param>
    /// <param name="volume"></param>
    /// <param name="pitch"></param>
    /// <returns></returns>
    public AudioSource Play(AudioClip clip, Vector3 point, float volume, float pitch)
    {
        //Create an empty game object
        GameObject go = new GameObject("Audio: " + clip.name);
        go.transform.position = point;

        //Create the source
        AudioSource source = go.AddComponent<AudioSource>();
        source.clip = clip;
        source.volume = volume;
        source.pitch = pitch;
        source.Play();
        Destroy(go, clip.length);
        return source;
    }
}

就是对AudioClip,正是我需要补的基础知识。

然后这里还有一些Pool的知识 http://forum.unity3d.com/threads/simple-reusable-object-pool-help-limit-your-instantiations.76851/:

其中还有代码,针对特效的管理:

using UnityEngine;
using System.Collections;

public class Effect : MonoBehaviour
{
    /// <summary>
    /// The array of emitters to fire when the effect starts.
    /// </summary>
    public ParticleEmitter[] emitters;

    /// <summary>
    /// The length of the effect in seconds.  After which the effect will be reset and pooled if needed.
    /// </summary>
    public float effectLength = 1f;

    /// <summary>
    /// Should the effect be added to the effects pool after completion.
    /// </summary>
    public bool poolAfterComplete = true;

    /// <summary>
    /// Resets the effect.
    /// </summary>
    public virtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        } else {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// Starts the effect.
    /// </summary>
    public virtual void StartEffect ()
    {
        foreach ( ParticleEmitter emitter in emitters )
        {
            emitter.Emit();
        }

        StartCoroutine(WaitForCompletion());
    }

    public IEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yield return new WaitForSeconds(effectLength);

        //Reset the now completed effect
        ResetEffect();

    }

}

比如同一设置特效长度,启动特效后启动所以离子,并启动一个协程,时间一到就ResetEffect,这时候回放到Pool里。

using UnityEngine;
using System.Collections;

public class SoundEffect : MonoBehaviour
{

    /// <summary>
    /// The sound source that will be played when the effect is started.
    /// </summary>
    public AudioSource soundSource;

    /// <summary>
    /// The sound clips that will randomly be played if there is more than 1.
    /// </summary>
    public AudioClip[] soundClips;

    /// <summary>
    /// The length of the effectin seconds.
    /// </summary>
    public float effectLength = 1f;

    /// <summary>
    /// Should the effect be pooled after its completed.
    /// </summary>
    public bool poolAfterComplete = true;

    /// <summary>
    /// Resets the effect.
    /// </summary>
    public virtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        } else {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// Starts the effect.
    /// </summary>
    public virtual void StartEffect ()
    {
        soundSource.PlayOneShot(soundClips[Random.Range(0,soundClips.Length)]);

        StartCoroutine(WaitForCompletion());
    }

    public IEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yield return new WaitForSeconds(effectLength);

        //Reset the now completed effect
        ResetEffect();

    }

}
 

音频的管理跟特效管理类似,就是播放的API不一样,操作完成后一样进行回收。

那这个池子是怎么写的呢?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObjectPool : MonoBehaviour
{

    public static ObjectPool instance;

    /// <summary>
    /// The object prefabs which the pool can handle.
    /// </summary>
    public GameObject[] objectPrefabs;

    /// <summary>
    /// The pooled objects currently available.
    /// </summary>
    public List<GameObject>[] pooledObjects;

    /// <summary>
    /// The amount of objects of each type to buffer.
    /// </summary>
    public int[] amountToBuffer;

    public int defaultBufferAmount = 3;

    /// <summary>
    /// The container object that we will keep unused pooled objects so we dont clog up the editor with objects.
    /// </summary>
    protected GameObject containerObject;

    void Awake ()
    {
        instance = this;
    }

    // Use this for initialization
    void Start ()
    {
        containerObject = new GameObject("ObjectPool");

        //Loop through the object prefabs and make a new list for each one.
        //We do this because the pool can only support prefabs set to it in the editor,
        //so we can assume the lists of pooled objects are in the same order as object prefabs in the array
        pooledObjects = new List<GameObject>[objectPrefabs.Length];

        int i = 0;
        foreach ( GameObject objectPrefab in objectPrefabs )
        {
            pooledObjects[i] = new List<GameObject>(); 

            int bufferAmount;

            if(i < amountToBuffer.Length) bufferAmount = amountToBuffer[i];
            else
                bufferAmount = defaultBufferAmount;

            for ( int n=0; n<bufferAmount; n++)
            {
                GameObject newObj = Instantiate(objectPrefab) as GameObject;
                newObj.name = objectPrefab.name;
                PoolObject(newObj);
            }

            i++;
        }
    }

    /// <summary>
    /// Gets a new object for the name type provided.  If no object type exists or if onlypooled is true and there is no objects of that type in the pool
    /// then null will be returned.
    /// </summary>
    /// <returns>
    /// The object for type.
    /// </returns>
    /// <param name='objectType'>
    /// Object type.
    /// </param>
    /// <param name='onlyPooled'>
    /// If true, it will only return an object if there is one currently pooled.
    /// </param>
    public GameObject GetObjectForType ( string objectType , bool onlyPooled )
    {
        for(int i=0; i<objectPrefabs.Length; i++)
        {
            GameObject prefab = objectPrefabs[i];
            if(prefab.name == objectType)
            {

                if(pooledObjects[i].Count > 0)
                {
                    GameObject pooledObject = pooledObjects[i][0];
                    pooledObjects[i].RemoveAt(0);
                    pooledObject.transform.parent = null;
                    pooledObject.SetActiveRecursively(true);

                    return pooledObject;

                } else if(!onlyPooled) {
                    return Instantiate(objectPrefabs[i]) as GameObject;
                }

                break;

            }
        }

        //If we have gotten here either there was no object of the specified type or non were left in the pool with onlyPooled set to true
        return null;
    }

    /// <summary>
    /// Pools the object specified.  Will not be pooled if there is no prefab of that type.
    /// </summary>
    /// <param name='obj'>
    /// Object to be pooled.
    /// </param>
    public void PoolObject ( GameObject obj )
    {
        for ( int i=0; i<objectPrefabs.Length; i++)
        {
            if(objectPrefabs[i].name == obj.name)
            {
                obj.SetActiveRecursively(false);
                obj.transform.parent = containerObject.transform;
                pooledObjects[i].Add(obj);
                return;
            }
        }
    }

}
 

其实这个Pool有多重写法,我在项目里的写法就是写成单例类。以资源的文件位置为Key,比如一个特效名字是“hit/release/bloat”就存进去。

这个帖子的启发点是播放一个时间段的特效用协程来完成,比现有项目用一个Mgr管理高效多了。

天下性能 唯池不破,布布扣,bubuko.com

时间: 2024-10-11 14:54:30

天下性能 唯池不破的相关文章

手游推广:天下武功唯快不破

手机游戏的推广一直都是个难题,移动互联网每天都在更新,玩家的思维也在不断的被影响着.手游传统的推广模式变得有些鸡肋,食之无味弃之可惜.在快节奏的工作.学习及生活中,人们可能现在更能接受的就是快速,便捷.正所谓天下武功唯快不破,其实是一个道理,化繁琐为简单,不断追求少而精的思想理念,放弃华而不实的推广方式,让玩家快速的接受游戏或是勾起玩家对游戏的兴趣. 1.减掉对非核心.泛大众用户的考虑 所有的游戏推广,都想影响更多,更大量的用户.但其实最大的问题就是,很难真正影响到这些用户.比如做用户分析的时候

天下武功唯快不破------实验吧

题目地址:http://www.shiyanbar.com/ctf/1854 打开链接 全是英文,能力有限,翻译一下,好像没其他东西了,查看一下源码 让用post请求,丢到burp改一下 看到response有一个FLAG: UDBTVF9USElTX1QwX0NINE5HRV9GTDRHOlhoY1diUTBtbw==,进行base64解密 将解密出的数据提交,好像没用,刷新太快了,去借一下大佬的代码 运行脚本得到flag 原文地址:https://www.cnblogs.com/zhangy

“云中论道”之——华山论剑 ,唯快不破:秘笈分享

"云中论道"技术课堂第二课开讲时间到~ 这次我们邀请到的是来自微软开源技术中心的高级产品经理,人称"蓦然汐来".她将为我们介绍,近一年来微软开源技术中心在Linux上的进一步努力下,运行于Hyper-V之上的Linux的性能有了哪些新的重大提升:在云的论剑中,如何保持快速度.高性能.全新秘笈,马上为大家揭晓! 本文作者介绍: 花名"蓦然汐来",现任微软中国云计算与企业产品工程部开源技术中心高级产品经理,负责微软虚拟化平台 Hyper-v 和公有云

曾经收藏过的好文,唯快不破

我在互联网混了那么多年,有一个"七字诀".我用这一整套方法论自己创办了小米,也帮助朋友创办了20多家公司. 七字诀第一是专注.比如现在像很多微博站每天没有很多更新,但是文章质量好很多,在少就是多的时代里面,我们是信息过多,怎么样把东西做得精致,有价值,才是问题关键. 我们整个时代都在谈苹果,都在谈乔布斯,大家有没有想过其实苹果这家公司到今天为止都只出过5款手机而已.我们深圳的三个厂一天就能出100款,出一款难在什么地方呢?当我自己做手机的时候真的觉得大到至简,越简单的东西越容易传播,越

【转】唯快不破:创业公司如何高效的进行产品研发管理

天下武功无坚不破,唯快不破.在瞬息万变的移动互联网领域,创业公司要想在巨头的夹缝中求生存,仅靠一款出色的产品是不够的,高效敏捷的研发能力才是公司生存与发展的关键.高效的研发模式包括如何确定开发项目,如何把控项目进度,如何驱动产品一代代完善以及如何调动员工的积极性等.通过对豌豆荚的访谈,让我们来看看这家被称为中国最具硅谷范的移动互联网公司在做产品研发的过程中是如何进行高效管理的. 一.高效研发的5个关键步骤 第一步:立项——定方向 在豌豆荚的整个研发过程中,立项称为Product Brief或者P

【Linux探索之旅】第三部分第五课:延时执行,唯慢不破

内容简介 1.第三部分第五课:延时执行,唯慢不破 2.第三部分测验题 延时执行,唯慢不破 上一课(<[Linux探索之旅]第三部分第四课:后台运行及合并多个终端>)中,我们学习了后台进程以及如何在一个终端里打开多个虚拟终端. 到目前为止,我们所运行的命令都是立即执行,也就是我们按下回车键的那一刻,命令就开始执行了. 其实Linux中命令还可以延时执行.这一课我们就来学习几个命令,可以帮助我们<稍后>执行程序.比如我们即将学习到的crontab命令. 所有这一课新学的命令都涉及到时间

实验吧--web--天下武功唯快不破

---恢复内容开始--- 英文翻译过来嘛,就是:天下武功无快不破嘛.(出题者还是挺切题的) 看看前端源码: 注意这里 please post what you find with parameter:key 请提交你的参数key 这里我们回头看看这个题目提示说,,让我看看响应头.(ps.天枢战队才是亮点...) 那咱们就抓个包看看呗: 哦我们这里看见了这个头文件!!!!! FLAG: UDBTVF9USElTX1QwX0NINE5HRV9GTDRHOmhBbnlpRHU1dA== base64无

[Java Performance] 线程及同步的性能 - 线程池/ThreadPoolExecutors/ForkJoinPool

线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自客户端的请求.Java中对于线程池的支持,来自ThreadPoolExecutor.一些应用服务器也确实是使用的ThreadPoolExecutor来实现线程池. 对于线程池的性能调优,最重要的参数就是线程池的大小. 对于任何线程池而言,它们的工作方式几乎都是相同的: 任务被投放到一个队列中(队列的

Java并发编程:线程及同步的性能——线程池

线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自客户端的请求.Java中对于线程池的支持,来自ThreadPoolExecutor.一些应用服务器也确实是使用的ThreadPoolExecutor来实现线程池. 对于线程池的性能调优,最重要的参数就是线程池的大小. 对于任何线程池而言,它们的工作方式几乎都是相同的: 任务被投放到一个队列中(队列的