cocos2d-x: I'm having a EXC_BAD_ACCESS - c++

I'm having a EXC_BAD_ACCESS (code=1 ...) sometimes code=2 using cocos2d-x.
Getting this error when I do for example:
std::cout << this->getChildrenCount() << std::endl;
std::cout << this->getChildrenCount() << std::endl;
On this exact code, the first line works but the second gives me the error.
I was trying to reach all the children so I could do a function like "hey, fade all objects to this value", since they're inside a class extending CCNode.
void BasicElement::fadeTo(int opacity, float duration)
{
CCActionInterval* actionTo = CCFadeTo::create(duration, opacity);
CCArray* pChildren = this->getChildren();
if (pChildren && pChildren->count() > 0)
{
CCObject* pObject = NULL;
CCARRAY_FOREACH(pChildren, pObject)
{
CCSprite* pChild = (CCSprite*) pObject;
pChild->stopAllActions();
pChild->runAction(actionTo);
}
}
}
Already tried to do my own CCArray adding the elements that I addChild but... Same problems persist.
Can anyone help me with this?

You cannot use same CCAction on more than one sprite. For every sprite you should create new action. So you should create the action inside the loop.
void BasicElement::fadeTo(int opacity, float duration){
CCArray* pChildren = this->getChildren();
if (pChildren && pChildren->count() > 0)
{
CCObject* pObject = NULL;
CCARRAY_FOREACH(pChildren, pObject)
{
CCSprite* pChild = (CCSprite*) pObject;
pChild->stopAllActions();
//Create the action here
CCActionInterval* actionTo = CCFadeTo::create(duration, opacity);
pChild->runAction(actionTo);
}
}
}

Related

Why setPosition work in some condition but doesn't work in other condition?

i make a game let's say ThrowBall, the Player can pick up the ball spawned and throw it into target get the score added then the ball return it's position and repeat. The problem is when Ball dragged by Player (i make the Ball as child of Player) into target, the Ball return it's position correctly into desired position, but the odd happens when it collided after i send the Ball into target by applying impulse it won't return the ball into desired position, why is this happening?
i'm running this game for android, i'm running this code in VS'17 using cocos2d-x-3.17. I tried changing impulse into force, moveby. I tried making the ball stop (setVelocity to zero before setPosition). I tried changing Point into Vect, vec2. I tried to break point debug, the code do read setPosition but do nothing.
GameScene.cpp
bool GameScene::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto pickupListener = EventListenerPhysicsContact::create();
pickupListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(pickupListener, this);
return true;
}
bool GameScene::onContactBegin(cocos2d::PhysicsContact &contact)
{
PhysicsBody *a = contact.getShapeA()->getBody();
PhysicsBody *b = contact.getShapeB()->getBody();
if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
// make the ball follow Player
isfollow = true;
}
else if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && TARGET_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && TARGET_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
isfollow = false;
// add score
score++;
__String *tempScore = __String::createWithFormat("%i", score);
scoreLabel->setString(tempScore->getCString());
// return spawn ball
ball->returnPos();
return false;
}
void GameScene::throwBall() {
if (isfollow == true) {
isfollow = false;
ball->getSprite()->getPhysicsBody()->applyImpulse(Vec2(100000, 100000));
}
}
Ball.h
class Ball
{
public:
Ball(cocos2d::Layer *layer);
cocos2d::Sprite *getSprite() { return randomSpawn; };
void returnPos();
private:
cocos2d::Size visibleSize;
cocos2d::Vec2 origin;
cocos2d::Sprite *randomSpawn;
};
Ball.cpp
Ball::Ball(cocos2d::Layer *layer)
{
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
randomSpawn = Sprite::create("res/ball.png");
randomSpawn->setPosition(Vec2(400, 80));
auto randomBallBody = PhysicsBody::createCircle(randomSpawn->getContentSize().width / 2);
randomBallBody->setCollisionBitmask(BALL_COLLISION_BITMASK);
randomBallBody->setContactTestBitmask(true);
randomBallBody->setGravityEnable(false);
randomSpawn->setPhysicsBody(randomBallBody);
layer->addChild(randomSpawn);
}
void Ball::returnPos()
{
randomSpawn->setPosition(Vec2(400, 80));
}
i want to make the object (Ball) return position when collided into Target and repeat. i'm sorry if the format is a mess, i'm new here, also it's not my full code, it's actually works fine i can run it, but only the setPosition won't work

Synchronize functions in Cocos2d-x?

I use cocos2d-x-3.13...
I'm just starting out but I've had problems with something: I have a number of sprites in a vector and every second I move them to each position, the problem arises when I want to delete them, since I have a function that moves them With a loop:
HelloWorldScene.cpp
bool HelloWorld::init() {
...
_enemies.reserve(15);
for (unsigned i = 0; i < 5; i++) {
//Here I create the sprites, and I activate the physics in each one :p
_enemies.push_back(sprite);
}
...
/*
This event checks for each collision, what I do is find the sprite
in my vector and then delete the sprite with "removeFromParent ()",
then delete the sprite from my vector. it's good, no? :v
*/
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = [=](PhysicsContact &contact) {
auto a = contact.getShapeA()->getBody(); //bullet
auto b = contact.getShapeB()->getBody(); //enemy
if (a->getCollisionBitmask() == 2 && b->getCollisionBitmask() == 2) {
a->getNode()->removeFromParent();
auto f = std::find(_enemies.begin(), _enemies.end(), ((cocos2d::Sprite*)b->getNode()));
if (f != _enemies.end()) {
_enemies.at(std::distance(_enemies.begin(), f))->removeFromParent();
_enemies.erase(f);
}
}
return true;
};
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
...
this->schedule(schedule_selector(HelloWorld::moveEnemies), 1.0f);
...
}
void HelloWorld::moveEnemies(float f) {
for (unsigned i = 0; i < _enemies.size(); i++)
{
cocos2d::Vec2 pos = _enemies.at(i)->getPosition(); //This line throws the exception
_enemies.at(i)->setPosition(pos.x + 5, pos.y);
}
}
I have an event that when I press a key, creates a sprite and if it collides with one of the enemies just disappears, everything is fine here, very simple, but when you put the "moveEnemies" function and the sheduler everything is complicated. .. by shooting at one of the enemies quickly throws me an exception (Visual Studio 2015):
"Access violation when reading location 0xDDDDDE35"
I think this occurs because is the vector manipulated at the same time by the event and the "moveEnemies" function?
Is it possible to solve this? Or am I doing something wrong? I would appreciate anyone guiding me ...
I found a simple solution, it is possible that someone will serve you ...
We simply add a scheduler to each sprite and the vector would become obsolete.
auto enemy = cocos2d::Sprite::createWithSpriteFrameName("x.png");
enemy->setPosition(x, y);
enemy->setScale(0.5, 0.5);
//bla bla bla...
enemy->schedule([enemy](float x) {
//Code
auto pos = enemy->getPosition();
enemy->setPosition(pos.x + 10, pos.y);
}, 2.0f, "tag");
It is assumed that deleting the sprite in the event would eliminate the scheduler ...

How do I restore the sprite into original image after swapped it to another one in coco2dx?

