Cocos2d-JS 实现X轴自定义视窗跟随

Cocos2d-JS 实现X轴自定义视窗跟随,第1张

概述环境: win7 64位 Cocos2d-JS v3.1 Cocos Code IDE v1.0.0.Final 自带的跟随函数cc.follow,跟随的时候总是以目标为中心位置,而且在非移动范围边缘进行移动时,目标只要稍微进行移动,也会触发跟随动作。 本文没有在web上进行测试、改善 本文以X轴为例,目标移动时超出某个范围才进行跟随动作,如图: 本文只是经验分享,Y轴的跟随本文没有实现,而且响应

环境:

win7 64位

Cocos2d-Js v3.1

Cocos Code IDE v1.0.0.Final


自带的跟随函数cc.follow,跟随的时候总是以目标为中心位置,而且在非移动范围边缘进行移动时,目标只要稍微进行移动,也会触发跟随动作。


本文没有在web上进行测试、改善


本文以X轴为例,目标移动时超出某个范围才进行跟随动作,如图:



本文只是经验分享,Y轴的跟随本文没有实现,而且响应的事件为键盘上的左右方向。另外,程序写的比较随意,显得略搓.......大家别在意....

另外这里的视窗这个hellowWorldLayer,也就是这个helloWorld层,是一个层,不是opengl的视口,写的时候没注意让大家混乱了不好意思


(其实也就是层的移动跟随,本文的视窗不是指opengl的视口,让层进行移动来达到看起来是视窗跟随的效果)


最终效果如下(暂时没有黑线):

上传的时候不知道为何变成JPG格式了= =那就传到相册空间好了,这里放一个链接吧...:

http://my.csdn.net/my/album/detail/1795641


背景图片用的是Tiled制作的地图,本文最后会提供资源,瓦片地图的大小为:



制作该地图的过程就省略了,网上好多教程。



正文:

1.新建一个工程,本文的工程为横向,分辨率为960*640,不过显示的是main.Js里800*450的默认分辨率。把app.Js里用不上的删掉,剩下这些:

var HelloWorldLayer = cc.Layer.extend({    ctor:function () {        this._super();        var size = cc.winSize;        return true;    }});var HelloWorldScene = cc.Scene.extend({    onEnter:function () {        this._super();        var layer = new HelloWorldLayer();        this.addChild(layer);    }});

2.把.tmx地图文件和对应的.png文件放到res文件夹下。 接着修改tmx文件引用的图片路径为相对路径,改路径这里介绍两种方法。


方法一:把引用图片路径改为引用的图片名字(加上格式)。


然后在main.Js里面添加res路径到文件搜索,添加后整个文件代码为:

