C++ deleting a sprite with delete operator

Started by
19 comments, last by PezMutanT 16 years ago
Think about storing things using RAII -- resource allocation is initialization -- so you don't forget to deallocate them.

Either use a boost auto pointer, or roll your own quickly:
template<typename T>class EasyAutoPtr {    T* t;  public:    static EasyAutoPtr FromNewCreation(T* t_) {return EasyAutoPtr(t_, true);}    explicit EasyAutoPtr(T* t_, bool take_reference=false):t(t_){if (!take_reference) t->AddRef();}    T* StealReference() {      T* tmp = t;      t = 0;      return tmp;    }    T* BorrowReference() {return t;}    T* BorrowReference() const {return t;}    T* DuplicateReference() {if (t) t->AddRef(); return t;}    T* DuplicateReference() const {if (t) t->AddRef(); return t;}    void swap(EasyAutoPtr<T>& other) {swap(t, other.t);}    virtual ~EasyAutoPtr() {if(t)t->RemoveRef();}    template<typename Other>    EasyAutoPtr(Other const& o):t(o.DuplicateReference()) {}    template<typename Other>    EasyAutoPtr<T> const& operator=(Other const& o) {      EasyAutoPtr<T> tmp = o;      this->swap(tmp);      return *this;    }    operator T*() { return BorrowReference(); }    operator T const*() const { return BorrowReference(); };    T* operator->() { return BorrowReference(); }    T const* operator->() const { return BorrowReference(); }    T& operator*() { return BorrowReference(); }    T const& operator*() const { return BorrowReference(); }};

(I would advise using a boost auto pointer -- I've written multiple auto pointer classes, and odds are the above one I whipped together has a bug!)
Advertisement
Quote:Original post by Zahlman
Whenever you call a non-virtual member function through a pointer or reference to the base class, the base class version of the function is called, not the derived one. The destructor is a member function; therefore, whenever you call 'delete' on a pointer to the base class, and the destructor of the base class is not virtual, the base class version is called. That's bad, because if the pointer actually points to a derived instance (and the ability to do that is what motivated you in the first place), then the program will try to clean up a derived instance as if it were a base instance. Note: this does not simply clean up the base part of the class and leave the derived part alone. It is explicitly undefined behaviour.


Perfecly explained, I understand now. Thanks a lot to both of you for your answers!
Quote:Original post by PezMutanT
- Reading the ID3DXSprite reference, it mention something about a list of batched sprites, like here:

"ID3DXSprite::Draw Adds a sprite to the list of batched sprites."

I don't understand how I should manage that list and if I could access every element of it (because every element would be a different sprite). Is it related with the AddRef() and Release() functions?
You don't. I mentioned that ID3DXSprite contains a vertex and index buffer internally; the Draw() function looks like this (Psuedo-code):
ID3DXSprite::Draw(x, y, w, h) // Whatever the parameters are{   add_4_vertices_to_vertex_buffer(x, y, w, h);   add_4_indices_to_index_buffer(x, y, w, h);   m_numSprites++;}ID3DXSprite::Flush(){   set_vb_and_ib();   m_pDevice->DrawIndexedPrimitive(blah, foo, m_numSprites*2);   m_numSprites = 0;}ID3DXSprite::End(){   Flush();}

What I mean is that Draw() just adds a sprite to the batch, and Flush() or End() actually draws the sprite. It's actually a bit more complicated than that, because ID3DXSprite deals with multiple textures, multiple transforms, and so on. But that's the general idea.
You don't need to access the list at all, it's all handled for you.

If you're interested in the internal workings, I made a Journal Entry a while ago about what ID3DXSprite does internally. That information was from a fairly old SDK, so the specifics have probably changed, but it gives you a rough idea of what it's really doing.
Thanks again, Evil Steve.

So I suppose I only have to keep a list (for example a vector) of references (pointers to my own Sprite class and/or its derived ones) to the different sprites in the game just to interact with them (for example killing one of them or moving one of them along the window), right?

I took a look at your journal, that's great stuff man! How can I access to it directly from the home page of gamedev.net?

Well, I don't know what I would do without you, guys...

Thanks a lot! ;)
Quote:Original post by Zahlman
Quote:Original post by PezMutanT
- Why a virtual destructor? If I only have one destructor in the parent class, shouldn't it be enough?


Whenever you call a non-virtual member function through a pointer or reference to the base class, the base class version of the function is called, not the derived one. The destructor is a member function; therefore, whenever you call 'delete' on a pointer to the base class, and the destructor of the base class is not virtual, the base class version is called.