In my gaming context, the sprite is a smiling baby, when the baby is touched, the current sprite image changed to a crying baby, then after 3 seconds of crying sound effect ended, the sprite will restore to the smiling baby image.
My problem is
How to swap back with the previous image?
I have changed the smiling baby to a crying one, but i have no idea how could I swap it with the original smiling one?
How to ensure one click at one time?
Each time the baby sprite is touched, the audio will start to play which is not ideal, because I hope the event function is only called after the previous event process is finished.
here is my code, and thank you a lot!
bool HelloWorld::init()
{
// 1. super init first
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//add background scene
auto backgroundSprite = Sprite :: create("scene001.jpg");
backgroundSprite->setAnchorPoint(Vec2(0,0));
backgroundSprite->setScaleX((visibleSize.width / backgroundSprite->getContentSize().width) * 1);
backgroundSprite->setScaleY((visibleSize.height / backgroundSprite->getContentSize().height) * 1);
addChild(backgroundSprite);
//add smileBaby sprite
auto smileBabySprite = Sprite :: create("figure001.png");
smileBabySprite -> setPosition(Vec2(500,400));
addChild(smileBabySprite);
//add crying audio
auto audio = CocosDenshion::SimpleAudioEngine::getInstance();
auto babyListener = EventListenerTouchOneByOne::create();
babyListener -> onTouchBegan = [smileBabySprite, audio](Touch* touch, Event* event)
{
//change smileBaby sprite to cryingBaby sprite
smileBabySprite->setTexture(CCTextureCache::sharedTextureCache()->addImage("figure002.png"));
audio -> playEffect("babycry.mp3",false,1.0f,1.0f,1.0f);
return true;
};
babyListener -> onTouchEnded=[smileBabySprite](Touch* touch, Event* event )
{
};
_eventDispatcher -> addEventListenerWithSceneGraphPriority(babyListener, this);
return true;
}
What you want is to keep state about if the baby is crying or not. The best thing to do is keep this logic in a custom Node subclass.
Here is some (almost pseudo-)code to get you started:
Baby.h:
#pragma once
#include "cocos2d.h"
class Baby : public cocos2d::Node
{
private:
cocos2d::Sprite *_sprite; // Weak reference
bool _crying;
float _cryingTime;
public:
CREATE_FUNC(Baby);
protected:
virtual bool init() override;
virtual void update(float delta) override;
public:
void touched();
bool isInside(cocos2d::Touch *touch) const
protected:
void setSprite();
};
Baby.cpp:
#include "Baby.h"
USING_NS_CC;
bool Baby::init()
{
if (!Node::init())
return false;
_crying = false;
setSprite();
scheduleUpdate();
return true;
}
void Baby::update(float delta)
{
Node::update(delta);
if (_crying) {
_cryingTime -= delta;
if (_cryingTime <= 0.0f) {
_crying = false;
setSprite();
}
}
}
void Baby::touched()
{
if (_crying)
return; // Already crying
_crying = true;
_cryingTime = 3.0f; // Length of audio, I guess?
setSprite();
// Start crying sound here
}
bool Baby::isInside(Touch *touch) const
{
Vec2 locationInNode = _sprite->convertToNodeSpace(touch->getLocation());
Size size = _sprite->getContentSize();
Rect rect = Rect(0.0f, 0.0f, size.width, size.height);
return rect.containsPoint(locationInNode);
}
void Baby::setSprite()
{
if (_sprite)
_sprite->removeFromParent();
_sprite = Sprite::initWithFile(_crying ? "baby_crying.png" : "baby.png");
Vec2 size = getContentSize();
_sprite->setPosition(size.width * 0.5f, size.height * 0.5f);
addChild(_sprite);
}
You add the Baby node in the parent instead of the sprite, using:
_baby = Baby::create();
_baby->setPosition(Wherever);
addChild(_baby);
Where _baby is an instance variable and use the isInside() method to test if a touch event is within the bounds of the sprite and call its touched() method:
Touch *touch = ...;
if (_baby->isInside(touch)) {
_baby->touched();
}
and the Baby object will ignore the touch depending on state.

EXC_BAD_ACCESS in cocos2d-x

I'm just training cocos2d-x.
I tryed to show sprite animation,but EXC_BAD_ACCESS error showed.
I wrote code as follows.
However,when I wrote the "animation" function to the inside of "init" function ,EXC_BAD_ACCESS error didn't show.
What is wrong?
GameScene.h
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
class GameScene : public cocos2d::CCLayer
{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene();
// implement the "static node()" method manually
CREATE_FUNC(GameScene);
void animation();
cocos2d::CCSprite* pPlayer;
//スプライトを格納する領域
cocos2d::CCSpriteFrame* pSprites[12];
};
GameScene.m
bool GameScene::init()
{
if(!CCLayer::init())
{
return false;
}
//端末サイズ取得
CCSize visiblesize = CCDirector::sharedDirector()->getVisibleSize();
//背景画像
CCSprite* bgImg = CCSprite::create("pic1.jpg");
//背景画像のポジション
bgImg->setPosition(ccp(visiblesize.width / 2, visiblesize.height / 2));
//背景画像のポジションを取得
CCPoint pos = bgImg->getPosition();
//===============================================================================
// ボタンイベント作成
//ボタンイベント追加
CCMenuItemImage *tapitem = CCMenuItemImage::create("animButton.png", "animButton.png", this, menu_selector(GameScene::animation));
CCMenu* tapMenu = CCMenu::create(tapitem, NULL);
tapMenu->setPosition(ccp(bgImg->convertToNodeSpace(pos).x, bgImg->convertToNodeSpace(pos).y));
//ボタン画像設置
bgImg->addChild(tapMenu);
//背景画像設置
this->addChild(bgImg);
cocos2d::CCSpriteFrame* pSprites[12];
const int WIDTH_SIZE = 96; //1つのスプライトの幅
const int HEIGHT_SIZE = 64; //1つのスプライトの高さ
//●アトラスから矩形切り出し、スプライト領域に格納.アニメーション画像を扱いたい時は、pSpriteから取り出してください。
for(int y = 0; y < 4; y++){
for(int x = 0; x < 3; x++){
CCRect rect(x * WIDTH_SIZE, y * HEIGHT_SIZE,WIDTH_SIZE,HEIGHT_SIZE);
pSprites[y * 3 + x] = CCSpriteFrame::create("texture1.png",rect);
}
}
// プレイヤースプライトを生成
pPlayer= CCSprite::create("texture1.png", CCRectMake(0, 64, 96, 64));
// プレイヤーのポジション
pPlayer->setPosition(ccp(100,100));
//プレイヤーをシーンに登録して
bgImg->addChild(pPlayer);
return true;
}
void GameScene::animation()
{
//移動先の指定
CCMoveTo* move = CCMoveTo::create(1.8, ccp(200, 100));
//===============================================
// アニメーションの作成
CCAnimation* animation = CCAnimation::create();
for(int i=3;i<6;i++){
animation->addSpriteFrame(pSprites[i]);
}
//アニメーションの設定:1コマ0.1秒で切り替える
animation->setDelayPerUnit(0.1);
//アニメーションの設定:6回ループさせる
animation->setLoops(6);
CCRepeatForever *pAction = CCRepeatForever::create( CCAnimate::create(animation) );
// 作成したアニメーションを実行
pPlayer->runAction(pAction);
pPlayer->runAction(move);
}
well, it didn't let me leave a comment as i don't have 50 rep... where exactly is this error coming up? The line i mean?
Is it this code piece?
for(int i=3;i<6;i++){
animation->addSpriteFrame(pSprites[i]);
}
if yes, then please make sure that the "pSprites[i]" hasn't been released... If that is the case please create it with "new" and then perform a clean up by yourself.
The reason this could be happening is because there is no one referencing these sprites inside the "init" function... and when the flow comes out of "init" function, these values get released (as they are created with CREATE which sets autorelease by default)
Again, this is my assumption, looking at the code...
do give your feedback!

