游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2076|回复: 4

小弟精心打造的一个对象缓冲器,可支持任何类型的对象

[复制链接]

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
发表于 2009-3-3 09:18:00 | 显示全部楼层 |阅读模式

设计思路:

  以页面为单位预先分配一定数量的对象给客户程序使用,用完再归还回来。
  
  采用页面链表技术,理论上分配数量无上限。
  
  页面中的对象用堆管理,请求时从堆顶移出一个给它使用,归还时放回堆顶。
  
  当页面用完时分配新页面在页面链表的未尾。
  
  需要客户程序额外记录一个页面索引值,归还时对号入坐。
  
  跟踪空闲对象数量,归还时判断空闲对象数量是否大于等于预定值(这里取2个页面数量值),
超过的话释放空闲页面,直至空闲对象数量小于等于预定值(这里取1个页面数量值)。
  
  每页面对象数量可通过带参数的构造函数设置,低于16时取16(如果低于16还不如用数组),
但具体取多少应根据实际情况而定,如果对象较小(低于128字节),此数值可以取大一点,如取
1024的话,一个页面也只占用128K的内存,对于现在的PC机来说微不足道。还有对象需要的数量变
动较大较频繁的话此值也应取大一点,过小的话分配和释放页面过多会降低程序运行速度。我推荐
的取值是估算你需要的最大量(这时对象请求归还操作在一个页面里,最佳情况),再计算目标平台内
存容量的1%(毕竟这不是程序的全部,还有其它模块也需要占用内存),权衡利弊取小值。


用法很简单:

        ObjectBuffer<int> ob;        //定义整型ObjectBuffer对象,无参构造,每页面对象数量取16
        int* p[48];                //客户程序装对象的数组
        unsigned long page[48];        //客户程序记录页面索引的数组
        for( int i = 0; i < 48; i++ )
        {
                p = NULL;
                page = 0;
                ob.RequestObject( &p, page );        //请求对象
                *p = 0;                        //请求来的对象是对象指针
        }
        for( i = 0; i < 32; i++ )
        {
                ob.ReturnObject( &p, page );        //归还对象
        }


作者心声:


    有用得着的话就拿去,但有一点就是请大家不要只看不说,大家多多提意见,比如发现什么错误啊,或者是
什么地方需要改进啊,或者是有更好的思路啊,大家一起分享哈嘛。我把它公布出来也是让大家一起分享嘛,所以请大家不
要只看不说,更或是用了也不说话。好了,不多说了,最后欢迎大家灌水,拍砖吧![em13][em13][em13][em13]