To be nit-picky, and as an interesting bit of trivia, a const base-class reference to a derived class temporary will correctly call the derived class destructor when it falls out of scope without a virtual dispatch. See the Guru question here.
Quote:Original post by PezMutanT
So I suppose I only have to keep a list (for example a vector) of references (pointers to my own Sprite class and/or its derived ones) to the different sprites in the game just to interact with them (for example killing one of them or moving one of them along the window), right?
Yup, exactly. What a lot of games do is have a scene graph. The most basic kind would just be a vector of pointers to a "game object". A Game Object would be a virtual base class, which would be inherited from by every game object type, and contains functions like Render() and Update() (Since update ticks might be different from render ticks; e.g. rendering at 60Hz and doing logic as fast as possible). You could also have OnLostDevice() and OnResetDevice() functions in there and use them to reset your ID3DXSprite.
Every game tick, the game just needs to call the Update() function for each object in this vector, and at render time call Render().

Quote:Original post by PezMutanT
I took a look at your journal, that's great stuff man! How can I access to it directly from the home page of gamedev.net?)
Thanks [smile] All the journals can be accessed from the "Members" menu at the top of each page -> Developer Journals.
Ok, I think I get the idea. Every tick I have to call the Update() function in every element of the vector (every sprite), and every render tick I have to call the Render() function in every element of the vector. And this Render() function would have one call to ID3DXSprite::Draw() in order to add that sprite to the batched list of sprites, of course between Begin() and End() functions. Is this right?

That "update ticks different from render ticks" thing... I hope being able to manage it...

Thanks again Evil Steve! ;)
Quote:Original post by PezMutanT
Ok, I think I get the idea. Every tick I have to call the Update() function in every element of the vector (every sprite), and every render tick I have to call the Render() function in every element of the vector. And this Render() function would have one call to ID3DXSprite::Draw() in order to add that sprite to the batched list of sprites, of course between Begin() and End() functions. Is this right?

That "update ticks different from render ticks" thing... I hope being able to manage it...

Thanks again Evil Steve! ;)
Yup, pretty much. You don't need to have update seperate from render, but it's a good practice to get into, since it's slightly more efficient to fill vertex buffers, etc and then wait as long as possible before rendering from them (Although it might not make any difference, it depends on the drivers), and various other reasons (If logic takes 2ms and rendering takes 10ms, you can process 3 frames of logic + 1 render frame and still vsync at 60Hz for instance).

Your code might look something like:
class GameObject{public:   GameObject() {}   virtual ~GameObject() {}   virtual void Update() = 0;   virtual void Render() = 0;   // Any other info you may want such as bounding spheres for culling,   // object names for debugging, etc};class Sprite : public GameObject{public:   // Various Sprite() member functions here   virtual void Update() { /* Do update code */ }   virtual void Render() { /* Do render code */ }};// Elsewhere:std::vector<GameObject*> m_sceneGraph;// Add some objects:m_sceneGraph.push_back(new Fire(...));m_sceneGraph.push_back(new Fire(...));m_sceneGraph.push_back(new Fire(...));// And then your main loop would be something like:for(size_t i=0; i<m_sceneGraph.size(); ++i){   m_sceneGraph->Update();   m_sceneGraph->Render();}

Two changes you could make to that would be passing in a frame time to the Update() function, so each object can update itself with respect to time (Which makes the game framerate-independant), and you could do batching; make each GameObject have an ID (an enum type probably), and sort the m_sceneGraph vector by this ID. Then when you render the first of each object, call a BeginBatchRender() virtual function, and when you render the last, call a EndBatchRender() virtual function.
Then your Sprite class could call ID3DXSprite::Begin() from BeginBatchRender() and ID3DXSprite::End() from EndBatchRender(), which would give you better performance than doing it once per sprite.

However, I'd recommend getting the basics working first, then adding on stuff like this.
Nice idea that last one about "ID'ing" every sprite in order to only make one call to ID3DXSprite::Begin() and ID3DXSprite::End() :)

But like you said, I will try doing the basics for now and adding new features one by one. I was trying to get into collision detection and that was the origin of my post, because I thought it could be handled having several derived classes for the different kinds of sprites (characters, fire, walls, ...) in order to being able to have different Update() functions for each one and also for being able to distinguish collisions between different sprites...

All of this is what I have in mind, but I still don't know how I'm going to do it... I feel kind of guilty asking again for advice, but... maybe someone could lead me to get me started...

Anyway, thanks Evil Steve!!
Well I've read about "double dispatch" and the "visitor pattern" and it looks like the best way I've seen so far to implement collision detection. It looks a little complicated but at least I know where to start...

This topic is closed to new replies.

Advertisement