How to make a sprite jump like a frog in cocos2d-x ios game using c++

I am trying to make a sprite as a frog which will come from the top of the screen and will go downwards to the bottom at y axis =0.Its working fine as a normal CCMoveTo but i want that after a jump the frog should rest for 1 second then again jump.Some kind of delay in moving.Can anyone tell me with this.I am attaching my code also.
my frog animations are from fly1.png to fly5.png.I just want a delay after each move or we can say that I just want to call the CCMove after 1 second delay each time until the frog reaches the y axis=0
Any help will be appreciated.Thanks
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
using namespace cocos2d;
using namespace CocosDenshion;
CCScene* HelloWorld::scene()
{
CCScene *scene = CCScene::create();
HelloWorld *layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !CCLayer::init() )
{
return false;
}
CCSize winSize=CCDirector::sharedDirector()->getWinSize();
_bgNode = CCNode::create();
_bgNode->setPosition(ccp(winSize.width/2, winSize.height/2));
this->addChild(_bgNode, -1);
_bgSprite = CCSprite::create("bg_2.jpg");
_bgNode->addChild(_bgSprite);
float rX = winSize.width/_bgSprite->getContentSize().width;
float rY = winSize.height/_bgSprite->getContentSize().height;
_bgNode->setScaleX(rX);
_bgNode->setScaleY(rY);
z=CCSprite::create("fly1.png");
z->setScaleX(rX);
z->setScaleY(rY);
z->setPosition(ccp(winSize.width/2,winSize.height+1));
this->addChild(z);
CCAction *a=CCRepeatForever::create(HelloWorld::getAnimationWithFrames(1,5));
z->runAction(a);
z->runAction(CCSequence::create(CCMoveTo::create(2.0, ccp(winSize.width/2, 0)), CCCallFuncN::create(this, callfuncN_selector(HelloWorld::setInvisible)), NULL));
return true;
}
cocos2d::CCAnimate* HelloWorld::getAnimationWithFrames(int from, int to)
{
CCArray* frames = CCArray::create();
for (int i = from; i <= to; i++)
{
CCString *str = CCString::createWithFormat("fly2%d.png", i);
CCSpriteFrame *f = CCSpriteFrame::create(str->getCString(), CCRect(0,0,256,400));
frames->addObject(f);
}
//(frames,speedofmovementofanimation);
CCAnimation *animation = CCAnimation::createWithSpriteFrames(frames,0.15f);
CCAnimate *a = CCAnimate::create(animation);
return a;
}
void HelloWorld::setInvisible()
{
this->removeChild(z,true);
}
Firstly, you have to create a frogJump() function. Then,in frogJump() function add the following code:
void HelloWorld::frogJump()
{
CCJumpTo* jumpTo = CCJumpTo::create(1,ccp(x/6,y/8),y/1.2f,1);
z->runAction(jumpTo);
}
Then, in the init() function add the following line:
this->scheduleOnce(SEL_SCHEDULE(&HelloWorld::frogJump),0);
this->schedule(SEL_SCHEDULE(&HelloWorld::frogJump),2);