taylormorris Posted May 20, 2015 Share Posted May 20, 2015 Hello, We are trying to create a new sub-class of Player but can't seem to get it done through the API. For reference, the new Player class would be a combination of PlayerActor and PlayerSpectator, where users could switch between 'walking' and 'flying' with a button press. I started with the example from the documentation (https://developer.unigine.com/en/docs/1.0/cpp_api/application) and added a new class successfully, just to test the C++ API implementation. But in trying to create a new class as an extension from Player caused a lot of problems, even though I am still just trying to mirror the exact functionality of PlayerDummy or PlayerSpectator. Here is the header file for PlayerGhost, to show the current approach #ifndef PLAYERGHOST #define PLAYERGHOST #include <UnigineEngine.h> #include <UnigineMathLib.h> #include <UnigineWorld.h> #include <UniginePlayer.h> #include <UniginePlayerDummy.h> #include <UnigineNode.h> #include <vector> #include "PlayerGhostInterface.h" class PlayerGhost : public Unigine::PlayerDummy { protected: template <class> friend class Unigine::Ptr; private: PlayerGhost(); virtual ~PlayerGhost(); std::vector<Unigine::NodePtr> nodes; Unigine::NodePtr create_node(const char *name, const UNIGINE_MAT4 &transform); void remove_node(Unigine::NodePtr node); // copy player PlayerGhost *copy(PlayerGhost *node) const; mutable Unigine::vec3 direction; ::PlayerGhost *player; public: void player_init(); void player_shutdown(); static Unigine::Ptr<PlayerGhost> create(const Unigine::NodePtr &node); virtual Unigine::PlayerPtr getPlayer() const; virtual void setViewportMask(int mask) const; virtual int getViewportMask() const; virtual void setReflectionMask(int mask) const; virtual int getReflectionMask() const; virtual void setSourceMask(int mask) const; virtual int getSourceMask() const; virtual void setReverbMask(int mask) const; virtual int getReverbMask() const; virtual void setFov(float fov) const; virtual float getFov() const; virtual void setZNear(float znear) const; virtual float getZNear() const; virtual void setZFar(float zfar) const; virtual float getZFar() const; virtual void setProjection(const Unigine::mat4 &projection) const; virtual Unigine::mat4 getProjection() const; virtual void setSProjection(const Unigine::mat4 &sprojection) const; virtual Unigine::mat4 getSProjection() const; virtual void setModelview(const UNIGINE_MAT4 &modelview) const; virtual UNIGINE_MAT4 getModelview() const; virtual UNIGINE_MAT4 getIModelview() const; virtual void setOldModelview(const UNIGINE_MAT4 &modelview) const; virtual UNIGINE_MAT4 getOldModelview() const; virtual void setUp(const Unigine::vec3 &up) const; virtual Unigine::vec3 getUp() const; virtual void setView(const Unigine::vec3 &view) const; virtual Unigine::vec3 getView() const; virtual void setOffset(const Unigine::mat4 &offset) const; virtual Unigine::mat4 getOffset() const; virtual void setVelocity(const Unigine::vec3 &velocity) const; virtual Unigine::vec3 getVelocity() const; virtual void setPostMaterials(const char *materials) const; virtual const char *getPostMaterials() const; virtual void setControlled(int controlled) const; virtual int isControlled() const; virtual void setControls(const Unigine::ControlsPtr &controls) const; virtual Unigine::ControlsPtr getControls() const; virtual void updateControls(float ifps) const; virtual void flushTransform() const; }; /** * PlayerDummy smart pointer. */ typedef Unigine::Ptr<PlayerGhost> PlayerGhostPtr; #endif You can see the attempt mimic some of the internal Player-derived classes but there seems to be a barrier on the create function, which works off of the internal-only PlayerInterface class. For example: Unigine::Ptr<PlayerGhost> PlayerGhost::create(const Unigine::NodePtr &n) { //Node *node = Unigine::GetNodeInterface(n.get()); if (n.get() == NULL || n->isPlayer() == 0) return PlayerGhostPtr(); return PlayerGhostPtr(new PlayerInterface(static_cast< Unigine::Player*>(node), 0)); } But PlayerInterface is totally inaccessible so I don't know what I should be doing instead. Is there a way to accomplish this with the C++ API that I am not understanding? Or would we need to make modifications inside the engine source and re-compile (we really don't want to do this if at all possible!!)? Help is greatly appreciated! Taylor Link to comment
maxi Posted May 21, 2015 Share Posted May 21, 2015 Hi, Taylor. When you subclass from Unigine::PlayerDummy, you only subclass from wrapper. You can create a trully Player-derived class only inside engine and make a wrapper to it. Or you can do the following: static Unigine::Ptr<PlayerGhost> create(const Unigine::NodePtr &node) { //Node *node = Unigine::GetNodeInterface(n.get()); if (node.get() == NULL || node->isPlayer() == 0) return PlayerGhostPtr(); return create(PlayerDummy::create(node)); } static Unigine::Ptr<PlayerGhost> create(const Unigine::PlayerDummyPtr &player) { return Ptr<PlayerGhost>(static_cast<PlayerGhost*>(player.get())); } Link to comment
taylormorris Posted May 22, 2015 Author Share Posted May 22, 2015 Thanks for the assistance! I have been working with this all day and still can't find a way through. For the create functions, I have updated them to Unigine::Ptr<PlayerGhost> PlayerGhost::create(const Unigine::PlayerDummyPtr &player) { PlayerGhost * pGhost = static_cast<PlayerGhost*>(player.get()); return Unigine::Ptr<PlayerGhost>(pGhost); } Unigine::Ptr<PlayerGhost> PlayerGhost::create(const Unigine::NodePtr &node) { Unigine::PlayerDummyPtr pDummy = PlayerDummy::create(node); PlayerGhost * pGhost = static_cast<PlayerGhost*>(pDummy.get()); return Unigine::Ptr<PlayerGhost>(pGhost); } And the creation event logic is NodePtr pNode = NodeDummy::create()->getNode(); PlayerDummyPtr pDummy = PlayerDummy::create(pNode); pPlayer = PlayerGhost::create(pDummy); All of this compiles and runs, but a Null Pointer assert gets tripped every time pPlayer is accessed. Any ideas? From all my tests today, it looks like the problem is with the use of static_cast... Link to comment
maxi Posted May 22, 2015 Share Posted May 22, 2015 Hi, Taylor. You have a pDummy = NULL, because PlayerDummy::create() method expectes only a ::PlayerDummy argument, not ::NodeDummy. The following code creates pPlayer PlayerDummyPtr pDummy = PlayerDummy::create(); PlayerGhostPtr pPlayer = PlayerGhost::create(pDummy); Link to comment
taylormorris Posted June 2, 2015 Author Share Posted June 2, 2015 Thanks for the help. We found that the problem was in the creation logic, the PlayerDummyPtr needed to be a class variable, as the new Player still contained that pointer and it was being destroyed after the creation event completed. But we also learned that the C++ API is probably not the best way to create a new 'player' class. Instead, we will be starting a new one through UnigineScript only Thanks again! Link to comment
Recommended Posts