/*************ObjectBuffer1.0****************/
//对象缓冲器类模版,缓冲器预先分配一定数量的对象,当用到时就从缓冲器
//请求,不用时归还缓冲器,采用页链表分配技术使缓冲器理论上无分配上限
//
        const unsigned long ObjectOfPageMin = 16;                //每页中对象数量的最低值16
                                                                                                        //低于此值时缓冲器将失去意义
        template <class T>        
        class ObjectBuffer
        {
        public:
                ObjectBuffer();
                //ulObjectPage,每页上对象的数量,此值应根据对象大小、使用
                //情况统筹选取,以降低内存浪费。当小于16时取值16。
                ObjectBuffer( unsigned long ulObjectOfPage );
                ~ObjectBuffer();

                //当要用一个对象时,就用RequestObject请求
                bool RequestObject( T** pObjectPointer, unsigned long& ulPage );
                //当不用对象时调用ReturnObject归还
                bool ReturnObject( T** pObjectPointer, unsigned long& ulPage );
                //pObjectPointer参数为指向对象指针的指针 ulPage参数为对象所在的页
                //注意:当归还对象后,*pObjectPointer == NULL、ulPage == 0
               
        private:
                struct SPage
                {
                        T*                                m_pObjects;//对象数组
                        T**                                m_ppObjectStack;//对象堆,堆中存储的是对象指针
                        unsigned long        m_ulTop;                        //堆顶,当为0时说明对象已用完
                        unsigned long        m_ulObjectCount;        //对象数量
                        SPage*                        m_pFront;                        //前一页
                        SPage*                        m_pBack;                        //后一页
                       
                        SPage()
                        {
                                m_pObjects                = NULL;        //对象数组
                                m_ppObjectStack = NULL;        //对象堆,堆中存储的是对象指针
                                m_ulTop                        = 0;        //堆顶,当为0时说明对象已用完
                                m_pFront                = NULL;        //前一页
                                m_pBack                        = NULL;        //后一页
                                m_ulObjectCount = 0;        //对象数量
                                unsigned long ulObjectOfPage = ObjectOfPageMin;
                                m_pObjects = new T[ ulObjectOfPage ];
                                m_ppObjectStack = new T*[ ulObjectOfPage ];
                                if( NULL == m_pObjects || NULL == m_ppObjectStack )return;
                                for( int i = 0; i < ulObjectOfPage; i++ )
                             m_ppObjectStack = &m_pObjects;
                                m_ulTop = ulObjectOfPage;
                                m_ulObjectCount = ulObjectOfPage;        //对象数量
                        }
                        SPage( unsigned long ulObjectOfPage )
                        {
                                m_pObjects                = NULL;        //对象数组
                                m_ppObjectStack = NULL;        //对象堆,堆中存储的是对象指针
                                m_ulTop                        = 0;        //堆顶,当为0时说明对象已用完
                                m_pFront                = NULL;        //前一页
                                m_pBack                        = NULL;        //后一页
                                m_ulObjectCount = 0;        //对象数量
                                if( ulObjectOfPage < ObjectOfPageMin )ulObjectOfPage = ObjectOfPageMin;
                                m_pObjects = new T[ ulObjectOfPage ];
                                m_ppObjectStack = new T*[ ulObjectOfPage ];
                                if( NULL == m_pObjects || NULL == m_ppObjectStack )return;
                                for( int i = 0; i < ulObjectOfPage; i++ )
                               m_ppObjectStack = &m_pObjects;
                                m_ulTop = ulObjectOfPage;
                                m_ulObjectCount = ulObjectOfPage;        //对象数量
                        }
                        ~SPage(){ Release(); }
                        void Release()
                        {
                                if( NULL != m_pObjects )delete[] m_pObjects;
                                if( NULL != m_ppObjectStack )delete[] m_ppObjectStack;
                                m_pObjects                = NULL;        //对象数组
                                m_ppObjectStack = NULL;        //对象堆,堆中存储的是对象指针
                                m_ulObjectCount = 0;        //对象数量
                                m_ulTop                        = 0;        //堆顶,当为0时说明对象已用完
                                m_pFront                = NULL;        //前一页
                                m_pBack                        = NULL;        //后一页
                        }
                        bool IsEmpty()
                        {
                                return 0 == m_ulTop;
                        }
                        bool IsFull()
                        {
                                return m_ulTop == m_ulObjectCount;
                        }
                        void SetBack( SPage* pBack ){ m_pBack = pBack; }
                        void SetFront( SPage* pFront ){ m_pFront = pFront; }
                        T* RequestObject()
                        {
                                if( IsEmpty() )return NULL;
                                m_ulTop--;
                                return m_ppObjectStack[ m_ulTop ];
                        }
                        bool ReturnObject( T* pObject )
                        {
                                if( m_ulTop == m_ulObjectCount )return false;
                                //检查对象是否重复归还
                                for( unsigned long i = 0; i < m_ulTop; i++ )
                                {
                                        if( m_ppObjectStack[ i ] == pObject )return false;
                                }
                                m_ppObjectStack[ m_ulTop ] = pObject;
                                m_ulTop++;
                                return true;
                        }
                };

                SPage*                        m_pBeginPage;                        //页链表开始页
                SPage*                        m_pEndPage;                        //页链表结束页
                SPage*                        m_pCurrentPage;                        //当前操作页
                unsigned long        m_ulCurrentPageNumber;        //当前页编号
                unsigned long        m_ulPageCount;                //页数量
                unsigned long        m_ulObjectOfPage;                //每页中对象的数量
                unsigned long        m_ulIdleObjectCount;        //空闲对象数量
        };

        template <class T>
        ObjectBuffer<T>::ObjectBuffer()
        {
                m_pBeginPage        = NULL;                //页链表开始页
                m_pCurrentPage        = NULL;                //当前操作页
                m_pEndPage                = NULL;        //页链表结束页
                m_ulPageCount        = 0;                //页数量
                m_ulCurrentPageNumber = 0;        //当前页编号
                m_ulIdleObjectCount = 0;        //空闲对象数量
               
                m_ulObjectOfPage = ObjectOfPageMin;
                m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
                if( NULL == m_pBeginPage )return;
                m_ulPageCount = 1;
                m_ulCurrentPageNumber = 1;        //当前页编号
                m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
        }
        template <class T>
        ObjectBuffer<T>::ObjectBuffer( unsigned long ulObjectOfPage )
        {
                m_pBeginPage        = NULL;                //页链表开始页
                m_pCurrentPage        = NULL;                //当前操作页
                m_pEndPage                = NULL;        //页链表结束页
                m_ulPageCount        = 0;                //页数量
                m_ulCurrentPageNumber = 0;        //当前页编号
                m_ulIdleObjectCount = 0;        //空闲对象数量

                m_ulObjectOfPage = ulObjectOfPage;
                if( m_ulObjectOfPage < ObjectOfPageMin )m_ulObjectOfPage = ObjectOfPageMin;
                m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
                if( NULL == m_pBeginPage )return;
                m_ulPageCount = 1;
                m_ulCurrentPageNumber = 1;        //当前页编号
                m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
        }
        template <class T>
        ObjectBuffer<T>::~ObjectBuffer()
        {
                while( NULL != m_pBeginPage )
                {
                        m_pCurrentPage = m_pBeginPage;
                        m_pBeginPage = m_pBeginPage->m_pBack;
                        m_pCurrentPage->Release();
                        delete m_pCurrentPage;                       
                }

                m_pBeginPage        = NULL;                //页链表开始页
                m_pCurrentPage        = NULL;                //当前操作页
                m_pEndPage                = NULL;        //页链表结束页
                m_ulPageCount        = 0;                //页数量
                m_ulCurrentPageNumber = 0;        //当前页编号
                m_ulIdleObjectCount = 0;        //空闲对象数量
        }
       
        template <class T>
        bool ObjectBuffer<T>::RequestObject( T** pObjectPointer, unsigned long& ulPage )
        {
                for( unsigned long i = 0; i < m_ulPageCount; i++ )
                {
                        if( !m_pCurrentPage->IsEmpty() )//如果不为空就请求一个对象
                        {
                                *pObjectPointer = m_pCurrentPage->RequestObject();
                                ulPage = m_ulCurrentPageNumber;
                                m_ulIdleObjectCount--;        //一个对象成功分配,空闲对象数量减1
                                return true;                       
                        }
                        if( m_pCurrentPage == m_pEndPage )//如果到了未尾就从头开始
                        {
                                m_pCurrentPage = m_pBeginPage;
                                m_ulCurrentPageNumber = 1;
                        }
                        else
                        {
                                m_pCurrentPage = m_pCurrentPage->m_pBack;
                                m_ulCurrentPageNumber++;
                        }
                }

                //如果循环结束还没找到空闲对象,说明页面已经用完,需要分配新页面
                SPage* m_pNew = new SPage( m_ulObjectOfPage );
                if( NULL == m_pNew )return false;
                m_pNew->SetFront( m_pEndPage );
                m_pEndPage->SetBack( m_pNew );
                m_pEndPage = m_pNew;
                m_ulPageCount++;
                m_pCurrentPage = m_pEndPage;
                m_ulCurrentPageNumber = m_ulPageCount;
                m_ulIdleObjectCount += m_ulObjectOfPage;        //空闲对象数量增加一个页面的数量
                if( !m_pCurrentPage->IsEmpty() )//如果不为空就请求一个对象
                {
                        *pObjectPointer = m_pCurrentPage->RequestObject();
                        ulPage = m_ulCurrentPageNumber;
                        m_ulIdleObjectCount--;        //一个对象成功分配,空闲对象数量减1

                        return true;                       
                }
                return false;
        }
       
        template <class T>
        bool ObjectBuffer<T>::ReturnObject( T** pObjectPointer, unsigned long &ulPage )
        {
                if( NULL == pObjectPointer || NULL == *pObjectPointer ||
                                0 == ulPage || ulPage > m_ulPageCount )return false;
       
                if( ulPage > m_ulCurrentPageNumber )
                {
                        for( ; m_ulCurrentPageNumber < ulPage; m_ulCurrentPageNumber++ )
                        {       
                                m_pCurrentPage = m_pCurrentPage->m_pBack;
                        }
                }
                if( ulPage < m_ulCurrentPageNumber )
                {
                        for( ; m_ulCurrentPageNumber > ulPage; m_ulCurrentPageNumber-- )
                        {       
                                m_pCurrentPage = m_pCurrentPage->m_pFront;
                        }
                }
                if( !m_pCurrentPage->ReturnObject( *pObjectPointer ) )return false;
                *pObjectPointer = NULL;
                ulPage = 0;
                m_ulIdleObjectCount++;        //一个对象成功归还,空闲对象数量加1

                //如果空闲对象数量大于2倍页面数量,说明空闲对象太多了,需要释放一些以减少内存占用
                if( m_ulIdleObjectCount >= ( m_ulObjectOfPage * 2 ) )
                {
                        SPage* pTemp1 = m_pBeginPage;
                        SPage* pTemp2 = NULL;
                        //遍历页面链表,找出空闲页面并释放
                        while( NULL != pTemp1 )
                        {
                                if( m_ulIdleObjectCount <= m_ulObjectOfPage )break;

                                pTemp2 = pTemp1;
                                pTemp1 = pTemp1->m_pBack;//向后遍历

                                //如果为空闲页面
                                if( pTemp2->IsFull() )
                                {
                                        //如果是开始页面让开始页面指向下一页面
                                        if( pTemp2 == m_pBeginPage )
                                        {
                                                m_pBeginPage = pTemp2->m_pBack;//让下一页作为新的开始页
                                                m_pBeginPage->m_pFront = NULL;//让新开始页的前一页指向空
                                               
                                                //如果和当前页面相同让当前页面指向下一页面
                                                if( pTemp2 == m_pCurrentPage )
                                                {
                                                        m_pCurrentPage = pTemp2->m_pBack;
                                                }
                                                pTemp2->Release();
                                                delete pTemp2;
                                                pTemp2 = NULL;
                                                m_ulPageCount--;
                                                m_ulIdleObjectCount -= m_ulObjectOfPage;
                                                continue;
                                        }
                                        //如果是结束页面让结束页面指向上一页面
                                        if( pTemp2 == m_pEndPage )
                                        {
                                                m_pEndPage = pTemp2->m_pFront;//让上一页作为新的结束页
                                                m_pEndPage->m_pBack = NULL;//让新结束页的后一页指向空
                                               
                                                //如果和当前页面相同让当前页面指向上一页面
                                                if( pTemp2 == m_pCurrentPage )
                                                {
                                                        m_pCurrentPage = pTemp2->m_pFront;
                                                        m_ulCurrentPageNumber--;//当前页面编号减1
                                                }
                                                pTemp2->Release();
                                                delete pTemp2;
                                                pTemp2 = NULL;
                                                m_ulPageCount--;
                                                m_ulIdleObjectCount -= m_ulObjectOfPage;
                                                continue;
                                        }
                                        //既不是开始页也不是结束页,只是和当前页相同让当前页指向下一页
                                        if( pTemp2 == m_pCurrentPage )
                                        {
                                                m_pCurrentPage = pTemp2->m_pBack;
                                                m_ulCurrentPageNumber++;//当前页面编号增1
                                        }
                                        pTemp2->m_pFront->m_pBack = pTemp2->m_pBack;
                                        pTemp2->m_pBack->m_pFront = pTemp2->m_pFront;
                                        pTemp2->Release();
                                        delete pTemp2;
                                        pTemp2 = NULL;
                                        m_ulPageCount--;
                                        m_ulIdleObjectCount -= m_ulObjectOfPage;
                                }
                        }
                }
                return true;
        }
        //end

