Subclassing cocos2dx::Sprite

I am making a simple class that has an array or sprites in there.

Ex:
Myclass : public cocos2dx::Sprite {
std::unordered_map<int,cocos2d::Sprite*> _sprites;

}

two questions.
1)When I make my class it’s fine. If I try to call set position on that class I get a crash here:

int main(int argc, char *argv[])
{
    AppDelegate app;
    return Application::getInstance()->run(); <== Thread 1. EXC_BAD_ACCES...
}

2)would there be something better to use that unordered list?

I am not sure what you are trying to accomplish, however

  1. I think you want to extend cocos2d::Sprite
#ifndef _MYSPRITE_HPP_
#define _MYSPRITE_HPP_

#include "cocos2d.h"

class MySprite : public cocos2d::Sprite
{
    public:
        MySprite();
        ~MySprite();
};

#endif // _MYSPRITE_HPP_

You might consider using a std::vector or a cocos2d::Vector. Using the later handles the retain. I prefer the first. This being said, perhaps you have a reason for using an std::unordered_map that I am not considering.

Also watch out for the Sprite::create trap with subclassed sprites. Sprite::create always creates a Sprite so if you subclass and want the create methods, you have to add them to your own class, otherwise you have a pointer to MyClass but it is really a Sprite, which can crash.

Do you have a reason to subclass Sprite? If your purpose is to extend game behaviors, then you are better off using ComController. It may be troublesome, but if done right, you can use one Controller class for many sprites of different images.

This might explain my crash.

But I wonder if what @duracellrabbid said below might be a better option to use a ComController?

I want a class that can have an array of N Sprites that I can set their z-order and draw then.

Example class

class myclass
{
std::vector<cocos2d::sprite*> *sprites;

addSprite( sprite *s, int zOrder ) { addChild(s, zOrder) };
update() { for(sprite s: sprites) { update s };
draw() { for(sprite s: sprites ) { draw s }

}

ComController seems to be a interesting class, can you link some reference material or shed some more info about it, or situations when to use it?

what you want is something that can set your sprite’s z-order based on a certain conditions right? In that case, you can sub-class a ComController and override its update method to check if the sprite attached to it has reached a condition to modify its LocalZOrder.

The class will have an array of sprites, when I instantiate the class, It’ll load all the needed sprite name, position, zorder, etc.

Sadly, I got my references from the examples in cpp_test. There are very little documentations on them but the examples in cpp_test should suffice. Here’s a few things to take note when using them:

  1. You will need to give your ComController a name if you want to get them using Node::getComponent(). Each Node can only have a ComController with one name. (e.g. Your Node can only have a ComController named “DoThingsController”, if you want to add another ComController with the same name, i think it will either not add it or give you an error.)

  2. The node which you attached the ComController can be referenced by getOwner().

  3. When you do a Node::addComponent(), ComController::onEnter will be triggered and you can do anything you want with the node in it. Note that this will only be called once. Do not confused it with Node::onEnter(). Likewise, when you remove the ComController from the node, ComController::onExit() will trigger.

  4. ComController::onEnter() will automatically schedule ComController::update(). So if you want to do anything everytime it updates, you can just override ComController::update().

  5. You can also handle Touch events in ComController, minus all the setting up of EventListener.

Hope it helps

Docs are a bit all over the place w/ cocos but that’s another thing.

The on enter and on exit looks like places where I can setup the sprites and stuff like that, thanks for those tips.

One more question, which cpp-test has the comcontroller in there?

Thanks for the heads up and summing that up :innocent: , i found some interesting classes in cpp test, look like i can some of them,

ExtensionsTest/CocoStudioComponentsTest

that’s cool, lots of really good info in there. Thanks a lot @duracellrabbid!

Hi, I have also referred the official document about subclass sprite.

In the header file:

#ifndef _MYSPRITE_HPP_
#define _MYSPRITE_HPP_

#include "cocos2d.h"

class MySprite : public cocos2d::Sprite
{
    public:
        MySprite();
        ~MySprite();
        static MySprite* create();

        void initOptions();

        void addEvents();
        void touchEvent(cocos2d::Touch* touch, cocos2d::Vector2 _p);

    private:

};

#endif // _MYSPRITE_HPP_

In the source file:

#include "MySprite.hpp"

using namespace cocos2d;

MySprite::MySprite() {}

MySprite::~MySprite() {}

MySprite* MySprite::create()
{
    MySprite* pSprite = new MySprite();

    if (pSprite->initWithSpriteFrameName("MySprite.png"))
    {
        pSprite->autorelease();

        pSprite->initOptions();

        pSprite->addEvents();

        return pSprite;
    }

    CC_SAFE_DELETE(pSprite);
    return NULL;
}

void MySprite::initOptions()
{
    // do things here like setTag(), setPosition(), any custom logic.
}

void MySprite::addEvents()
{
    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);

    listener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event)
    {   
        cocos2d::Vector2 p = touch->getLocation();
        cocos2d::Rect rect = this->getBoundingBox();

        if(rect.containsPoint(p))
        {
            return true; // to indicate that we have consumed it.
        }

        return false; // we did not consume this event, pass thru.
    };

    listener->onTouchEnded = [=](cocos2d::Touch* touch, cocos2d::Event* event)
    {
        MySprite::touchEvent(touch);
    };

    cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener, 30);
}

void MySprite::touchEvent(cocos2d::Touch* touch, cocos2d::Vector2 _point)
{
    CCLOG("touched MySprite");
}

However, suppose I want MySprite to be a base sprite class, and I want to create different heroes subclassed from MySprite, how can I achieve this? It is sth like that class MySprite: public cocos2d::Sprite and class Hero1: public MySprite and class Hero2: public MySprite .

What I am confused with is that I don’t know the best way to implement the create method of the subclasses. I have googled it but I couldn’t find any good example. I am new in the cocos forum so I can’t open a new discussion but only can ask for help in such a related problem. Thanks very much.

PS: I use cocos2dx-3-10.

Yes, this is how you do it.

@slackmoehrle Em… thanks.

However, do I need to implement the create method in Hero1 and Hero2 respectively? It seems that I need to call initWithSpriteFrameName() method in create method, Different Sprite Frames are used to initialize Hero1 and Hero2. So I am still confused with how the create method to be implemented, and I do not know whether in Hero1 need to call autorelease() or not.

I will appreciate that if I can get a sample code example about these subclasses, thx a lot.

I don’t use a built in create() method really. I just make up my own and that is what I call. I do this so I can pass in whatever parameters I want.

all right I think I know what you mean…

It seems that we just need to make sure that one hero is created with autorelease(), then it’s ok and safe, right?

THX.