Scene场景设计

//场景上的物体
struct SceneEntry
{
    friend class SceneEntryIndex;
    public:
    //物体类型
    enum SceneEntryType
    {
        SceneEntry_Player,    /**< 玩家*/
        SceneEntry_NPC,        /**< NPC*/
        SceneEntry_Build,    /**< 建筑*/
        SceneEntry_Object,    /**< 地上物品*/
        SceneEntry_MAX
    };

    //物体状态
    enum SceneEntryState
    {
        SceneEntry_Normal,        /**< 普通状态 */
        SceneEntry_Death,        /**< 死亡状态 */
        SceneEntry_Hide            /**< 隐藏状态 */
    };
    ...
};


class Scene : public SceneEntryIndex
{
    public:
    
        enum SceneType
        {
            STATIC,        //静态地图
            GANG        //副本
        };
        
        bool init(DWORD mapid); //初始化地图场景
        bool Scene::sendCmdToNine(const zPosI posi, const void *pstrCmd, const int nCmdLen);
        ...
};

bool Scene::sendCmdToNine(const zPosI posi, const void *pstrCmd, const int nCmdLen)
{
    SceneSendToEveryOne sendeveryone(pstrCmd, nCmdLen); //示例,对于每个九屏玩家发送了一个pstrCmd指令
    const zPosIVector &pv = getNineScreen(posi);
    for(zPosIVector::const_iterator it = pv.begin(); it != pv.end(); it++)
    {
        execAllOfScreen(zSceneEntry::SceneEntry_Player,*it,sendeveryone);
    }
    return true;
}

class SceneManager
{
    public:
        bool init();
        Scene * loadScene(Scene::SceneType type, DWORD mapid);
        
        struct MapInfo {
            DWORD mapid;
            char name[100];
            ...
        }
        
        typedef std::map<DWORD , MapInfo> MapMap;
        MapMap map_info; //所有地图信息
};

//场景战斗类,包括场景玩家和npc的战斗
class SceneEntryPk : public SceneEntry
{
    public:
        Scene *scene; //所在的场景指针
        ...
};

//场景玩家
class SceneUser : public SceneEntryPk 
{
    public:
        bool changeMap(Scene *newscene,const Pos &pos); //切换地图
        bool intoScene(Scene *newscene,bool needInitInfo,const Pos &initPos); //进入地图场景
        bool LeaveScene(); //离开场景
        
        void sendMeToNine(); //把自己通知九屏
        void sendNineToMe(); //把九屏通知自己
        ...
};

void SceneUser::sendNineToMe()
{
    GetEnvryOneAndSend one(this); //里面实现了一个打包数据的exec
    const zPosIVector &pv = scene->getNineScreen(getPosI());
    for(zPosIVector::const_iterator it = pv.begin(); it != pv.end(); it++)
    {
        scene->execAllOfScreen(*it,one);
    }
}


typedef DWORD zPosI;
typedef std::vector<zPosI> zPosIVector;

//场景物体屏索引
class SceneEntryIndex
{

    protected:

        Pos sceneWH; //场景宽和高
        
        DWORD screenMax; //最大屏索引编号
        
        DWORD screenx; //横向多少屏
        
        DWORD screeny; //纵向多少屏

    private:

        typedef std::set<SceneEntry *> SceneEntry_SET;

        typedef std::map<zPosI, SceneEntry_SET> PosIMapIndex;

        PosIMapIndex index[SceneEntry::SceneEntry_MAX]; //场景所有物体 SceneEntryType PosI SceneEntry
        
        SceneEntry_SET all[SceneEntry::SceneEntry_MAX]; //场景所有物体 SceneEntryType SceneEntry
        

        //在初始化的时候计算九屏关系
        typedef map<DWORD, zPosIVector> NineScreen_map;
        
        typedef NineScreen_map::iterator NineScreen_map_iter;
        typedef NineScreen_map::const_iterator NineScreen_map_const_iter;
        typedef NineScreen_map::value_type NineScreen_map_value_type;
        
