闪影教程:制作跑酷游戏多张随机无限地图

原理:

既然要做无限地图,那么肯定是不能中断的,假设我们有两张地图,先将这两张地图的首尾相连。

假设这两张地图同时往左侧移动,并当最左边那张完全移出舞台,也假设你要做的跑酷游戏只有前进,没有后退,那么就表示最左侧的地图,已经完全不需要他了。

此时我们可以将两张地图的道尾互换。

如愿循环下去,便会形成无限。

这很基础,但是当地图增加到五张十张二十张时,并且还要随机显示,其难度就要复杂的多。所以我尝试了一些优化的方法。比如我只做一张地图,通过设置一些属性,是否能做到多张并且随机的效果。

于是,我尝试了做一张大的地图,地图中分了很多区域,每个区域隔的远一点,让它们不会相交,然后在图层属性上增加了一些点属性,用来记录每个区域的必要属性,这样的就可以把每个区域当成一张小地图来显示。

那么我们来看看闪影中是怎么做的:

首先我将图层的宽高数量建的很大,然后在里面建了很多的小区域(下图每个红矩形是一个区域。)

接下来如果我想把每个区域都是当成一个地图的话,那我至少要知道每个区域的起始点、宽度等等属性。因我并不打算得到地图的高度,于是我只在图层属性上加了两个点属性。

如:第一片区域第一个点,我起名叫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掉,这样可以避免很多问题。否则的话就把图层的宽高数量设置的大点,一千不够就二千,二千不够就五千一万。闪影不是地图的整体宽高设置越大性能越高,这点别弄混了。

11赞

大佬啊。带我飞

我来助你一臂之力

mark

为什么不顺着两张图替换的思路 做一个地图类 带一个id属性和初始化方法 第一张图出屏的时候随机一个数找到与之id对应的地图进行初始化(这个时机可以提前),然后进行地图拼接,移出的图不要释放,再次随机到就直接使用,随机到新图就new一个。有50张图,实际使用到10张图,就new 10次。照着这个思路还可以用更好的算法进行优化

本来就是优化的,为什么还要倒退回去。一开始的思路没有变,算法没有变,后面需要建N张图的方法,优化成只需要一张就行了,不仅效率会提高,加上闪影有池对像功能,内存空间也会节省很多。如果真是十几张地图,就初始十几张地图随机,那这篇教程,不就没什么意义了。

mark

mark

mark

mark

mark

大佬,那个setLocationFunc干了啥操作? 不是特别懂

移动地图,如果设置了mapCameraNode这个属性,可以不用setLocationFun这个方法,直接用摄像机移动

IOS 上 卡的不要不要的,。。

闪影0.9,我有升过级,但是后来限制角色类,我也就没更新了。当时苹果6S,我测没有问题,不知道你那个是什么机型,如果是闪影问题,我可以追踪一下

这个做法是要配合闪影来搞的么? 主要没看懂设置的节点的属性坐标如何映射到屏幕中的坐标的

要学,要看教程

大佬牛B