Invalid Native Object - event listener

I am testing out switching scenes. I created a very simply start screen with a game title and one button that the player will press to switch to the main scene.

The start screen:

var StartScreenLayer = cc.Layer.extend({
sprite: null,
ctor: function () {

    this._super();
    var size = cc.winSize;
    var pos = [480, 360];
    ship = CreateSprite("res/StartScreen.png", pos[0], pos[1], this);
    start_Button = CreateSprite("res/Button_Fire.png", 65, 60, this);
    start_Button.setTag(101);
    cc.eventManager.addListener(listener_TouchStartScreen, start_Button);
    return true;
},

});

In the listener added to the start screen, I have the following to switch the scene:

onTouchEnded: function (touch, event) {
        var target = event.getCurrentTarget();

        switch (target.getTag()) {
            case 101:
                var scene = cc.Scene.create();
                var layer = new MainGameLayer();
                scene.addChild(layer);
                cc.Director.getInstance().replaceScene(scene);
                break;
        };


        return true;
    }

unfortunately, the main scene crashes when I attempt to add the main scene listener:

cc.eventManager.addListener(listener_Keyboard, mainscene.node);

crasher with the following error:

jsb: ERROR: File ..\auto\jsb_cocos2dx_auto.cpp: Line: 19045, Function: js_cocos2dx_EventDispatcher_addEventListenerWithSceneGraphPriority
Invalid Native Object
JS: C:/Online/Cocos/CocosProjects/Cocos_Test_1/frameworks/runtime-src/proj.win32/../../..//script/jsb_cocos2d.js:1455:Error: Invalid Native Object

from my undestanding this sort of error occurs when an object is released natively, but I can’t figure out which object would have been released. Any help would be appreciated. Thanks

1 Like

You are correct that Invalid Native Object means it has been released natively. This often happens when people use the create method for an Cocos object and don’t add it to the scene or retain it.

What is your code for creating listener_Keyboard and mainscene.node? If one or both of those were not added to your scene before the function they were created in ended, it’s likely that is your problem.

Here is the constructor for the main scene. I removed some sprite creation code and the mobile listeners to keep it brief.

var MainGameLayer = cc.Layer.extend({
    sprite:null,
    ctor:function () {
        
        this._super();
        var size = cc.winSize;
        var mainscene = ccs.load(res.MainScene_json);
        this.addChild(mainscene.node);
        this.scheduleUpdate();

        if (cc.sys.isMobile) {
           // deleted for brevity
        } else {
            cc.eventManager.addListener(listener_Keyboard, mainscene.node);
        }

        return true;
    },
    update: function (dt) {
        FrameUpdate(dt, this); 
    },
    
});

Here is the code for listener_Keyboard

var listener_Keyboard = cc.EventListener.create({
    event: cc.EventListener.KEYBOARD,
    onKeyPressed: function (keyCode, event) {
        if (keyCode == cc.KEY.space) {
            PressFire();
        } else if (keyCode == cc.KEY.left) {
            MoveShipLeft();
        } else if (keyCode == cc.KEY.right) {
            MoveShipRight();
        }
    }
});

Please note that if I set the MainGameLayer to be the active layer on start, that layer runs correctly.

In other words, extending my scene like this runs the main layer correctly

var CocosTestScene = cc.Scene.extend({
    onEnter:function () {
        this._super();
        var layer = new MainGameLayer();
        this.addChild(layer);
    }
});

Thanks

My guess is that because you don’t immediately add listener_Keyboard to the event manager, or retain it, it is being freed before you try to use it. If you set this scene as the active scene on start then it is probably added to the event manager before it has a chance to be released.

You either need to call listener_Keyboard.retain() immediately after creating it, or you need to create the listener inside MainGameLayer's ctor instead.

retaining the listener_Keyboard fixes this for Windows desktop and Android. Web still doesn’t process, but I’ll keep poking around to see if I can figure out what I missed. thanks

More Info

the Web app is failing on this call:

cc.Director.getInstance().replaceScene(scene);

in the onTouchEnded function

onTouchEnded: function (touch, event) {
        var scene = cc.Scene.create();
        var layer = new MainGameLayer();
        scene.addChild(layer);
        cc.Director.getInstance().replaceScene(scene);  // fails here
        return true;
    }

Moving the listener creation into the ctor yields the same result

I’m stumped. It’s working correctly in Windows and Android, but not the web.

Could the way I am initializing the original scene be contributing to the issue?

var CocosTestScene = cc.Scene.extend({
    onEnter:function () {
        this._super();
        var layer = new StartScreenLayer();
        this.addChild(layer);
    }
});

What error are you getting?

No error at all. It just simply doesn’t replace the scene.

Execution does not hang. I placed a sound in the constructor of the MainGameLayer and it plays every time I click on the StartScreenLayer.

In onTouchEnded, if you comment out the line making the new MainGameLayer and comment out the line adding the layer to the scene, does it change scene?

i.e.

onTouchEnded: function (touch, event) {
   var scene = cc.Scene.create();
   // var layer = new MainGameLayer();
   // scene.addChild(layer);
   cc.Director.getInstance().replaceScene(scene);
   return true;
}

Windows/Android: commenting out those lines causes the StartScreen scene to disappear, but the MainGame does not replace it, the screen goes black

Web: commenting out those lines does not change the scene. the StartScreen remains

Ok, I cleared my browser cache and am getting the same behavior, but I now get the following error in the Browser Console when I attempt to switch scenes:

TypeError: cc.Director.getInstance is not a function

replacing

onTouchEnded: function (touch, event) {
        var scene = cc.Scene.create();
        var layer = new MainGameLayer();
        scene.addChild(layer);
        cc.Director.getInstance().replaceScene(scene);  // fails here
        return true;
    }

with

onTouchEnded: function (touch, event) {

        var scene = cc.Scene.create();
        var layer = new MainGameLayer();
        scene.addChild(layer);
        cc.director.runScene(scene);

        return true;
    }

fixes the issue. Not sure why considering the singleton is supported in the documentation

http://www.cocos2d-x.org/reference/html5-js/V2.2/symbols/cc.Director.html

also, replaceScene() does not work on the Web, and had to be replaced with runScene()