久々の投稿です。
表題の通り、Cocos2-dxの3.xでSpriteのテクスチャ(画像)を簡単に変更する方法を備忘として書いておきます。
※ちなみに、3.xと書いてますが正確にいつから採用されたのかは調べてないので、バージョンによってはできないかもです(cocos2d-xの3.10では余裕でできました)
以前までのやり方
以前までのやり方では、こんな風にすることで内部のテクスチャを変えることができました。
(cocos2d-xの2.x形式で書きます)
// 普通の画像から変更 CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(filename); sprite->setTexture(texture); sprite->setContentSize(texture->getContentSize()); // テクスチャアトラスから変更 CCSpriteFrame* frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(filename); sprite->setTexture(frame->getTexture()); sprite->setTextureRect(frame->getRect()); sprite->setDisplayFrame(frame);
まあ、これだって簡単ですね。
でもいちいち2行ないし3行かかないといけないのは面倒なので、ユーティリティクラスなどを作ってその中で作業したりしてました。
Cocos2d-x 3.xでは上の処理が実装されてる
はい、うれしいことに、いつのまにかもうSpriteの中に上のような処理は実装されてました。なので、以下を呼び出すだけで画像の変更をすることができます。
// テクスチャアトラスから作成
sprite->setSpriteFrame("変更画像");
// 普通の画像から変更(※ためしてないですが多分こんな感じでできそう)
sprite->setSpriteFrame(Sprite::create("変更画像")->getSpriteFrame());
すみません、普通の画像からSpriteの画像を変更する方法は試してないです。
でも多分上みたいな感じでできるんじゃないかなー。
画像を変更する用のActionを自作する
こんな感じでActionを自作しておくと、runActionでも利用できたりしていろいろと便利です。
(でも、これくらいのなら調べてないだけで既にフレームワーク内にありそうな気もしますが)
// hppファイル内
class CC_DLL ChangeFrame : public cocos2d::ActionInstant {
protected:
std::string m_image;
public:
static ChangeFrame* create(const std::string& image);
virtual void update(float time) override;
virtual ActionInstant* reverse() const override;
virtual ActionInstant* clone() const override;
protected:
ChangeFrame() {
}
virtual ~ChangeFrame() {
}
bool initWithName(const std::string& image);
private:
CC_DISALLOW_COPY_AND_ASSIGN(ChangeFrame);
};
// cppファイル内
ChangeFrame* ChangeFrame::create(const std::string& image) {
ChangeFrame* ret = new (std::nothrow) ChangeFrame();
if (ret && ret->initWithName(image)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
bool ChangeFrame::initWithName(const std::string& image) {
m_image = image;
return true;
}
ActionInstant* ChangeFrame::clone() const {
// no copy constructor
auto a = new (std::nothrow) ChangeFrame();
a->initWithName(m_image);
a->autorelease();
return a;
}
ActionInstant* ChangeFrame::reverse() const {
return this->clone();
}
void ChangeFrame::update(float time) {
CC_UNUSED_PARAM(time);
auto target = dynamic_cast<Sprite*>(_target);
if (target) {
target->setSpriteFrame(m_image);
}
}
// 使い方
// 0.5秒後に画像を変更する
auto delay = DelayTime::create(0.5f);
auto changeFrame = ChangeFrame::create("変更画像");
auto actions = Vector<FiniteTimeAction*>();
actions.add(delay);
actions.add(changeFrame);
auto sequence = Sequence::create(actions);
// もとからある画像にアクションを設定
sprite->runAction(sequence);
Animationというクラスもあるよ
上のはSpriteを直接変える方法ですが、単純にずっと繰り返すアニメーションを実装したいならAnimationクラスを作成して、Animateでゴニョゴニョする方が楽だったりもします。
auto cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("animation.plist");
// 画像のリストを作成
std::vector<std::string> name = {
"test1.png","test2.png","test3.png"
};
auto animation = Animation::create();
for(auto str : name) {
animation->addSpriteFrame(cache->getSpriteFrameByName(str));
}
// 1つのアニメーション周期
animation->setDelayPerUnit(0.5f);
// 終わった後1フレームに戻すかどうか
animation->setRestoreOriginalFrame(true);
// 繰り返しアクションを行う
sprite->runAction(RepeatForever::create(Animate::create(animation)));
上記のようにアニメーションの実装も結構簡単にできるんですが、
ちょっと変えたいだけというような時には直接Spriteの画像を変更するのもアリかなと思います。
