不是办法的办法:解决加载服务器上的图片问题的方法

之前已经发过一个帖子讨论这个问题了,这里再重新整理一下。
内存里面的Texture2D怎么赋值给sprite组件?

加载网络上的图片一定是用cc.loader.load()方法,没啥说的,重点是怎么把已经加载到了内存里面的图片赋值给sprite组件使用。
这次我在场景里放了两个引用同一张图片的sprite来说明问题,如下图,两个sprie的原始样子

两个sprite我只给左边的加载新图片

我之前有两个办法:
1.new 一个新的cc.SrpiteFrame,然后sprite.spriteFrame=新spriteFrame

新图片加载以后按照新图片的尺寸修改了node的width和height

中间黄色文字是自己new spriteFrame会被引擎鄙视

2.使用spriteFrame.setTexture()方法

这个不会有尺寸的问题,但是新问题是setTexture方法直接修改了图片。sprite组件初始设置的图片是a,所有引用了这个a图片的sprite都被修改了。结果就是这样,我只想修改左边的sprite,右边的sprite同时被修改了。

好再不会被鄙视了

这就是之前困扰了我差不多一个星期的问题,一直死脑筋在里面转没转出来。我都准备放弃creator了,下礼拜老板要交货,鸭梨山大啊。
昨晚干完其他活,作为调剂又把这个问题翻出来了(其实已经放弃creator转投cocos2d-js一整天了)。突然灵光一闪,想了下面的办法:

得到我需要的效果:

人物图片是个很大尺寸的图片,现在就压缩在需要的范围了,另外一个图片也没有收到影响。

还是用方法1,只是把尺寸修改回来了。
**被鄙视这件事怎么处理,希望会的来说说。**比如可能什么情况下有什么后果,或者怎么样处理,希望大牛来说说。
我是真不懂,也不知道会不会有什么严重问题,只能先不管了。方法2.是真的不能用,除非什么有特别需要的地方。

就是这样了,方法很简单,过程很曲折,这个问题对我的项目影响很大,已经到了放弃creator差点就开始用cocos2d-js重构的地步了。做这个决定是很痛苦的,所以格外又格外,慎重又慎重的写这个帖子记录一下。

2赞

我目前是这样想的(以下代码仅提供思路,未测试):

RemoteImageLoader.js:
cc.Class({
    extends: cc.Component,
    properties: {
        lockSize: false
    },
    onLoad: function() {
        this._mySpriteFrame = null;
    },
    _releaseMySpriteFrame: function() {
        // 若为原生环境,且mySpriteFrame存在,则release
        if (CC_JSB && this._mySpriteFrame) {
            this._mySpriteFrame.release();
            this._mySpriteFrame = null;
        }
    },
    _setMySpriteFrame: function(spriteFrame) {
        // 仅在原生环境下需要retain, release
        if (CC_JSB) {
            spriteFrame.retain();
            this._releaseMySpriteFrame();
            this._mySpriteFrame = spriteFrame;
        }
    },
    _createSpriteFrameWithoutWarning: function() {
        // 临时屏蔽创建cc.SpriteFrame时来自引擎的BS
        var warn = cc.warn;
        cc.warn = function() {
        };
        var spriteFrame = new cc.SpriteFrame();
        // 恢复cc.warn
        cc.warn = warn;
        return spriteFrame;
    },
    _setTexture: function(texture) {
        // 创建cc.SpriteFrame,屏蔽warning
        var spriteFrame = this._createSpriteFrameWithoutWarning();
        // 给spriteFrame设置texture
        spriteFrame.setTexture(texture);
        // 获取节点上的cc.Sprite
        var sprite = this.getComponent(cc.Sprite);
        if (!sprite) {
            sprite = this.addComponent(cc.Sprite);
        }
        // 替换节点cc.Sprite组件的cc.SpriteFrame
        sprite.spriteFrame = spriteFrame;
        this._setMySpriteFrame(spriteFrame);
    },
    loadRemoteImageWithUrlAndType: function(url, type = 'png') {
        cc.loader.load({id: url, type: type}, (err, texture)=> {
            if (!err) {
                var size;
                if (this.lockSize) {
                    size = this.node.getContentSize();
                }
                this._setTexture(texture);
                if (this.lockSize) {
                    this.node.setContentSize(size);
                }
            }
        });
    },
    onDestroy: function() {
        cc.log('destroy');
        this._releaseMySpriteFrame();
    }
});

我对retain, release理解不深,希望Jare帅、Panda大神能指点一下。也希望官方能出更方便的远程图片加载方法!

1赞

这个没关系的,在原生层会警告需要自己管理 sprite frame 的内存,这是一个提醒而已。

@toddlxt,在 3.13 中,就不需要再自己管理这部分内存了,retain release 的机制可以省略。

实际上就应该像方法一一样,重新设置了 sprite frame 之后,你还需要自己去修改尺寸的

2赞

目前就是这样用的,但是在web端怎么处理呢?好像在web端执行a.spriteFrame = new cc.SpriteFrame(tex)后,会出现原来的spriteframe和新的spriteFrame同时显示的问题。。。 目前引擎设计的思路是不是一张图片导入编辑器后就变成了一张纹理供精灵使用,无论创建多少精灵(使用同一张纹理),所用的精灵都是同一个纹理,而不是每个精灵都有一份自己的拷贝?

应该是a.spriteFrame.setTexture(tex)会出现你说的问题吧?通过new cc.SpriteFrame(tex)不会替换之前spriteFrame的纹理。

很抱歉给楼主带来这么多麻烦!这些应该是引擎要处理好的事情。

1赞

希望1.3.0正式版能去掉new cc.SpriteFrame()的warning

已经去掉了 asdf

多谢楼主分享 我也遇到了这个问题

多谢楼主分享 我也遇到了这个问题

同遇到谢谢楼主,我那个重复setTexture过后会读取width或height报错,可给我坑惨了

谢谢楼主的分享