cocos2dx 3.x schedule error - c++

When I try implement add one node per n seconds, the procedure crashes.
if I just run runBlock(0.0f), the procedure runs normally.
This is my code
MainLayer.cpp
bool MainLayer::init(){
if (!Layer::init()){
return false;
}
block_array = new std::vector<block*>();
Size visibleSize = Director::getInstance()->getVisibleSize();
auto body = PhysicsBody::createEdgeBox(visibleSize,PHYSICSBODY_MATERIAL_DEFAULT, 3.0);
body->setCategoryBitmask(0x0001);
body->setCollisionBitmask(0x0001);
body->setContactTestBitmask(0x0000);
body->getShape(0)->setRestitution(0.0);
auto edgeNode = Node::create();
edgeNode->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
edgeNode->setPhysicsBody(body);
this->addChild(edgeNode);
auto sp = Sprite::create("CloseNormal.png");
sp->setTag(PLAYER);
auto sp_body = PhysicsBody::createCircle(sp->getContentSize().width / 2);
sp_body->setCategoryBitmask(0x003);
sp_body->setCollisionBitmask(0x003);
sp_body->setContactTestBitmask(0x001);
sp->setPhysicsBody(sp_body);
sp->setPosition(visibleSize / 2);
this->addChild(sp);
initBlock();
/**
When run function "runBlock", process crash!!
*/
schedule(schedule_selector(MainLayer::runBlock), 5.0f, CC_REPEAT_FOREVER, 0.0f);
//runBlock(0.0f); if just run it, everything is right
return true;
}
void MainLayer::initBlock(){
block_array->push_back(new block1()); //block is other class, it has no problem
block_array->push_back(new block2());
block_array->push_back(new block3());
}
void MainLayer::runBlock(float dt){
Size size = Director::getInstance()->getVisibleSize();
int len = block_array->size();
block* bl;
do
{
int rand = floor(CCRANDOM_0_1()*len);
if (rand == len){
rand -= 1;
}
bl = (*block_array)[rand];
} while (bl->node->getParent()); //Crash in here!!!!!
bl->come(Vec2(size.width*1.5, 0));
this->addChild(bl->node);
}
I use VS2013. The error info is
Without exception handling in 0x009D5402(in test.exe) 0xC0000005: Access violation when reading location 0xFEEF0012
I have debug. "bl->node" is allocated memory. So I don't think it is NULL pointer error. However, I don't know what reason cause the crash.
Please help me, Thanks!

After a few frames all your blocks will have parents and the while loop will never exit.
I don't really understand what it is you're trying to accomplish here, but might I suggest keeping two arrays, filling the first in initBlocks(), randomly picking one in runBlock(), processing it, and moving it to the second array.
This way you don't need the while loop, which wastes a lot of time if you keep picking a block that you've already processed.

Do it this way:
void MainLayer::runBlock(float dt)
{
Size size = Director::getInstance()->getVisibleSize();
//waiting_block_array = block_array when you initialize
if (waiting_block_array)
{
int rand = random (0, waiting_block_array.size () - 1);
addChild (waiting_block_array[rand]);
waiting_block_array[rand]->come(Vec2(size.width*1.5, 0));
this->addChild(waiting_block_array[rand]->node);
waiting_block_array.erase (waiting_block_array.begin () + rand);
}

Related

C++ Thread works fine long time but then I'm getting abort error

I have built up a procedural terrain creator using voxels. The terrain is divived in chunks, those chunks are created in a seperate, detached thread. Since I did this, there is no lag anymore because they get built in background. Everything works fine for about 2000 chunks (32*32*64), but then i get an "abort() has been called" error. The debug information looks just fine.
Enough words, here is some code:
In the Manager-constructor the Thread is initialized:
try{
m_creatorThread1 = std::thread(&ChunkManager::CreateChunk, this);
m_creatorThread1.detach();
}
catch (...){
m_work = false;
m_creatorThread1.join();
throw;
}
This is the function the thread executes:
void ChunkManager::CreateChunk(){
while (m_work){
if (!m_buildQ.empty()){
Position tmp = m_buildQ.back();
m_buildQ.pop_back();
Chunk* ctmp = new Chunk(this->m_terrain, tmp);
m_mutex.lock();
m_chunks.push_back(ctmp);
m_mutex.unlock();
}
}
}
the function that feeds the m_buildQ:
void ChunkManager::GenerateChunks(Position position){
for (int i = position.x - CHUNK_PRLD_X; i < position.x + CHUNK_PRLD_X; i++){
for (int j = position.z - CHUNK_PRLD_Z; j < position.z + CHUNK_PRLD_Z; j++){
Position chunkPos;
chunkPos.x = i *CHUNK_SIZE; chunkPos.z = j *CHUNK_SIZE;
if (!IsUsed(chunkPos)){
m_used.push_back(chunkPos);
m_buildQ.push_back(chunkPos);
}
}
}
}
and finally the function that renders the chunks:
void ChunkManager::Render(){
m_mutex.lock();
for (vector<Chunk*>::iterator it = m_chunks.begin(); it != m_chunks.end(); ++it){
if (m_Frustum->CheckSphere((*it)->getPosition().x +CHUNK_SIZE/2, CHUNK_HEIGHT / 2, (*it)->getPosition().z + CHUNK_SIZE/2, CHUNK_SIZE*1.3f)){
if ((*it)->hasGraphics())
(*it)->Render();
else{
(*it)->InitializeGraphics(OpenGL);
}
}
}
m_mutex.unlock();
}
In short: Every frame there is a check if new chunks need to be loaded, if so, GenerateChunks feeds the m_buildQ vector with positions of chunks that got to be loaded. The thread runs in background and creates new chunks if something is in the buildQ. because of openGL-reasons, the VAO and VBO dont get initialized in the thread but in the renderer if needed.
As I said, everything works fine until I've spent some time in the application and thousands of chunks were created. Can anyone find the mistake?
Here some things of the debug:
m_chunks: size= 1392
it-ptr: points on valid chunk
thread: hnd:0x00000264 id: 0
if someone needs more debug information just tell me.

Variable inside lambda function is showing garbage value

I am using this method in a Cocos2d X game.
void OpponentNode::discard(int cardNum)
{
log("\nOpponentNode::discard <%d>\n", cardNum);
for (int i = 0; i < vecOpponentHand.size(); i++)
{
if (vecOpponentHand.at(i) == cardNum)
{
vecOpponentHand.erase(vecOpponentHand.begin() + i);
break;
}
}
CardSprite * discardedCard;
for (int i = 0; i < vecOpponentCards.size(); i++)
{
if (vecOpponentCards.at(i)->getTag() == cardNum)
{
discardedCard = vecOpponentCards.at(i);
vecOpponentCards.erase(vecOpponentCards.begin() + i);
break;
}
}
log("\nOpponentNode::discard <%d>\n", cardNum);
discardedCard->makeFaceUp();
RotateTo * rotate = RotateTo::create(0.4 * SPEED_MULTIPLIER, 0);
MoveTo * move = MoveTo::create(0.4 * SPEED_MULTIPLIER,
origin + Vec2(visibleSize.width * 0.75, visibleSize.height * 0.6));
Spawn * spawn = Spawn::create(rotate, move, NULL);
CallFunc * callFunc = CallFunc::create(
[&]()
{
log("\nOpponentNode::discard <%d>\n", cardNum); //this one shows garbage/different value
if (delegate)
{
delegate->opponentNodeDidFinishDiscard(this, cardNum);
}
this->removeChild(discardedCard);
});
discardedCard->runAction(Sequence::create(spawn, callFunc, NULL));
log("\nOpponentNode::discard <%d>\n", cardNum);
}
Strangely, when I log the integer cardNum like above, I get different value from the log inside the lambda function. For example, I get "OpponentNode::discard <402>" from the top 2 logs and the bottom most log but get "OpponentNode::discard <64>" from the log inside the lambda function.
Other points:
The lambda block is executed last.
I mostly get values like 64 or garbage values like -15493456.
My guess is the integer cardNum is getting deallocated before the execution. Can anyone point me to the right direction?
You're capturing a reference to the cardNum parameter. I would think you want to capture that one by value.
It's not clear to me what delegate is. Assuming it's a class member then I think you just need [this, discardedCard, cardNum]. Which you could abbreviate to just [=], although I think the explicit one is clearer.

C++ Debug assertion failed, using Windows.h mutex

I have a problem caused by this code:
char KernelFS::mount(Partition* part) {
WaitForSingleObject(mutexFS,INFINITE);
int pos;
for(pos=0; pos<26; pos++)
if(mountedPartitions[pos] == 0)
break;
if(pos < 26) {
mountedPartitions[pos] = part;
bitVectors[pos] = new BitVector(part);
fileEvidention[pos] = new ListHandler();
openedFiles[pos] = 0;
forbidOpening[pos] = false;
ReleaseMutex(mutexFS);
return intToChar(pos);
}
else {
ReleaseMutex(mutexFS);
return '0';
}
}
and
char KernelFS::format(char part){
WaitForSingleObject(mutexFS,INFINITE);
forbidOpening[charToInt(part)] = true;
ReleaseMutex(mutexFS);
while(openedFiles[charToInt(part)]>0)
WaitForSingleObject(unmountSem,INFINITE);
WaitForSingleObject(mutexFS,INFINITE);
// write fresh bit vector to cluster 0 of partition
bitVectors[charToInt(part)]->formatBitVector();
openedFiles[charToInt(part)] = 0;
forbidOpening[charToInt(part)] = false;
delete fileEvidention; //!!***!!
fileEvidention[charToInt(part)] = new ListHandler();
// some other stuff, irrelevant
ReleaseMutex(mutexFS);
return 1;
}
There are 3 thread executing, 1 is blocked and two are running through this code;
they first call mount, then format (each has its own argument Partition object, p1 and p2).
The first time mount is called, it always goes through - then there is an assertion failure at random during one of the next calls of mount/format by any of the two running threads.
Usually, it fails during thread 1 - it calls mount(..) completes it, then calls format(...) and fails around:
delete fileEvidention[charToInt(pos)];
(in debug mode, when I reach this instruction, even if I try to go into with F11, there is an assertion failure)
In case it matters... this is the initialization:
char KernelFS::firstLetter = 'A'; // 'A' = 65
Partition* KernelFS::mountedPartitions[26] = {0}; // init. no partitions are mounted
BitVector* KernelFS::bitVectors[26] = {0}; // init. no partitions are mounted
bool KernelFS::forbidOpening[26] = {false};
long KernelFS::openedFiles[26] = {0};
ListHandler* KernelFS::fileEvidention[26] = {0};
HANDLE KernelFS::mutexFS = CreateMutex(0,0,0);
HANDLE KernelFS::unmountSem = CreateSemaphore(0,0,INFINITE,0);
I have never had this error before, I have no idea how to debug this nor what could cause it.
Thanks for the help, in advance.
EDIT:
when i remove the marked line of code (and ignore the memory leak) there is no assertion failure. What is this witchcraft ?
! :)
Solved. should be
delete fileEvidention[charToInt(part)];
......

Cocos2d-x: 0xC0000005: Access violation reading location 0xCDCDCDD1

everyone:
The problem is strange. I paste my code first.
void GameObjectsLayer::updateEnemy(float interval)
{
UNREFERENCED_PARAMETER(interval);
Enemy *lpEnemy = new Enemy("enemy1.png", 1, 10, 8);
lpEnemy->getSprite()->setAnchorPoint(CCPointZero);
lpEnemy->setPosition(ccp(-30, 400));
CCMoveTo *lpMoveAction = CCMoveTo::create(350.0f / ENEMY1_MOVE_SPEED, ccp(320, lpEnemy->getPosition().y));
CCCallFuncND *lpCallback = CCCallFuncND::create(lpEnemy->getSprite(), callfuncND_selector(GameObjectsLayer::removeEnemy), lpEnemy);
CCSequence *lpSeqActions = CCSequence::create(lpMoveAction, lpCallback, NULL);
this->addChild(lpEnemy->getSprite(), 10);
lpEnemy->getSprite()->runAction(lpSeqActions);
// When I set the breakpoint here, the _vEnemies is valid and the application runs well.
_vEnemies->push_back(lpEnemy);
}
void GameObjectsLayer::removeEnemy(CCNode *lpSender, void *lpParam)
{
Enemy *lpEnemy = (Enemy*)lpParam;
lpEnemy->getSprite()->stopAllActions();
this->removeChild(lpSender);
// When access the _vEnemies variable here, the exception occurs at "_vEnemies->begin()"
// I set a breakpoint here, the address of _vEnemies is invalid, but I set a breakpoint in the previous function, the _vEnemies has a valid address, what happened? I really can't comprehend the behavior. _vEnemies is the member variable of this class.
std::vector<Enemy*>::iterator iter = _vEnemies->begin();
while (iter != _vEnemies->end())
{
if (lpEnemy == *iter)
{
this->removeChild(lpEnemy->getSprite());
//delete *iter;
iter = _vEnemies->erase(iter);
continue;
}
++iter;
}
delete lpEnemy;
}
these two methods are used in two CCSchedules, which is intialized in init() method, the codes are below:
bool GameObjectsLayer::init()
{
bool bRet = false;
do
{
/* not important, omit them */
this->schedule(schedule_selector(GameObjectsLayer::updateEnemy), 5.0f);
this->schedule(schedule_selector(GameObjectsLayer::enemyShoot), 1.0f);
scheduleUpdate();
bRet = true;
}
while (0);
return bRet;
}
I got a head-ache. I don't know what happened. The version of my cocos2d-x is 2.1.5, and IDE is VS2012. Thanks for help..
Well, this is an old one, but for anyone who might stumble here :
The problem seems to be in this line
CCCallFuncND *lpCallback = CCCallFuncND::create(lpEnemy->getSprite(), callfuncND_selector(GameObjectsLayer::removeEnemy), lpEnemy);
The signature for this (from docs) is
static CCCallFuncND* create ( CCObject *pSelectorTarget,
SEL_CallFuncND selector,
void * d
)
*pSelectorTarget is the object on which the selector is called. So in this example it should be this instead of lpEnemy->getSprite().
Frankly, It seems a little strange to me that it didn't crash earlier.

Is it possible to create a std::map of *CCAnimation objects?

They seem to all get autoreleased the moment I create them =s
void SceneView::createAnimation(KillerRabbit* killerRabbit, std::string animation) {
CCArray* animFrames = CCArray::createWithCapacity(15);
int first = std::stoi(killerRabbit->spriteSheetMap[animation]["FIRST"]);
int last = std::stoi(killerRabbit->spriteSheetMap[animation]["LAST"]);
char str[100] = {0};
for (int i = first; i <= last; i++) {
// Obtain frames by alias name
sprintf(str, (killerRabbit->spriteSheetMap[animation]["KEY"]+"[%d].png").c_str(), i);
CCSpriteFrame* frame = sharedSpriteFrameCache->spriteFrameByName(str);
animFrames->addObject(frame);
}
spriteAnimationsMap[killerRabbit->spriteName][animation] = CCAnimation::createWithSpriteFrames(animFrames, 0.1f);
// 14 frames * 1sec = 14 seconds
rabbitSprites[killerRabbit->spriteName][animation]->
runAction(CCRepeatForever::create(CCAnimate::create(spriteAnimationsMap[killerRabbit->spriteName][animation])));
}
If I omit this part of the code:
rabbitSprites[killerRabbit->spriteName][animation]->
runAction(CCRepeatForever::create(CCAnimate::create(spriteAnimationsMap[killerRabbit->spriteName][animation])));
And try to access the object in:
spriteAnimationsMap[killerRabbit->spriteName][animation]
In a later part of the code with another method, the object inside that map would have been autoreleased, how can I retain it so I can use the different animations stored in it at a later time?
Oh, silly me, I had to do this:
spriteAnimationsMap[killerRabbit->spriteName][animation]->retain();