        NineScreen_map ninescreen;

        void freshEffectPosi(const zPosI oldposi, const zPosI newposi);
        

    public:

        SceneEntryIndex() {}
        void init(const Pos sceneWH, const DWORD screenx, const DWORD screeny, const DWORD screenMax);
        virtual ~SceneEntryIndex() {}
        
        const zPosIVector &getNineScreen(const zPosI &posi)
        {
            NineScreen_map_const_iter iter = ninescreen.find((DWORD)posi);
            if( iter != ninescreen.end())
            {
                return iter->second;
            }
            
            return ninescreen[(DWORD)-1];
        }
        ...
};

void SceneEntryIndex::init(const Pos sceneWH, const DWORD screenx, const DWORD screeny, const DWORD screenMax)
{
    this->sceneWH=sceneWH;
    this->screenx=screenx;
    this->screeny=screeny;
    for(int i = 0; i < SceneEntry::SceneEntry_MAX; i++)
    {
        for(DWORD j=0; j < screenMax; j ++)
        {
            index[i][j];
        }
    }

    //预先建立地图九屏索引
    const int adjust[9][2] = { {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, 0} };
    
    for(DWORD j=0; j < screenMax ; j ++)
    {
        int nScreenX = j % screenx;
        int nScreenY = j / screenx;
        
        //计算周围九屏
        {
            zPosIVector pv;
            for(int i = 0; i < 9; i++) {
                int x = nScreenX + adjust[i][0];
                int y = nScreenY + adjust[i][1];
                if (x >= 0 && y >= 0 && x < (int)screenx && y < (int)screeny) {
                    pv.push_back(y * screenx + x);
                }
            }
            ninescreen.insert(NineScreen_map_value_type(j,pv));
        }
    }
}

//刷新屏索引
bool SceneEntryIndex::refresh(SceneEntry *e,const Pos & newPos)
{
    if(e==NULL) return false;
    SceneEntry::SceneEntryType type = e->getType();
    if(e->inserted)
    {
        //已经加入地图,只是在屏之间来回切换
        bool ret=false;
        zPosI orgscreen=e->getPosI();

        SceneEntry_SET &pimi = index[type][orgscreen];
        SceneEntry_SET::const_iterator it = pimi.find(e);
        if (it != pimi.end() && e->setPos(sceneWH, newPos))
        {
            ret=true;
            if(orgscreen!=e->getPosI())
            {
                pimi.erase(it);
                index[type][e->getPosI()].insert(e);
            }
        }

        return ret;
    }
    else
    {
        //新加入地图
        if(e->setPos(sceneWH,newPos))
        {
            index[type][e->getPosI()].insert(e);
            //在全局索引中添加
            all[type].insert(e);
        
            e->inserted=true;
        }

        return e->inserted;
    }
}

//移除场景物体
bool SceneEntryIndex::removeSceneEntry(SceneEntry *e)
{
    if(e==NULL || !e->inserted) return false;

    SceneEntry::SceneEntryType type = e->getType();
    SceneEntry_SET &pimi = index[type][e->getPosI()];
    SceneEntry_SET::iterator it = pimi.find(e);
    if (it != pimi.end())
    {
        //在屏索引中删除
        pimi.erase(it);
        //在全局索引中删除
        all[type].erase(e);
        
        e->inserted=false;

        return true;
    }

    return false;
}

//遍历一屏物体,并对其进行callback操作
void SceneEntryIndex::execAllOfScreen(const zPosI screen,zSceneEntryCallBack &callback)
{
    for(int i = 0; i < SceneEntry::SceneEntry_MAX; i++)
    {
        SceneEntry_SET &pimi = index[i][screen];
        for(SceneEntry_SET::iterator it=pimi.begin();it!=pimi.end();)
        {
            //预先保存迭代器,防止回调中使迭代器失效
            SceneEntry_SET::iterator tmp = it;
            it++;
            zSceneEntry *eee = *tmp;
            if (!callback.exec(eee)) return;
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/Ftworld21/article/details/120282862