Cocos Creator 踩坑记录


1.动态添加的脚本,脚本事件不执行。

写好了脚本XTimer,采用动态addComponent(Xtimer),但是脚本的start update都不执行。

代码如下:

var node = new cc.Node('[XTimer]')
            //调用新建的node的addComponent函数,会返回一个sprite的对象
        node.addComponent(XTimer);

 

检查发现一切正常,就连输出添加后的alert("BBBBBBBBBBBBB:" + node.active + " " + ttt.enabled); 这两个值都是ture。而且发现将XTimer拖动到场景物体上就正常,只有动态添加的不正常。

后来发现是未给node设置父节点的问题。但我想把node就在场景跟节点中,所以在节点后添加如下代码。

var scene = cc.director.getScene();
        node.setParent(scene);

OK,正常运行了。

====================================

2.getChildByName获取不到子物体。

今天发现getChildByName获取不到层次2次以上的子物体。如

var life2 = this.obj.getChildByName("dao/boxlife2");

找了很多资料才知道:

2)查找子节点一般用this.node.getChildByName(),如果子节点的层次较深,你还可以使用 cc.find("Cannon 01/Barrel/SFX", this.node)。注意,当 cc.find 只传入第一个参数时,将从场景根节点开始逐级查找,如:cc.find("Canvas/Menu/Back");
如上所述,getChildByName只能查找以及目录。要查找路径还得用:var life1 = cc.find("dao/boxlife1", this.obj);
OK,2问题解决。
 
3.函数回调不是注册时的所在的对象。======================================
今天编写观察者模式,用于在UI上订阅事件,然后在战斗逻辑中触发该事件。然而发现消息函数执行了,但却并不是组成时的对象。
代码如下图:订阅者
export default class ui_page_battle extends UIBaseWindow {
    public numid: string = "-1";
    public _AwakeImpl() {
        this.numid = GUtil.GetUUID();
        GUtil.BindOnClick(this.txtBtn, this.node, "txtBtnClick", "222");
        XObserverCore.RegisterNotification(ConstDefineNotifiStr.note_mainplayerfall,this.OnGameOver);
    }

    
    public txtBtnClick(event, customEventData): void {
        
        // 这里 event 是一个 Event 对象,你可以通过 event.target 取到事件的发送节点
        var node = event.target;
        var button: cc.Button = node.getComponent(cc.Button);
        //// 这里的 customEventData 参数就等于你之前设置的 "foobar"
        ////alert("btn:" + customEventData);
        ////button.node.destroy();
        //button.node.y += 50;
        this.CreateNewPlayerToSence();
        this.txtBtn.node.active = false;
    }
    public OnGameOver(param: EventParam): void {
        this.Btn_Reset.active = true;//以这种方式注册的订阅者在这里Btn_Reset 始终为undifine,就是根本就未定义。就连此时打印numid都是undefine证明观察者管理器调用的OnGameOver函数并非注册时该函数所在的对象。这里猜测着是js的机制,因为之前绑定按钮事件居然要指定函数所在的脚步名称、节点、以及函数名称。
    }
}

这里测试了很多总方法,如果是直接

ui_page_battle.Instance.OnGameOver();的话就一切正常,再次证明了上图委托调用的猜想。这里将代码修改为在匿名函数里调用居然正常了。
export default class ui_page_battle extends UIBaseWindow {
    public numid: string = "-1";
    public _AwakeImpl() {
        this.numid = GUtil.GetUUID();
        this.InitUIObject();
        GUtil.BindOnClick(this.txtBtn, this.node, "txtBtnClick", "222");
        XObserverCore.RegisterNotification(ConstDefineNotifiStr.note_mainplayerfall, (o) => {
            this.OnGameOver(o);//改成这样就正常了
        });
        this.txtBtn.node.active = false;
    }

    public KeyDebug(o: EventParam): void {

        //alert("999999999999999999999999:" + this.numid);
    }
    public _StartOpenImpl() {

        //alert("5555555555:");
        //this.Btn_Reset.active = false;
    }
    public _UpdateImpl(dt) {
        //alert("333333333333333333333333333333:" + this.node.name + " " + this.Btn_Reset.name + " " + this.numid);
    }
    public _DestroyImpl() {
    }
    public txtBtnClick(event, customEventData): void {
        
        // 这里 event 是一个 Event 对象,你可以通过 event.target 取到事件的发送节点
        var node = event.target;
        var button: cc.Button = node.getComponent(cc.Button);
        //// 这里的 customEventData 参数就等于你之前设置的 "foobar"
        ////alert("btn:" + customEventData);
        ////button.node.destroy();
        //button.node.y += 50;
        this.CreateNewPlayerToSence();
        this.txtBtn.node.active = false;
    }
    public OnGameOver(param: EventParam): void {
        this.Btn_Reset.active = true;
    }
}

