原理:
既然要做无限地图,那么肯定是不能中断的,假设我们有两张地图,先将这两张地图的首尾相连。
假设这两张地图同时往左侧移动,并当最左边那张完全移出舞台,也假设你要做的跑酷游戏只有前进,没有后退,那么就表示最左侧的地图,已经完全不需要他了。
此时我们可以将两张地图的道尾互换。
如愿循环下去,便会形成无限。
这很基础,但是当地图增加到五张十张二十张时,并且还要随机显示,其难度就要复杂的多。所以我尝试了一些优化的方法。比如我只做一张地图,通过设置一些属性,是否能做到多张并且随机的效果。
于是,我尝试了做一张大的地图,地图中分了很多区域,每个区域隔的远一点,让它们不会相交,然后在图层属性上增加了一些点属性,用来记录每个区域的必要属性,这样的就可以把每个区域当成一张小地图来显示。
那么我们来看看闪影中是怎么做的:
首先我将图层的宽高数量建的很大,然后在里面建了很多的小区域(下图每个红矩形是一个区域。)
接下来如果我想把每个区域都是当成一个地图的话,那我至少要知道每个区域的起始点、宽度等等属性。因我并不打算得到地图的高度,于是我只在图层属性上加了两个点属性。
如:第一片区域第一个点,我起名叫a0,设置在第一片区域开始的位置,用此来记录这片区域的xy。
第一片区域第二个点,我起名叫a1,设置在第一片区域结束的位置。
这两个点就足够了,如果设置第二片区域,也是一样。增加一个b0的点在第二片区域开始的位置,增加另一个b1的点在第二片区域结束的位置,以此类推,就不多说了,那么我们看看代码是怎么写的。
arr记录所有区域的字母,id在arr中进行随机,所以id必定是a到k之内的字母。其它不管,只看Init方法的里面的内容,因为我所有的点属性都放到一个叫“地面”的图层上了,所以第一句就是得到这个图层的node。
既然得到图层了,那么第二句,就很明了了,得到起始点坐标,交将地图坐标设置过去,因为这里的id+0,其中的id是随机的,所以得到的起始点也是随机的。
那么只需要运行游戏看一下效果(因为gif设置太大,会超出大小,所以我让其地图的x向后减,方便看效果)。
至此已经完成了大半了,只剩无限连接了,接上最开始的原理。接下只需要稍微的添加点东西就行了。
start () { this.arr=['a','b','c','d','e','f','g','h','i','j','k']; let id=this.arr[Math.floor(Math.random()*this.arr.length)]; let _this=this; this.mapNode1=new cc.Node(); this.mapNode1.parent=this.node; this.mapjs1=this.mapNode1.addComponent('map'); this.mapjs1.Init=function(){ _this.MaplayerNode=_this.mapjs1.getLayerNodeFun('地面'); _this.mapjs1.runBo=true; _this.mapNode1['rightX']=_this.MaplayerNode[id+'1'].x;//区域右面的位置 _this.mapNode1['topY']=_this.MaplayerNode[id+'0'].y*-1+195;//区域y坐标 _this.mapNode1['leftX']=_this.MaplayerNode[id+'0'].x;//区域左面的位置 _this.mapNode1['mapWidth']=_this.MaplayerNode[id+'1'].x-_this.MaplayerNode[id+'0'].x;//右-左=区域宽度 if(_this.mapjs2.runBo){//如果第二地图,先加载完,那么将坐标放到第一张地图后面,否则放到前面 _this.mapjs1.setLocationFun((_this.MaplayerNode[id+'0'].x-_this.mapNode2['mapWidth'])*-1,_this.mapNode1['topY']); }else{ _this.mapjs1.setLocationFun(_this.MaplayerNode[id+'0'].x*-1,_this.mapNode1['topY']); } } this.mapNode2=new cc.Node(); this.mapNode2.parent=this.node; this.mapjs2=this.mapNode2.addComponent('map'); id=this.arr[Math.floor(Math.random()*this.arr.length)]; this.mapjs2.Init=function(){ _this.MaplayerNode=_this.mapjs2.getLayerNodeFun('地面'); _this.mapNode2['rightX']=_this.MaplayerNode[id+'1'].x; _this.mapNode2['topY']=_this.MaplayerNode[id+'0'].y*-1+195; _this.mapNode2['leftX']=_this.MaplayerNode[id+'0'].x; _this.mapNode2['mapWidth']=_this.MaplayerNode[id+'1'].x-_this.MaplayerNode[id+'0'].x; if(_this.mapjs1.runBo){//如果第一地图,先加载完,那么将坐标放到第一张地图后面,否则放到前面 _this.mapjs2.setLocationFun((_this.MaplayerNode[id+'0'].x-_this.mapNode1['mapWidth'])*-1, _this.mapNode2['topY']); }else{ _this.mapjs2.setLocationFun(_this.MaplayerNode[id+'0'].x*-1, _this.mapNode2['topY']); } _this.mapjs2.runBo=true; } }
代码上原理已经解释的差不多,就是通过两点得到区域起始和结束的位置,然后再通过结束减去起始,得到区域宽度。之后就是让地图循环移动下去,因为要随机,我们只需要在地图移出舞台时,重制一下ID和rightX、topY等属性就行。
randomMap(mapNode){ let id=this.arr[Math.floor(Math.random()*this.arr.length)]; mapNode['rightX']=this.MaplayerNode[id+'1'].x; mapNode['topY']=this.MaplayerNode[id+'0'].y*-1+195; mapNode['leftX']=this.MaplayerNode[id+'0'].x; mapNode['mapWidth']=this.MaplayerNode[id+'1'].x-this.MaplayerNode[id+'0'].x; }, update (dt) { if(this.mapjs1.runBo&&this.mapjs2.runBo){ let speed=15; this.mapjs1.setLocationFun(this.mapNode1.x-speed); if(this.mapNode1.x<this.mapNode1['rightX']*-1){ this.randomMap(this.mapNode1); this.mapjs1.setLocationFun((this.mapNode1['leftX']-(this.mapNode2.x-this.mapNode2['leftX']*-1+this.mapNode2['mapWidth']))*-1,this.mapNode1['topY']); } this.mapjs2.setLocationFun(this.mapNode2.x-speed); if(this.mapNode2.x<this.mapNode2['rightX']*-1){ this.randomMap(this.mapNode2); this.mapjs2.setLocationFun((this.mapNode2['leftX']-(this.mapNode1.x-this.mapNode1['leftX']*-1+this.mapNode1['mapWidth']))*-1,this.mapNode2['topY']); } } },
完成之后,将地图移动速度提升到10倍的效果。
改良一下做成微信小游戏的效果。
至此基本结束了,最后说一下注意点,上面的方法实际上是区域循环,其坐标不是地图左上角,而是你设置的属性,一定要弄清楚这点,别把自己弄晕了。
其次地图尽量大点,最起码间隔要大于最大的屏幕宽高,加上可能会移动的差值,如果能力可以,可以只将显示在舞台的地图显示,另一个parent=null掉,这样可以避免很多问题。否则的话就把图层的宽高数量设置的大点,一千不够就二千,二千不够就五千一万。闪影不是地图的整体宽高设置越大性能越高,这点别弄混了。