Cocos2d-JS 使用定时器取消往图片、骨骼动画添加的shader

前端之家收集整理的这篇文章主要介绍了Cocos2d-JS 使用定时器取消往图片、骨骼动画添加的shader前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

环境:

win7 64位

Cocos2d-JS v3.0 (final)

Cocos Code IDE v1.0.0.RC2

注意本文是在非web上实现,使用shader本人的浏览器不能正常显示效果


本文基于上一篇文章Cocos2d-JS下往Sprite SkeletonAnimation Armature(骨骼动画)添加shader 进行拓展。


正文:

使用shader还原方法有很多种,这里先介绍一下本人的理解:图片添加shader并不会影响图片原来的各种属性,只是在屏幕上显示之前,把图片的信息和所用的shader进行各种处理,把处理后的效果显示出来。

用一个公式解释的话,那就是 A (图片) + B(shader) = C(最终显示效果)。

而不是A+B=A。


(实际上opengl变换并不是相加,这里只是打个比方,示意一下)


既然理解了,那么要在已经使用shader的图片/骨骼动画/等等上取消特效就很简单了,直接使用shader,只是这个shader不添加任何特效,单纯的显示图片原来的信息,那就好了。


这里介绍两种方法

第一种:在app.js最下面添加这样一个方法(具体可以参照上文app.js里面garySprte(sprite)方法):

function sourceSprite(sprite) {  
    if (sprite) {  
        var shader = new cc.GLProgram();  
        shader.initWithString(cc.SHADER_POSITION_COLOR_VERT,cc.SHADER_POSITION_COLOR_FRAG );//没有特效的shader  
        shader.link();
        shader.updateUniforms();//我的理解是经过一系列的矩阵变换渲染到屏幕上  
        sprite.setShaderProgram(shader);//应用到精灵上  
    }  
}  

这里不需要添加新的.vsh和.fsh文件了,因为cc.SHADER_POSITION_COLOR_VERT 和cc.SHADER_POSITION_COLOR_FRAG 已经是了,我们可以到cocos2d-js 官方文档查看API :http://www.cocos2d-x.org/reference/html5-js/V3.0/index.html

接着在中间位置找到CCShaders.js



接着在73到100行可以看到具体的定义



然后在app.js里面的

  1. graySprite(this.sprite);

后面添加

     this.scheduleOnce(function(){
        sourceSprite(this.sprite);
        },6);//表示6秒后执行还原方法:sourceSprite(this.sprite)


但是,这样添加的话,效果是有的,但是控制台每帧都报opengl error,尽管报错,但是效果跟我们预期的一样。不过强迫症不能忍,当然也可以去找一下怎么修复这个问题。


不过这里还有另外一种更加简单的方法,那就是在使用(带特效)shader之前,先保存目标的shader,具体操作为:

在app.js里的ctor方法里,调用

graySprite(this.sprite);
之前,添加这么一句获取目标的shader:
var spriteBefore = this.sprite.getShaderProgram();
接着在这句的后面,添加定时器操作:

this.scheduleOnce(function(){
        this.sprite.setShaderProgram(spriteBefore);
        },5);//表示6秒后执行还原:this.sprite.setShaderProgram(spriteBefore);


同理,SkeletonAnimation也是一样,在ctor方法return true前添加

var spineBoyBefore = spineBoy.getShaderProgram();
        this.scheduleOnce(function(){
        	spineBoy.setShaderProgram(spineBoyBefore)
        	;},6);//6秒后执行还原

注意在创建spineBoy后添加


然后特别说明一下,添加特效shader时要注意SkeletonAnimation的gl_Position为:

gl_Position = (CC_PMatrix * CC_MVMatrix) * a_position;
不然还原后位置会发生变化 ,感觉就像在位移


最后就是Armature动画

这个要块骨骼皮肤渲染的比较麻烦,因为在遍历的时候使用for in了,而不是for(;;){},在for in中,就算在使用特效shader前保存了原本的shader,之前再使用定时器设定X秒后运行还原,尽管执行的次数跟骨骼数量一样,但只对一个骨骼有效,在遍历方法里:

grayArmature: function (armature) {  
        var locBoneDic = armature.getBoneDic();  
        for (var key in locBoneDic) {  
            var bone = locBoneDic[key];  

            if (bone && bone.getDisplayRenderNode()) { 
                var node = bone.getDisplayRenderNode();  
                graySprite(node);  
            }  
        }  
    }  

因为是在X秒后再对node进行还原shader,而此时node保存的只是遍历骨骼时保存的最后一个骨骼,所以说,要用for(;;){},把骨骼添加进node[i]数组(或者列表里面),X秒后操作的时候每个骨骼都保留了下来,但是,由于本人刚接触JS,而且基础不咋地,就继续探索别的方法了。


那,先保存原来的shader,再写一个遍历方法,再设置为原来的shader不就可以了?


cocos2d-js的定时器延迟函数:

scheduleCallbackForTarget

scheduleOnce

等等,我在这篇文章总结了一下使用延时函数要注意的地方http://www.jb51.cc/article/p-zxbnxooz-qm.html



本文使用的实现方式,那就是在每帧更新方法里面设置一个标志,X秒后把标志设置为true,然后执行遍历方法,接着把标志设置为false


先在一开始添加全局变量


bc:图片原本的shader

fa:标志位

armature:骨骼动画



接着在onEnter里面添加:(其实添加的位置最好是在ctor,也就是初始化的时候,不过本人注重实现效果,优化什么的完全没有考虑)

      this.fa = false;//初始化标志位为false
       this.scheduleUpdate();//开启update,每秒刷新时的操作
       this.scheduleOnce(function() {
		this.fa = true;
	},7); //7秒后把标志位设置为true

重写update方法

update : function() {
		 if (this.fa) {//上面用延迟方法把this.fa设置为7秒后为true
			this.grayArmature(this.armature,false);//下面会介绍修改的grayArmature方法
			this.fa = false;
		} 
	},

接着把修改onEnter方法

	onEnter : function() {//主要是更新armature的作用域,改变了X坐标
		this._super();
		var size = cc.winSize;
		var skins = new Array();
        ccs.armatureDataManager.addArmatureFileInfo(res.COwboy_png0,res.CowBoy_plist0,res.CowBoy_exportjson);
        this.armature = ccs.Armature.create("Cowboy");
        this.armature.getAnimation().play("Walk");
        this.armature.x = size.width * 0.8;
        this.armature.y = size.height / 2;
        
        this.armature.setScale(0.5);
        this.grayArmature(this.armature,true);
        
        this.addChild(this.armature,4,0);
  
        this.fa = false;
        this.scheduleUpdate();
       this.scheduleOnce(function() {
		this.fa = true;
	},7); 
        
	},
 最后,改动grayArmature 
grayArmature:function(armature,flag){ 
    	var locBoneDic = armature.getBoneDic(); 
    	for (var key in locBoneDic) { 
    		var bone = locBoneDic[key];  
    		if (bone && bone.getDisplayRenderNode()) { 
    			var node = bone.getDisplayRenderNode();
    			
    			if (flag) {
    				this.bc = node.getShaderProgram();//保存原本的shader
    				graySprite(node);
				} else {
					node.setShaderProgram(this.bc);
				}
    		}
    	}
    },

方法最后有没有逗号,根据自己实际情况而定

最后看看效果,运行程序后第4秒时:



第5秒:



第6秒(注意要做gl_Position的处理):



第7秒:



最后整个app.js:有些测试函数本人就懒得去掉了,大家可以自己拿去改改试一下效果,中间的图片使用的延迟方法跟上面介绍的有出入,不过大家可以到官方文档查查API,效果跟上面介绍是一样的。

var HelloWorldLayer = cc.Layer.extend({
    sprite:null,bc: null,fa:null,armature:null,ctor:function () {
        // ////////////////////////////
        // 1. super init first
        this._super();

        // ///////////////////////////
        // 2. add a menu item with "X" image,which is clicked to quit the
		// program
        // you may modify it.
        // ask the window size
        var size = cc.winSize;

        // add a "close" icon to exit the progress. it's an autorelease object
        var closeItem = new cc.MenuItemImage(
            res.CloseNormal_png,res.CloseSelected_png,function () {
                cc.log("Menu is clicked!");
               
            },this);
        closeItem.attr({
            x: size.width - 20,y: 20,anchorX: 0.5,anchorY: 0.5
        });

        var menu = new cc.Menu(closeItem);
        menu.x = 0;
        menu.y = 0;
        this.addChild(menu,1);

        // ///////////////////////////
        // 3. add your codes below...
        // add a label shows "Hello World"
        // create and initialize a label
        //var helloLabel = new cc.LabelTTF("Hello World"+SimpleNativeClass.getAnotherMoreComplexField(),"Arial",38);
        var helloLabel = new cc.LabelTTF("Hello World",38);
        // position the label on the center of the screen
        helloLabel.x = size.width / 2;
        helloLabel.y = 0;
        // add the label as a child to this layer
        this.addChild(helloLabel,5);

        // add "HelloWorld" splash screen"
        this.sprite = new cc.Sprite(res.HelloWorld_png);
        this.sprite.attr({
            x: size.width / 2,y: size.height / 2,scale: 0.5,rotation: 180
        });
      
        var spriteBefore = this.sprite.getShaderProgram();
        this.addChild(this.sprite,0);
        graySprite(this.sprite); 
        cc.director.getScheduler().scheduleCallbackForTarget(this,function(){
        	this.sprite.setShaderProgram(spriteBefore);
        	},5,false,!this._isRunning );
        this.sprite.runAction(
            cc.sequence(
                cc.rotateTo(2,0),cc.scaleTo(2,1,1)
            )
        );
        helloLabel.runAction(
            cc.spawn(
                cc.moveBy(2.5,cc.p(0,size.height - 40)),cc.tintTo(2.5,255,125,0)
            )
        );
        
        var spineBoy = new sp.SkeletonAnimation(res.SpineBoy_json,res.SpineBoy_atalas);
        spineBoy.setPosition(cc.p(size.width * 0.1,size.height / 2 - 150));
        spineBoy.setAnimation(0,'walk',true);
        spineBoy.setMix('walk','jump',0.2);
        spineBoy.setMix('jump',0.4);
        var spineBoyBefore = spineBoy.getShaderProgram();
        graySprite(spineBoy);
        this.addChild(spineBoy,2);
        this.scheduleOnce(function(){
        	spineBoy.setShaderProgram(spineBoyBefore)
        	;},6); 
        return true;
    },onEnter : function() {
		this._super();
		var size = cc.winSize;
		var skins = new Array();
        ccs.armatureDataManager.addArmatureFileInfo(res.COwboy_png0,update : function() {
		 if (this.fa) {
			 cc.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
			this.grayArmature(this.armature,false);
			this.fa = false;
		} 
	},grayArmature:function(armature,flag){ 
    	var locBoneDic = armature.getBoneDic(); 
    	cc.log(locBoneDic);
    	for (var key in locBoneDic) { 
    		var bone = locBoneDic[key]; 
    		if (bone && bone.getDisplayRenderNode()) { 
    			var node = bone.getDisplayRenderNode();
    			
    			if (flag) {
    				this.bc = node.getShaderProgram();
    				graySprite(node);
				} else {
					node.setShaderProgram(this.bc);
				}
    		}
    	}
    },grayArmature2:function(armature,bc){ 
    	var locBoneDic = armature.getBoneDic(); 
    	cc.log("131231313");
    	for (var key in locBoneDic) { 
    		var bone = locBoneDic[key]; 
    		if (bone && bone.getDisplayRenderNode()) { 
    			var node = bone.getDisplayRenderNode();
    				node.setShaderProgram(bc);
    		} 
    	} 
    },});

function graySprite(sprite)
{
	if(sprite)
	{
		var shader = new cc.GLProgram();
		shader.init(res.Grat_vsh,res.Gray_fsh);
		shader.link();
		shader.updateUniforms();
		sprite.setShaderProgram(shader);
	}    
}

function backToSprite(sprite)
{
	if(sprite)
	{
		var shader = new cc.GLProgram();
		shader.init(cc.SHADER_POSITION_COLOR_VERT,cc.SHADER_POSITION_COLOR_FRAG );
		shader.link();
		shader.updateUniforms();
		sprite.setShaderProgram(shader);
	}    
}


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

猜你在找的Cocos2d-x相关文章