c – 在游戏中处理实体
作为一个小小的练习,我正在尝试编写一个非常简单的游戏引擎,只需处理实体(移动,基本AI等)
因此,我试图考虑一个游戏如何处理所有实体的更新,我有点困惑(可能是因为我以错误的方式进行) 所以我决定在这里发布这个问题,向您展示我目前的思考方式,看看有没有人可以向我提出一个更好的方法. 目前,我有一个CEngine类,它指向需要的其他类(例如CWindow类,CEntityManager类等) 我有一个游戏循环,伪代码会像这样(在CEngine类内) while(isRunning) { Window->clear_screen(); EntityManager->draw(); Window->flip_screen(); // Cap FPS } 我的CEntityManager类看起来像这样: enum { PLAYER,ENEMY,ALLY }; class CEntityManager { public: void create_entity(int entityType); // PLAYER,ALLY etc. void delete_entity(int entityID); private: std::vector<CEntity*> entityVector; std::vector<CEntity*> entityVectorIter; }; 我的CEntity类看起来像这样: class CEntity() { public: virtual void draw() = 0; void set_id(int nextEntityID); int get_id(); int get_type(); private: static nextEntityID; int entityID; int entityType; }; 之后,我将为敌人创建一个类,并给它一个精灵表,它自己的功能等. 例如: class CEnemy : public CEntity { public: void draw(); // Implement draw(); void do_ai_stuff(); }; class CPlayer : public CEntity { public: void draw(); // Implement draw(); void handle_input(); }; 所有这一切都很好,只是画精灵到屏幕上. 但是,我来到了使用一个实体中存在但不在另一个实体中的函数的问题. 在上面的伪代码示例中,do_ai_stuff();和handle_input(); 从我的游戏循环中可以看到,有一个调用EntityManager-> draw(); 但是后来我想,如果是一个需要处理输入的玩家实体呢? 我没有尝试过,但我认为我不能像我在draw()函数中循环一样,因为像敌人这样的实体不会有一个handle_input()函数. 我可以使用if语句来检查entityType,像这样: for(entityVectorIter = entityVector.begin(); entityVectorIter != entityVector.end(); entityVectorIter++) { if((*entityVectorIter)->get_type() == PLAYER) { (*entityVectorIter)->handle_input(); } } 但是我不知道人们通常会如何写这个东西,所以我不知道最好的方法. 我在这里写了很多,我没有提出任何具体的问题,所以我会澄清我在这里寻找什么: >我是否已经布局/设计了我的代码好吗?它是否实用? 解决方法
你会越来越接近大多数游戏实际做的方式(尽管绩效专家总裁Mike Acton
often gripes about that).
通常你会看到这样的东西 class CEntity { public: virtual void draw() {}; // default implementations do nothing virtual void update() {} ; virtual void handleinput( const inputdata &input ) {}; } class CEnemy : public CEntity { public: virtual void draw(); // implemented... virtual void update() { do_ai_stuff(); } // use the default null impl of handleinput because enemies don't care... } class CPlayer : public CEntity { public: virtual void draw(); virtual void update(); virtual void handleinput( const inputdata &input) {}; // handle input here } 然后实体管理器遍历并在世界上的每个实体上调用update(),handleinput()和draw(). 当然,这些函数有很多功能,当你调用它们时,其中大部分都不做任何事情,可能会浪费很多,特别是对于虚拟函数.所以我也看过一些其他的方法. 一个是将输入数据存储在全局(或作为全局接口或单例等的成员)中.然后覆盖敌人的update()函数,所以他们do_ai_stuff().和更新(),以便它通过轮询全局进行输入处理. 另一个是在Listener pattern上使用一些变体,所以关心输入的所有内容都继承自一个普通的监听器类,并且通过InputManager注册所有这些监听器.然后,输入管理器依次调用每个侦听器: class CInputManager { AddListener( IInputListener *pListener ); RemoveListener( IInputListener *pListener ); vector<IInputListener *>m_listeners; void PerFrame( inputdata *input ) { for ( i = 0 ; i < m_listeners.count() ; ++i ) { m_listeners[i]->handleinput(input); } } }; CInputManager g_InputManager; // or a singleton,etc class IInputListener { virtual void handleinput( inputdata *input ) = 0; IInputListener() { g_InputManager.AddListener(this); } ~IInputListener() { g_InputManager.RemoveListener(this); } } class CPlayer : public IInputListener { virtual void handleinput( inputdata *input ); // implement this.. } 还有其他更复杂的方法.但所有这些工作,我已经看到他们中的每一个实际运输和销售的东西. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |