Update nodes in the Update cycle

I have the following code. It’s creating random bars that look like the old Spectrum loading screen. I’ve got a feeling that I’m doing something wrong, something that I shouldn’t be doing through the update method. Because I get random crashes on this screen.

void panel_splashscreen::update(float delta)
{
uipanel::update(delta);

if(chilli::randomno::instance.chance(0.5) || loading_complete)
{
    return;
}

removeLoadingBars();

auto barColor = Color4B(_clrDarkBlue);

int c=chilli::randomno::instance.get()&1;
f32 y=0;
f32 width = getContentSize().width;
while(true)
{
    f32 height = chilli::randomno::instance.get(RES(2), RES(20));

    if(c==0)
    {
        auto layer = LayerColor::create(barColor, width, height);
        layer->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT);
        layer->setPosition(0, y);
        layer->setLocalZOrder(ZORDER_FAR-1);
        uihelper::AddTopLeft(this,layer,0,y);
        loading_bars.pushBack(layer);
    }
    c = (c+1)&1;

    y+=height;
    if(y>getContentSize().height)
    {
        break;
    }
}

}

Try inside cocos ui thread, that might solve your crash issue.

Isn’t the update already called inside the UI thread? Or should I be doing the work somewhere else like OnEnter?

You should probably create all the layers and then just change their sizes on update.
It looks like may a bad access through invalid or null pointer?

Does it occur on the first pass through update or does this happen after a while?
Do you mean random that uihelper::AddTopLeft(this,layer,0,y); succeeds some of the time, or is it only random because the variable c is not often 0?

Set a breakpoint in AddTopLeft, and follow it down until inside resume() and hopefully you can see more into why it’s crashing, it’s either dereferencing a null/invalid pointer or allocation is failing if you’re using too much memory (maybe android emulator small ram?).

I’ll try to go take a peek into onEnter/resume internals, but it’d be strange if there’s a bug in there, so it’s likely either a bad allocation or the layers are not being retained and are somehow invalid pointers.

… OH …

so you may want to check if (layer) or if (layer != nullptr) as well.

It works the majority of the time on iOS and OSX, just barfs every now and then. But while debugging (something else) on android I noticed that it would do it for a number of runs on the bounce and then work for a while.

Why would layer ever be null? if it’s null then it might as well crash hard because allocations failing is a memory problem etc etc…

Anyway, just trying to work out the rules… should I or should I not create/delete Nodes in the Update?

Yeah, it should never be null, unless an allocation issue occurred. It was mostly just a quick thought for you to at least check it while in debugger, or you drop in an assert.

(I just have no idea of any other issue besides bad allocation that would occur at random like you’re explaining, unless something else is stomping on memory for some reason? could be an array overflow or something)

You can definitely create Nodes and addChild during update.

You could create all LayerColors up front and then change their width and height on update if there’s some weird issue where you’re not running out of memory, but you’re hitting some sort of memory address overflow? (I’m just throwing ideas out like spaghetti on a wall).

If you want to keep your code and set both width and height then you could create enough for each vertical pixel and just hide them all first instead of removing them. Or you could create enough for every vertical pixel and update height’s worth of them to the same width as if they were all one Layer. Not sure if that made sense, but I’m used to preferring create up-front and then re-use instead of creating and removing every frame.

You could also use Sprite instead of LayerColor?, since I believe every Layer-derived node is by default not batched? I could be wrong on that, but I do know we use 1x1 or 2x2 white pixel .png for any colored rectangles on screen after LayerColor didn’t seem to perform well.
Edit: oh, and you should be able to use setColor to any color.
(You’d use setTextureRect to change it to any Size on screen.)

Definitely a strange bug from across the internet.

Hope you’re able to figure it out without too much head-ache.

Cheers - many thanks for the throwing ideas around - sometimes you just need to hear things… so much appreciated.

The tip on LayerColor / Sprite is a general well received tip thanks.

The fact that I can get a more consistent crash on Android at least means I have something to play with. But knowing that I can create nodes during update at least allows me to focus elsewhere.

Quick other thoughts:

1 - How are you removing the SplashScreen panel?

Maybe it’s the splash screen (ie: this) that becomes invalid?
It’s tough to know what’s going on with only the code you shared.
You could try to assert or even printf the address of this and layer in your code and also the this in Node::resume() in order to determine which one is causing the segfault.

2 - It sounds like it’s not only specific devices, correct? Only ask because I’ve had crashes on only one device (or a set of devices with same chips) with a faulty graphics driver, or whatever.

It is looking more like memory use/corruption… I fixed an issue that I was working on yesterday, I while I was working on it (on android) that’s when I was seeing the biggest issue. Since I fixed that I’ve not seen it since on Android.

I am wondering if there is something to do with the game memory state at launch… if device memory is not good when the game launches it randomly crashes…but the runs after that are fine. ???

I’m sure it’s possible for previous state of the system to cause first-run crash and then your game uses enough memory that gets cleared out and reset after it crashes that first time to enable it to run smoothly after, but that’d be strange from my experience just because the system should prepare the memory for your game, but as always with Android/PC/Mac (and more so now in iOS) there can be many things running in the background that could cause issues unrelated to your game.

Definitely an odd bug for sure, usually you can trigger crashes with the right steps … though it does sound like you fixed something that was helping cause the issue? Anyway, hopefully you’ve mostly eliminated the issue for now so you can progress onward.

Thanks for the discussion… I’ve changed this code now anyway… not sure what I was thinking when I originally wrote it… there is create/delete outside of initialise and I’m only using one Node for the whole loading bars instead of potentially hundreds!!!

void panel_splashscreen::update(float delta)
{
    f32 y=0;
    f32 width = getContentSize().width;
    int c=chilli::randomno::instance.get()&1;

    uipanel::update(delta);

    loadingProgress->clear();

    if(loadingProgress->isVisible()) {
        loadingProgress->drawSolidRect(Vec2::ZERO, Vec2(loadingWidth,loadingHeight), Color4F(_clrDarkYellow) );
        loadingProgress->drawSolidRect(Vec2::ZERO, Vec2(loadingWidth*MIN(1.0f,currentProgress),loadingHeight), Color4F(_clrDarkBlue) );
    }

    if(chilli::randomno::instance.chance(0.5)) {
        return;
    }
    
    loadingBars->clear();
    
    if(loadingComplete) {
        return;
    }

    while(y<getContentSize().height)
    {
        f32 height = chilli::randomno::instance.get(RES(2), RES(20));

        if(c==0) {
            loadingBars->drawSolidRect(Vec2(0,y), Vec2(0+width, y+height), Color4F(_clrDarkBlue) );
        }
        c = (c+1)&1;

        y+=height;
    }
}
1 Like

Ah, I don’t use DrawNode that often, and thus forgot to suggest it, but glad you figure out a good use for it.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.