这里这个得特别注意。

附录:上面服的调用方法也可用下面这样调用:

start() {
        let self = this;//用self的方式调用就可避免undifine的问题
        cc.loader.downloader.loadSubpackage('subpackages', function (err) {
            if (err) {
                return console.error(err);
            }
            self.LoadInit();
        });
        
    }
    private LoadInit() {

            this.gameCore = new GameCore();
            this.gameCore.Register();
    }

 

3.操作符远近的问题================================

var ui: UIBaseWindow = this.GetGameIngWindow(pageName);UI不为空

        if (ui != null) {//为真

            alert("2222222222222");
            this.RemoveWindow(ui);
            ui.CloseWindow(() => {
                if (backcall != null) {
                    backcall();
                }
            });
        }
if (ui! = null) {!号和=号中建有了空格,此时条件为假

            alert("2222222222222");
            this.RemoveWindow(ui);
            ui.CloseWindow(() => {
                if (backcall != null) {
                    backcall();
                }
            });
        }

4.设置局部坐标和世界坐标

item.setPosition(pos);

当item是世界根物体时 设置的坐标就是世界坐标,如果是子物体,就是设置它的局部坐标。

这里要特别注意多个子物体嵌套时,比如A。B。C。A是世界,B是A的自物体同时是C的父物体。且B如果局部坐标不为(0,0),这时如果将C的局部坐标转换为世界坐标是无法正确的。必须一级一级向上层层转换。

 

5.委托回调时调用this里的属性是undefined的问题。

如:

public useWeaponCtrl: UseWeaponControl;
private start(){
let self = this;
        item.RegisterCollisionCall(self.OnCollisioned);
}
private OnCollisioned(layer: string, otherCollider: cc.Node) {
        var other = <cc.Node>otherCollider;
        switch (layer) {
            case "monster":
                var otherCtrl: IPlayerControl = other.getComponent(IPlayerControl);
                console.log("7777777777777777:", this.strkey);
                console.log("6666666666666:", layer, " ", this.useWeaponCtrl.node.getComponent(IPlayerControl));
                otherCtrl.player.useFight.AcceptAtk(this.useWeaponCtrl.node.getComponent(IPlayerControl));
                XAudio.Play("data/audio/audio_hurt", 1, false);
                break;
        }
    }

如果是以item.RegisterCollisionCall(self.OnCollisioned);这种方式回调,受限于js的底层架构问题,回调后再OnCollisioned()函数里这个对象是未定义的。比如

this.useWeaponCtrl就是undefined

解决方法是在注册委托时直接构建一个匿名函数,然后在匿名函数里调用本对象里的方法,就像下面这样。

 

public useWeaponCtrl: UseWeaponControl;
private start(){
let self = this;
        item.RegisterCollisionCall((layer: string, other: cc.Node) => {
            self.OnCollisioned(layer, other);
        });
}
private OnCollisioned(layer: string, otherCollider: cc.Node) {
        var other = <cc.Node>otherCollider;
        switch (layer) {
            case "monster":
                var otherCtrl: IPlayerControl = other.getComponent(IPlayerControl);
                console.log("7777777777777777:", this.strkey);
                console.log("6666666666666:", layer, " ", this.useWeaponCtrl.node.getComponent(IPlayerControl));
                otherCtrl.player.useFight.AcceptAtk(this.useWeaponCtrl.node.getComponent(IPlayerControl));
                XAudio.Play("data/audio/audio_hurt", 1, false);
                break;
        }
    }

这样调用就完全正确。

 

4.集合第二次判断为空的问题。

private RefreshWeaponList(): void {
        this.playerslist.Clear();
        this.playerslist = XTask.GetAllTaskList();
        console.log("7777777777777777777777777:"+this.playerslist.Count.toString());
    }

  这里this.playerslist.Clear();第一次执行没问题。但第二次执行时,由于playerlist已经等于了XTask.GetAllTaskList();且由于这里的playerlist是引用类型。所以第二次Clear会直接Clear掉

XTask.GetAllTaskList();这里可以去掉Clear。所以在第二行不要直接使用等于,使用AddRange就可以用Clear了。

----------


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM