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

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

概述环境: win7 64位 Cocos2d-JS v3.0 (final) Cocos Code IDE v1.0.0.RC2 注意本文是在非web上实现,使用shader本人的浏览器不能正常显示效果 本文基于上一篇文章:Cocos2d-JS下往Sprite SkeletonAnimation Armature(骨骼动画添加shader  进行拓展。 正文: 使用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里面的

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-JS 使用定时器取消往图片、骨骼动画添加的shader全部内容,希望文章能够帮你解决Cocos2d-JS 使用定时器取消往图片、骨骼动画添加的shader所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1005866.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存