cc.game.onStart = function(){    cc.vIEw.adjustVIEwPort(true);    cc.vIEw.setDesignResolutionSize(800,450,cc.ResolutionPolicy.SHOW_ALL);    cc.vIEw.resizeWithbrowserSize(true);    var searchPaths = Jsb.fileUtils.getSearchPaths();    var paths = [                 'res'                 ];    for (var i = 0; i < paths.length; i++) {        searchPaths.push(paths[i]);    }    Jsb.fileUtils.setSearchPaths(searchPaths);    //load resources    cc.LoaderScene.preload(g_resources,function () {        cc.director.runScene(new HelloWorldScene());    },this);};cc.game.run();

方法二:直接在路径写上res/ :

 <image source="res/tmw_desert_spacing.png"

3.加载地图,在app.Js的HelloWorldLayer构造函数ctor里添加如下代码:

var tiled = new cc.TMXTiledMap("res/test1111.tmx");//直接加载路径下tmx文件        this.addChild(tiled);

4.添加目标,这里用helloworld图片,先在HelloWorldLayer里面添加一个变量:

hero:null,

然后在第三步后面继续添加:

this.hero = new cc.Sprite("res/HelloWorld.png");        this.hero.scale = 0.2;//因为原图片太大,于是缩小为原大小的20%        this.hero.setposition(size.wIDth * 0.5,size.height * 0.3);        this.addChild(this.hero,1);

5.添加键盘事件和目标左右移动:

(关于更多的事件,请参考这个:http://www.cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en,或者其他demo、资料。)

HelloWorldLayer里添加以下变量,用作判断左移或者右移、目标缩放后的宽度:

isleft:null,isRight:null,heroWIDth:null,

再添一个目标移动速度:(好吧我表示直接初始化更加省事了)

heroSpeed:5,

在ctor里初始化:

 this.isleft = false;        this.isRight = false;

注意在创建hero后才赋值,经过测试,在缩放后获取的宽度为不缩放时大小,所以要乘以0.2:

this.heroWIDth = this.hero._getWIDth() * 0.2;
在第四步后添加事件监听和处理:
cc.eventManager.addListener({            event: cc.EventListener.KEYBOARD,//事件为键盘按键            onKeypressed:  function(keyCode,event){                var helloWorldLayer = event.getCurrentTarget();//获取当前 *** 作的作用域,与最后一行的那个参数有关,this则为该HelloWorldLayer。                cc.log("Key " + keyCode.toString() + " was pressed!");//测试出按下的键的编号,额,,,没去找按键对应编号的表                if (keyCode == 23) {//左方向                    cc.log("left");                    helloWorldLayer.isleft = true;                    helloWorldLayer.isRight = false;                }                if (keyCode == 24) {//右方向                    cc.log("right");                    helloWorldLayer.isRight = true;                    helloWorldLayer.isleft = false;                }            },onkeyreleased: function(keyCode,event){                //var label = event.getCurrentTarget();                var helloWorldLayer = event.getCurrentTarget();                if (keyCode == 23)                    helloWorldLayer.isleft = false;                if (keyCode == 24)                    helloWorldLayer.isRight = false;                cc.log("Key " + keyCode.toString() + " was released!");            }        },this);

这里特别说明一下:为了在按下一个方向时,按下另一个方向,目标会立刻转向运动,所以在键盘按下时除了要将需要前进的方向值为true,另一个方向同时置为false,实现的方法有好多种,大家不要在意本文的写法......


接着开启update,在update里面更新目标的位置。在后面继续添加:

this.scheduleUpdate();
然后再在 HelloWorldLayer里重写update方法(注意在ctor的最后加逗号,):
update : function(dt) {        var pos = this.hero.getpositionX();        if (this.isleft && !this.isRight) {            if ((pos - this.heroWIDth *0.5) > 0  ) //超出左边移动边界就不让目标左移                this.hero.setpositionX(pos - this.heroSpeed);        }        if (this.isRight && !this.isleft) {            if ( (this.mapLength ) > (pos + this.heroWIDth)) //超出右边界就不让目标右移                this.hero.setpositionX(pos + this.heroSpeed);        }    },

如无意外目标可以左右移动了。

注意,按键事件和update在每一帧的处理顺序:先处理按键,再到update。


5.5这里说一下cc.Follow

用new创建的话,控制台会报这样的问题Jsb_create_APIs.Js:437:ReferenceError: ret is not defined

改为.ctreate创建就好了

接着不想做自定义视窗跟随函数的同学,直接添加以下代码即可完事:

        var followAction = cc.Follow.create(this.hero,cc.rect(0,3800,size.height));        this.runAction(followAction);

若有黑线问题第七步有讲


6.添加自定义的视窗跟随函数(也就是层的移动跟随,本文的视窗不是指opengl的视口,让层进行移动来达到看起来是视窗跟随的效果):

先交代一下cc.Follow,这个动作创建的时候最好用.create方法,用new的话


先在HelloWorldLayer里添加一个变量,用来表示视窗移动的状态,本人比较懒,用一个整形表示,0为不动,1为左移,2为右移,理论上用枚举类型会比较符合规范= =...

 cameraStatue:null,

再加个变量保存地图的宽度

 mapLength:null,

接着在ctor初始化为0:

this.cameraStatue = 0;

在创建tiled(地图)后保存他们的宽度

this.mapLength = tiled.getContentSize().wIDth;
然后在 HelloWorldLayer里添加自定义视窗跟随函数:
setCamera : function(targetpositionX,offsetleft,offsetRight,windowWIDthHalf,tileDW) {        var cameraX = this.getpositionX();//获取视窗的X坐标        var isOut = Math.abs(targetpositionX - (-cameraX));//得出视窗与目标X轴上的距离        var ofx = windowWIDthHalf - 105;//实际上减去的值为80+25,下面介绍如何得出        if (targetpositionX >  (ofx) && (targetpositionX < (tileDW - windowWIDthHalf +25))) {//视窗移动范围判定            if (isOut < offsetleft) {//视窗是否移动判定                this.cameraStatue = 1;            }            if (isOut  >= offsetleft && isOut <= offsetRight) {//视窗是否移动判定                this.cameraStatue = 0;            }            if (isOut > offsetRight) {                this.cameraStatue = 2;            }            if (this.cameraStatue == 1) {                this.setpositionX(cameraX + this.cameraSpeed);            }            if (this.cameraStatue == 2) {                this.setpositionX(cameraX - this.cameraSpeed);            }        }    }
接下来讲解一下这个函数(锚点默认):

参数targetpositionX为需要跟随目标的X坐标,

参数offsetleft为左边移动边界,也就是目标和视窗X轴上的相对位置,

参数offsetRight为右边移动边界,也就是目标和视窗X轴上的相对位置,
参数windowWIDthHalf为视窗宽度的一半,

参数tileDW为地图的宽度。


以下所有的分析都是以锚点为默认的情况下(Layer默认锚点是(0,0),里面的node默认(0.5,0.5)),而且main.Js里显示的画布为:800*450,所以cc.winSize的宽度为800。(大家可以用cc.log打印cc.winSize.wIDth看看)

相机起始X坐标:0,

目标起始X坐标400,(在屏幕宽度(800)一半(400),恩,应该是这样算的)


var isOut = Math.abs(targetpositionX - (-cameraX));
这句的作用是取得跟随的目标和视窗X轴上的差值,这里视窗,也就是cameraX值取反,是因为视窗往右移,X轴的坐标是越来越小的,也就是和目标的方向相反,X轴的原点一致,大家可以自己输出视窗的X轴坐标观察结果。这里把最后的值取绝对值,在本文中其实加不加绝对值也没问题,因为目标都是在X大于0的时候进行移动,取绝对值是为了应对在目标移动到X轴负坐标的时候,但是本文没有这种情况= =...

var ofx = windowWIDthHalf - 105;

这句等号右边完整的表达式是:windowWIDthHalf - 80 -25,减去80是为了补偿图片一半的宽度,因为锚点为目标中点,所以要补回左边边缘到中点的长度。然后这里的25为人工调试测出的结果(猜测跟分辨率从960*640的3:2变到800*450的16:9有关),不然会出现视窗移动后再移回来,回不到视窗原点。

(上传后不知为何变成JPG格式= =那就传到相册空间,放个链接吧)

http://my.csdn.net/my/album/detail/1795643


if (targetpositionX >  (ofx) && (targetpositionX < (tileDW -windowWIDthHalf +25))) {

再次强调目标右移的X坐标为增量,而视窗右移为减量。大家可以自己输出看看结果

这句为视窗可以移动的范围,由于判断是根据目标的X轴,所以向右为正。视窗不能移到地图外面,所以左边界不是0,而是视窗宽度的一半,加上目标锚点和测试时出现的偏移影响,所以左边界为上一句表达式所示;右边界同理。


之后就是判断目标和视窗的相对距离有没有超出预设的左右值,由于视窗X轴向右为负,所以向左移动时加上移动速度,向右移动时减去移动速度。


最后在update里的最后调用这个函数:

this.setCamera(pos,300,500,cc.winSize.wIDth * 0.5,this.mapLength);



7.去除移动时出现的黑线

上面的动态图最后会出现这样的黑线:



在本博客的另一篇文章讲解了如何修复黑线的问题:http://www.jb51.cc/article/p-ackiqksi-qm.html



8.源码和资源

main.Js:

cc.game.onStart = function(){    cc.vIEw.adjustVIEwPort(true);    cc.vIEw.setDesignResolutionSize(800,this);};cc.game.run();

app.Js:

var HelloWorldLayer = cc.Layer.extend({    isleft:null,hero:null,cameraStatue:null,mapLength:null,heroSpeed:20,cameraSpeed:20,ctor:function () {        this._super();        var size = cc.winSize;        this.isleft = false;        this.isRight = false;        this.cameraStatue = 0;                var tiled = new cc.TMXTiledMap("res/test1111.tmx");        this.addChild(tiled);        this.hero = new cc.Sprite("res/HelloWorld.png");        this.hero.scale = 0.2;        this.hero.setposition(size.wIDth * 0.5,1);        this.mapLength = tiled.getContentSize().wIDth;        this.heroWIDth = this.hero._getWIDth() * 0.2;        cc.log(this.hero._getWIDth()*0.2*0.5);                cc.eventManager.addListener({            event: cc.EventListener.KEYBOARD,onKeypressed:  function(keyCode,event){                var helloWorldLayer = event.getCurrentTarget();                var pos = helloWorldLayer.hero.getpositionX();                cc.log("Key " + keyCode.toString() + " was pressed!");                if (keyCode == 23) {                    cc.log("left");                    helloWorldLayer.isleft = true;                    helloWorldLayer.isRight = false;                }                if (keyCode == 24) {                    cc.log("right");                    helloWorldLayer.isRight = true;                    helloWorldLayer.isleft = false;                }            },this);                this.scheduleUpdate();        return true;    },update : function(dt) {        var pos = this.hero.getpositionX();        if (this.isleft && !this.isRight) {            if ((pos - this.heroWIDth *0.5) > 0  )                 this.hero.setpositionX(pos - this.heroSpeed);        }        if (this.isRight && !this.isleft) {            if ( (this.mapLength ) > (pos + this.heroWIDth))                 this.hero.setpositionX(pos + this.heroSpeed);        }                this.setCamera(pos,this.mapLength);    },setCamera : function(targetpositionX,tileDW) {        var cameraX = this.getpositionX();        var isOut = Math.abs(targetpositionX - (-cameraX));        var ofx = windowWIDthHalf - 105;        if (targetpositionX >  (ofx) && (targetpositionX < (tileDW -windowWIDthHalf +25))) {            if (isOut < offsetleft) {                this.cameraStatue = 1;            }            if (isOut  >= offsetleft && isOut <= offsetRight) {                this.cameraStatue = 0;            }            if (isOut > offsetRight) {                this.cameraStatue = 2;            }            if (this.cameraStatue == 1) {                this.setpositionX(cameraX + this.cameraSpeed);            }            if (this.cameraStatue == 2) {                this.setpositionX(cameraX - this.cameraSpeed);            }        }    }});var HelloWorldScene = cc.Scene.extend({    onEnter:function () {        this._super();        var layer = new HelloWorldLayer();        this.addChild(layer);    }});

用到的tmx和tmx对应的png文件: http://download.csdn.net/detail/et_sandy/8164981 总结

以上是内存溢出为你收集整理的Cocos2d-JS 实现X轴自定义视窗跟随全部内容,希望文章能够帮你解决Cocos2d-JS 实现X轴自定义视窗跟随所遇到的程序开发问题。

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

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

原文地址: https://outofmemory.cn/web/1012802.html

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

发表评论

登录后才能评论

评论列表(0条)