21

主题

112

帖子

118

积分

注册会员

Rank: 2

积分
118
发表于 2009-3-3 16:06:00 | 显示全部楼层

Re:小弟精心打造的一个对象缓冲器,可支持任何类型的对

我在写横板射击游戏的时候,也用了一个类似的东西,主要是用来构造和管理“子弹”的 BulletMgr,和用来构造和管理“敌人”的 EnemyMgr。。呵呵

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-3-3 22:51:00 | 显示全部楼层

Re: Re:小弟精心打造的一个对象缓冲器,可支持任何类型

draculamx: Re:小弟精心打造的一个对象缓冲器,可支持任何类型的对象,有用就拿去

我在写横板射击游戏的时候,也用了一个类似的东西,主要是用来构造和管理“子弹”的 BulletMgr,和用来构造和管理“敌人”的 EnemyMgr。。呵呵


呵呵,贴上来瞧瞧,让小弟参考参考嘛!

21

主题

112

帖子

118

积分

注册会员

Rank: 2

积分
118
发表于 2009-3-3 23:15:00 | 显示全部楼层

Re:小弟精心打造的一个对象缓冲器,可支持任何类型的对

.....我离开那个公司很久了。。。代码带不出来。。。
原理很简单,就拿 BulletMgr 来说吧:
它主要负责:
1.生成子弹:初始点(在什么地方出现),目标(要飞向哪里),运动方式(直线,曲线,跟踪...),类型(小子弹,大子弹,导弹,可以被其玩家子弹抵消的子弹。。。。。)
2.管理子弹:根据第一步的条件,计算子弹的坐标,让它们按照正确的属性去“飞行”,碰撞检测,生命周期检测
3.销毁子弹:根据第二步中的判断(飞出屏幕,撞击到物体。。。)销毁他们

内部更简单。。就是一个 List ,然后在第二步和第三步中,遍历每个元素(子弹),计算飞行坐标,根据条件,判断他们是否销毁,还是继续飞行

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-3-3 23:39:00 | 显示全部楼层

Re: Re:小弟精心打造的一个对象缓冲器,可支持任何类型

draculamx: Re:小弟精心打造的一个对象缓冲器,可支持任何类型的对象,有用就拿去

.....我离开那个公司很久了。。。代码带不出来。。。
原理很简单,就拿 BulletMgr 来说吧:
它主要负责:...


理解,谢了!我也准备做一个,呵呵!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-20 05:10

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表