162008j53uzr97neitoqjj.jpg
  在5月13日Unite 2017 案例分享专场上,椰岛游戏CTO徐步诣分享了椰岛游戏在2D游戏上的技术分享,以下为详细内容:

  大家好,很高兴今天来到这里做分享,我先简单地自我介绍一下,我名字叫徐步诣,怎么说呢,最后那一个字念诣,经常有人念错,以至于有一个快递小哥念对了,我没反应过来,叫了三遍名字,我都没反应过来。

  我提一个问题,在场的各位有谁听说过椰岛游戏的?请举一个手?还不少,我很开心。我介绍一下椰岛游戏,椰岛游戏是成立于2009年,在上海是一个很小的Studio,我们致力于研发小体量的独立游戏,获得国IGF和Unity的奖项,我们每年都有组织GameJam,最早的时候是在公司里面做头脑风暴,然后我们要搞一个GameJam就搞了上海的GameJam,后来发展越来越大,就跟国际上的GlobalGameJam就发展起来,后面还有一个独立开发者社区就是IndieAce,这个独立社区规模也在扩大,方便做IndieGame的人方便交流。从2009年到现在,已经有八年,经过八年的发展,我们还是一个小公司,现在人也不多,但是其实公司的氛围很好。

  我这次会说两个方面,一个是说我们作为IndieGame,椰岛和Unity是怎么发展,去做游戏这件事情。后面第二个阶段,我会分享两个简单,从我们自己项目的事例上面做一个简单的技术分享。

  一开始我先多罗嗦一下,为什么选择Unity,这么几点,上手容易应该大家都会比较有体会。我最大的感觉是说Unity其实不是为了技术人员准备,其实是给策划或者美术这些人准备的,它的界面非常友好,所以一个人可以开发出一个原形哪怕不懂得写代码,在我们工作室头脑风暴的时候,基本一个人或者两个人,花一个星期就会出一个模型,我们会不停地迭代。跨平台不说,这次Unity也说了支持28个平台,非常了不起,所以我们其实在Xbox和PS4在国内首发的时候,也是把我们的平台植入到这个平台上,相对来说也是容易很多。

  开发和运行的那个高效率,其实是这样子,他们是一对矛盾,在我的理解,如果要讲求开发效率,那你的运行效率不一定很高,反过来也是一样的,但是在Unity里面找到了一个,我认为是比较好的平衡点。Unity不谈,最后Unity配合了一个il2cpp这个非常棒,可以把大部分的代码进行编译,也保证了运行的效率,这是一个平矛盾,但是找到一个平衡点,这个特别好。

  人才储备对我们小公司而言,希望进来的人,马上可以为我所用,就发挥你的能力,如果招Unity的人也好,或者招C#的人也相对广一点。Editor扩展这块,后面会讲到,它的最大好处,如果针对IDE进行二次开发,会有一个很好的平台,Unity支持IDE,那也可以在上面跑,而且还有一个好处,就是你在游戏IDE里面可以编辑,也可以在某种程度上做早所见即所得这样的。

  我再说一下椰岛的这个特色,其实我们椰岛基本上是专注在2D方面的,有这几个理由,还有其他的就不细说了。相对来说我们团队比较小,其实我们一个项目,大概是在人员配置一开始只有两到三个人,非常非常精简。做2D游戏相对比较适合我们的团队,因为不需要大量的美术,或者说模型之类的,我们只要2D图片就好了,这是一个。

  第二个可以快速开发出原形,这个刚刚讲过了,可以说游戏里面开发的铁三角,策划、美术、程序,理论上来说缺一不可,但是实际上,我们做头脑风暴也好,或者说参加Gamejam也好,经常看到一个人单挑。我们希望大家组队,但是一个人单挑,这也是可以的。其实用其他的游戏引擎,用Unity更方便,游戏原形来进行验证和迭代。我们其实在公司里边,出原形基本上就是一个人,完了之后,原形其实是24小时到48小时就出来了,对原形进行迭代。迭代的时间确定这个原形的玩法基本上在一周两周左右,剩下的时间其实都是在打磨,所以你可以看出Unity在这个方面,其实是很高效,非常高效的使用工具。

  第三点是一个比较了,相对来说是一个比较,因为现在游戏都是在往3D化发展,我们这边关注在2D方面。其实做2D,有做2D的好处。因为你不需要考虑那么多的特效,那么炫的表达,你要吸引住玩家,其实很大一部分程度就靠可玩性,所谓的Gameplay,反过来就让我们更加注重游戏性,或者游戏的表达,怎么才能做出好玩的游戏,来吸引玩家,在2D的世界里面,这也是一个挺难做到的事情。

  这个是我罗列了一下我们产品和Unity之间的时间线,实际上之前,在2013年之前,我们也采用过其他的引擎,我们通过反复比较还是决定用Unity来做。2013年,你们现在可以看到,叫Unity,这个对3D是支持很好,相对来说2D会弱一些。所以他们是在2013年引进这个4.3版本,不知道大家对这个版本有没有印象,我觉得这个版本还是很重要,在他们社区里面推出来一个2D的例子,那个例子应该是英国伦敦,那个大本钟那边,有大作战,有几个人在那边打来打去,那个时候看了觉得不错,Unity做2D做到这样了,就是在那个版本里面,引入了所谓叫2Dsprite的东西,我们决战喵星也是在2013年发布,但是很可惜,Unity在2013年底,我们用的技术并没有2Dsprite,我们是用AssetStore里面的Ex2D。然后到了2014年的时候,Unity发布了4.6,这个最重要的更新是引用了自己的一个界面系统,我们在2014年最重要的事情就是移植,我们就把这个切,切完之后立刻,应该说可以在XboxOne上跑了,但是上面有一些小的坑要去踩,这个不细了说,但是总体来说还是很方便。

  我们自己还有一款拼字游戏,2014年的时候用Spel1master,我们就用在项目当中,这个项目几乎完成,但是最后没有上线,没有上线的原因很简单,我们觉得不好玩,是一个弱联网的游戏,所以服务器全部都好了,但是最后还是撤下来,没有上去。因为这是一个拼字游戏,对国人来说,不是很擅长,做起来以后,老外的反馈不是很好玩,所以就放弃了。

  时间到了2015年的话,Unity5.3有一个最重要的功能就是2Djoint,这个东西功能非常好,对于我们自己来讲,我们有决战喵星,因为决战喵星成功,我们很自然想到,这件事情最后在我们的团队里面也是处于暂停状态,因为我们也觉得不好玩。决战喵星完全使用UnitySprite,还有一款是超脱力医院,我们从发布到现在已经累积一千万个下载,已经完成使用Sprite加NGUI,这个UI比较重,里面有很多UI的元素,当时UGUI,我们觉得不够成熟,因为刚刚推出不久,我们就选控件相对比较多的ugui来做。

  到了今年的话,5.6是一个大的更新,非常大,相对2D而言,功能也很多。我们5月5号在Steam上面推出汐的游戏,这个汐的UI不是特别重,这个游戏在后面案例分享会详细讲到。还有一款现在正在开发的超脱力的系列,也是完全用Ngui和sprite,这个我待会儿也说一下。

  我现在就说,我后面有两块,一块是汐,我先说汐的技术分享,简单说一下。我们先看一下视频。就是从视频可以看到是一个平台跳跃类的游戏,内部开玩笑,这个新的正确打开方式,你在旁边备一个手柄和备一个键盘,因为这个游戏非常难,会难到令你抓狂,可能会把手柄和键盘砸到。其实汐是一个2D卷轴游戏,就使用了大家非常熟悉的Parallax scroller,有好多层,每一层都做卷轴运动,一般来讲,层会分几大部分,不一定是这三大部分,就是近景、背景、远景这样,但是在游戏里面分的层是比较多。

  实际上最早FC上面的超级玛丽也是用这种方式来表达的,超级玛丽大致关卡的样子是这个样子,这个关卡有很大的特点,特点是里面的物件几乎都是可以重用的,随着卷轴的滚动,我可以把一些重复的,像管道,或者是后面的云什么的重复地把它做出来,把它放上去就可以了。相对来说比较有规律,程序也可以很方便地来实现。

  这是我们汐的场景,在Unity编辑器里面的场景,这还只是部分,没有完全截得下来。其实大家可以看到这个汐的场景是完全没有规律,不是很简单,横向的卷轴就完事了,上面有高度,还有关卡的设计。我们在制作上面,基本上有一个原则,我不限制你怎么样拼,你可以随便在游戏里面拼出你想要的游戏,这是layout,给我们拼出的样子,很复杂。

  基于美术这种要求,或者说基于layout的要求,不可能做到重复性,不可能做到循环每件事情。然后里面的场景会非常多,大家看到这边没有一个小白框,小白框,比如在右下角有一个小白框,那个代表一个屏幕,能够显示的内容,大家可以大概估计一下,这里面有多少内容要显示。这就带来一个最直接的问题,场景我要怎么样去动态地管理。因为我不可能一加载就把这么多产品全部加载进来。虽然说显示Unity可以自动裁掉,但是场景加这么多是不可以接受,内存也接受不了。

  我们就简单说一下场景的管理方式,在随便某一个关卡里面,我们基本上所有的这个子物体八千多个,八千多个不是所有,只是一部分,这个图大家可以看到,在左下角有一个白框,那个白框就是一开始玩家的出现点,就是你们能看到的一个屏幕的大小。这还只是游戏的第一部分,后面会讲到把游戏切成好多哈多scene,就是刚才所说的第一个方面就是切scene,我们把游戏分成几个章节,这样切一次可以把八千多个物体切成一千多个左右。完了之后,你都去显示,同时都去加载的话,也不行,有没有什么好的办法,我们想到跟Cam做一个AABB,所有物件在场景里面都有自己的包围,都有自己的碰撞,我们camera也有自己的,很容易算出来,就很简单做一个AABB的测试,跟AABB相交,那就说明应该出现在屏幕上面,那就显示出来,否则的话我们就把它Detach,Detach不光光是不显示,应该是被摘掉了。

  还有一个办法进一步优化,其实是有的,你如果在场景里面对一千个物体跟cam之间做一个AABB做一个测试,这个消耗量也是非常大,是什么办法,其实有一个很现成的办法可以用,就是按照空间的关系,把它加到四叉树进行管理,这个时候跟AABB做测试,不是跟某一个特定的物体做AABB做测试,是用四差数的节点做AABB的测试就可以了,只要跟这个节点命中、相交,下面所有子物体都显示,否则的话都不显示,这是一个以空间换时间的方法。

  怎么样把物体加到四叉树里面,这个四叉树本身并不是均分的,因为场景是任意的,就是根据策划或者说需求,有些地方摆的物件比较少,有些地方摆的物件比较多,所以我们在划分四叉树本身的时候,并不是在整个空间里面均分四叉树,而是根据关卡的特性,物件多的地方我们四叉树分的密一些。物件少的地方,四叉树分的细一点,放入四叉树很简单,就是把这个物件的AABB跟四叉树本身做一个比较,如果命中的话就放进去。但是这里面有两点要注意,一点是说,静态的物件是没有问题,但是动态的物件不行,还要做进一步的处理。

  第二点是说,有可能一个物件,会凸显在两个四叉树节点中,这个时候怎么办,跟两个四叉树节点都相交怎么办,我们的办法是两边都放,这样其实以空间换时间效率,也没有太多的问题。还有一点我们物件并不是在逻辑上仅仅简单的是一个概念,也可能在场景里面有很多,会组成一个大的机械装置,齿轮或者是其他的东西,我们会把这一个大的所有的东西包成一个碰撞盒,然后把它跟AABB,四差数的AABB做测试,放到某一个节点里面去,相对来说比较灵活,并没有强制一定在这个层面上,可以组合起来。

  在这个优化之后,使用的四叉树优化之后,我们一个场景的数量基本上降到了260左右,从八千左右降到260个,所以卷轴的性能提升的是非常明显的。这里有一段视频,麻烦播放一下,我们看一下四差数的命中情况。可以看到那个数页是动态的创建出来,是根据Cam的运动情况,动态地创建出来。

  总结一下就是说,怎么样去减少这个场景里面的物件的挂载,你要减少Children的Transform数,用四差数来管理,用AABB来进行碰撞的检测,通过这种比较简单的方法可以很好的提升整个游戏的性能。

  说完汐,我来说一下《超脱力医院》,超脱力医院是一个Isometric维的游戏,这个特点就是说,有人称它为2.5D,最大的特点你以45度的角去看上去,游戏的场景就是很3D化,但是实际上用的2D的面片来表达出来,地图上分成N×N的格子,每个物体都在一定的格子,就这样的。也是最简单的排序方式就是以Y轴来进行排序,所以说你玩这个大小,就决定了里面格子的描绘的先后顺序,这是最简单的方法。但是这是有问题,因为我们超脱力医院里面用这个方法,但是后面发现有很多的问题,有很多坑。先来看一段视频,这个视频被压缩过了。每一间诊室都是用这个做的,玩家到里面可以扩展一下。

  Isometric有不足的地方,我们在做超脱力医院的时候发现有很多不足的地方。主要来说有两点,第一点就是地图编辑器,我们原来用的是第三方开源的地图编辑器,他基于windows frame,就只能在windows,最终显示出来和导到Unity里面有很大不同。这个排序是Y轴排序,我旁边有一张图,如果按照Y轴排序的话,其实这个彩色的方块应该在绿的后面,现在反而在前面,这就是引出来的问题,我们其实想要表达的是在后面,但实际上是在前面。就是基于各种各样原因,但是在超脱力医院后续的,我们想解决自己的问题。

  这是续作的改进,右边这张图是后来续作目前的样子,当然这不是最终的。我们提了几个要求,第一个编辑器肯定要所见即所得,不希望两个编辑器之间来回倒腾,这是一个要求。第二个我们支持层高,所谓层高,就是要有楼梯,要有第二层楼,整个房间,有一层两层,第三个有地图光照,有白天有晚上。

  这是原来用的地图编辑器,我写了一个旧,你可以看到是用windows frame做的,首先只能在windows平台,第二个有一个限制,这个地图大小不能有很大,如果做很大,我们就做四个,把四个在游戏里面拼出来,这个制作来说,效率是下降的。第三个独立游戏之外,所以你经常发生说,这个做到后面,这个设备的很好,放在Unity里面一看,完全不是这么回事,又不是拼的很好,这也是一个很大的问题。

  所以我们现在把它改进了一下,改进的方法实际针对上面几点,一个是把它直接再在UnityEditor里面上面这张图,看我们自己做的界面,最右边是物品的列表,有一些预览图,可以放到游戏当中。好处就是跨平台,刚才也说了,做在Unity里面,就不担心在其他平台上不能运行了。这边也没有区域限制,基本上就是内存限制了,内存有多少,我们就可以用到多少,在Unity里面有施展。最重要就是做到所见即所得,也就是现在的地图编辑器是这样,在游戏里看到的就是这样。你可以很方便在里面进行编辑,然后也不需要把这个数据导出来,导到原品里面进行检查,可以直接编辑,就很方便。

  另外一个问题就是所谓的排序算法,我刚才说了,排序算法最最方便的,就是根据Grid的Y值来进行排序,根据Y的大小然后来决定这个是在之前还是在之后。有几个问题,最主要的是我们遇到最主要是这样一个问题,首先两个物件蓝的和绿的,按照Y轴来说,相安无事。虽然说它们都是在同一个Y值上,我们会以一个默认的方法来决定谁先画谁后画。比如决定从屏幕的左边到右边,左边的物体先画,右边的物体后画,这样就很简单,蓝色的先画绿色的后画,互相之间没有遮挡关系所以很OK,没有关系。

  第二张图,我在中间加了一个红色的物体,当然只有Grid,Y轴也是向,按照刚才的描绘顺序也是没有问题,实际上先画蓝色的,再画绿色的再画红色的,所以也是相安无事。现在问题出现了,我们画一个长长的物体,就是红色的,我把它拉长,在这种情况下,你可以看到,他们的Y轴,先说红色的物体这个中心,这个中心跟上一张红色物体的中心是一样的。按照这个描绘顺序来说,因为Y值是相同的,所以描绘的顺序也是先是蓝色,然后再是红色,然后再是绿色。这种情况下,显示的很好,也没有问题。

  如果把红色的这个长条换一个角度,其实对于排序来说,它没有发现任何的变化,为什么?因为红色的中心还是在那个点,蓝色的中心也还在那个点,绿色的中心也还在那个点,所以它们的值Y轴是相同,按照相同的描绘顺序来看,我先画红的,再画蓝的,再画绿的,这不是我们想要的,我们想要的是这个红色被绿色的挡住,我们想要的是最后这个图的样子。这是传统的排序最要命的问题,就是说如果所有的物件都是在一个Grid的里面,老老实实本本分分没有问题,游戏当中不可能是这样,肯定有大大小小的物体,肯定会显示的时候占用多个Grid但是中心却只再一个grid上进行计算,这样的话就会带来显示上的问题。

  我们聊一下,我们怎么改进,想办法去改进,我们自己也讨论过很多的解决方案,其中的一个解决方案,把红色的物体切成小块,按照Grid。因为切成好多细分的小块,每块都有自己的Y,就很简单,就按照这个东西来进行排序了。这里面其实会有一些问题,就是说这个给美术造成一定的工作量。为什么这么讲,因为美术在画的时候,是一个思维的整体,把它从程序上硬切,切完之后再去做这件事情,有可能一时半会儿没办法理解,或者设计的时候造成困惑,这是一个。第二个很简单,你也增加程序的工作量,本来一个grid计算,现在分成十个,就多了十倍,这是一个。

  我们还想用第二种方式,我们确定周围的Grid,这个红色的物体,长的物体,确定周围跟它相关的Grid,然后针对这些Grid做特殊的处理,或者做特殊的排序操作,这样也是可以的。但是这引来另外一个问题是说,你要对这些相互有影响的Grid做一个标识,或者做一个特定的偏移或者什么。这个其实对程序后面的编辑产生一定的影响。还有一个就是说,你就算用了这种方法,也没有办法去实现我们要求的这个层高,就是刚才说有楼层,一层两层这样的一个要求,所以我们最后定下来的这个方案是所谓的建立3D的包围盒,可以理解为3D的碰撞盒,用来计算最终的排序。到了这一点上,其实Grid对于我们排序来说已经不重要了,一个物体到底是不是在grid上,我们不关心。完全按照这个3D的模型,进行3D空间的碰撞计算,然后再做前后的关系,这样就算是有层高,也没有关系,因为我们可以很容易地,层高有自己的3D碰撞盒,楼梯,包括第二层楼,如果是这样的话,跟第一层的做3D碰撞,也可以很容易计算出先后关系。

  这个就是我们编辑器里面的,可以让策划,可以方便去,或者程序可以方便去定制三维包裹盒,就是属于地图编辑器的一部分,可以看到,的那个框其实就是三维的包裹盒,下面说的值,红色的框里面,框出来的三个值,其实是真正进行3D计算。但是有一点要说明,就算3D,我们用的也是一个整形,就为了方便计算,还有效率上的考虑。

  这样玩了之后,其实很好对3D物体里面,3D空间里物体做一个排序,实际上排序还是分两种方式,一种叫全排序,一种叫做局部排序,这也是为了效率的考虑,因为物件太多,如果所有物件都做3D,所谓全局排序很简单,就是场景里面所有东西都排一次,就这样。全局排序,是有特定的时间才会做这样的事情,一个是游戏载入。因为游戏载入的时候把场景全部载出来,这个时候做一次全局排序。还有访问其他玩家的地图,因为我们是一个弱社交的游戏,可以看到其他的玩家他们自己的地图是什么样的,还会有一些互动,当你看别人地图的时候,我们也会进行一个全排序,相当于也是一个关卡的加载。

  解锁大块区的时候,我们游戏是分大的区域,大区域解锁的时候,这个区域里面本身会有一些很大的物体,有一些很重的物体,在这些物体的描绘上面,我们也采取全排序的方式。相对来说有了全排序就会有局部排序,局部排序的概念,我只排其中很小很小的一部分。在这里我们引入了一个叫做基座的概念,所谓基座是这样,所有玩家可以修改的部分,因为我们这个游戏允许玩家可以装饰自己的办公室,装饰自己的街道这样子,摆一个路灯,摆一个花盆这样。在这里可以自定义的地方就引入一个叫做基座的概念,在这个基座上面,我们留出大概50到100个空间,这是排序的值,最后排序的值留出来。在基座进行物件摆放的时候,就直接在基座的偏移上面加上,那基座只需要排一次就完了。

  最重要的东西就是移动的物件,所有东西都是静态,只要排一次就完事了,就很完美,但实际上里面有人走来走去,人会跟静态的物件之间发生排序关系顺序的一个变化,这件事情怎么解决呢?我们的做法是说,所有在游戏里面移动的物体,都是用路点控制,实际上不可以随便乱走。路点本身是一个3D的点,其实是跟刚才的物件的包围盒在一个坐标空间里,我们只需要对路点和包围盒进行排序,能确定前后关系。另外一个问题我走在两个路点之间怎么办,就走一个线性差值设置就行了,也可以比较好的解决这个问题。我今天分享就到这里,谢谢大家。

内容结束代码 人物, 椰岛游戏, 徐步诣111111111111111111111111111111111111111锐亚教育

锐亚教育,网络游戏,网游,新游,游戏,新闻,国内,全球,评论,资讯,专题,图片,焦点,排行,免费,私服,魔兽,传奇,西游,泡泡堂,冒险岛,征途,劲舞团,劲乐团,公会,外挂,17173,玩家,测试,内测,封测,公测,试玩,调查,flash