Unity小游戏开发----记录与思考

前言

  • 离职网易已经5个月了,这段时间一直在沉淀自己,尝试摸索一些新的技术,最近花了一点点时间做了一个Unity小游戏,感受了一下作为一个独立游戏开发者的一点开发流程,先做一个小小的总结:

作为一名独立游戏开发者,要掌握的东西太多了!一定会比想象中的多很多,抛开优化不谈,就单纯的功能设计和数值设计,就能噶掉一大批无脑决定独立开发的人。要想真正完成一款游戏的开发,至少需要拥有的能力包括但不限于:玩法策划、数值策划、逻辑框架设计以及功能实现能力。其中前面两个对应策划能力,后面两个对应程序能力,拥有了这两个能力之后,配合购买一些素材即可实现一个完整的游戏功能,当然只能保证完整,而不能保证体验(笑)

成果展示

b站: 自制油管小游戏v0.1.0版

游戏截图(v0.2.1版):
在这里插入图片描述
忽略一下截图里面超高的历史分数,以及旁边的GM指令,这个游戏的玩法主要就是模仿油管里打广告的那种,由于只能看不能玩,就心血来潮自己做了一个玩玩,然后这一做,就把这篇文章做出来了!

技术总结

乍一看这游戏挺简陋的,貌似实现起来挺容易,但实际上,如果考虑这个游戏需要在手机端运行的话,那么马上就会有一大堆的问题。

对象池(多个同类型的不同对象公用一个对象池)

首先就是频繁进行角色的生成和销毁,这里给出的解决方案就是最常见的对象池,使用对象池来减少对prefab的频繁生成和销毁,而是改为SetActive(true)和SetActive(false),这样就能极大的减少这部分的性能开销,具体实现如下:
使用Unity自带的PoolSystem,新建一个脚本,脚本做成单例模式方便获取(不做也可以,那在每个调用的地方引用到这个脚本即可),创建一个ObjectPool<对象脚本>的对象池,同时实现它的Create、Get、Relase、Destory的功能,并初始化对象池变量。
这里详细讲一下细节,由于我的游戏设计,玩家一共可以有三种等级形态的角色,普通情况下,为了保证能正确的取出正确形态的角色,一般需要用到三个对象池,分别用于存储三种不同的角色,这样自然能实现需求,但有没有更好的方法呢?或者说,能否通过一个对象池就实现这种功能呢?答案自然是可以的,而这一功能的实现重点就在于,将三种形态的对象保存在同一Prefab中,这么一来不就自然实现了一个对象池保存三种形态的角色,具体的实现方式就是用一个空对象,将我们具体的不同对象添加为子物体,再绑上一个大类型的脚本,例如我的角色就叫Character,那么我就来这么一个脚本,脚本中添加一个Init函数,这个函数用于在Get对象后,再手动调用Init初始化一个我们自己需要的具体角色出来,至于一些角色的具体属性,则完全可以使用ScriptableObject储存起来,然后设定一个对应的方式调用后,在Init里赋值就好了,相当的方便简洁。

// 一个简单的调用和初始化
Character character = CharacterFactory.Instance.CharacterPool.Get();
character.Init(index, Config.ListHealth[index], Target.position - new Vector3(0, 0, 5), transform.rotation, this);

NavMesh寻路以及烘焙(NavMeshSurface指定对象烘焙)

第二个性能开销的大头是寻路导航烘焙,毕竟,地砖一块一块的随机生成,那么敌人一批一批的生成自然寻路也是要变的,那要给新生成的地砖加入到导航中自然要重新烘焙才是,第一个想到就是去找AI插件,UnityAsset Store里最高评价的A寻路插件就成了我的首要目标,但价格过于昂贵,且在其他文章中有提到A寻路插件的动态烘焙性能不够好,于是乎我又转回了使用Unity自带的NavMesh,NavMesh的底层也是A*实现的,理论上来说性能也不会差到哪里去,但是动态烘焙怎么办呢,查看官方文档,发现Unity有一个开源的项目,里面有一套Unity NavMeshComponent,其功能就是使用了NavMesh为底层设计了一套功能更加完善的寻路,尤其是NavMesh Surface组件,刚好就是我想要的动态烘焙功能的核心,它可以挂在一个对象上,然后仅对此对象与连接了此对象的对象进行烘焙,而不是全场景静态烘焙,这样就实现了静态烘焙NavMesh。

GPU Instance以及GPU动画(解决SkinMesh 无法GPU实例化的问题)

大伙用多了Unity的都知道,当场景内的渲染对象过多的时候,drawcall就会相应的大量提升,drawcall越高,CPU的压力也就越大,在移动端这种需要每一滴性能的地方,怎么降低drawcall也是非常重要的,而降低drawcall的方法无非就是合批(静态合批和动态合批)以及实例化(GPU Instance和SRP Instance),由于场景是动态变化的,使用我这里选用的是GPU Instance来进行drawcall的降低,而查过相关资料或者再懂一点Unity的小伙伴也会知道SkinMesh蒙皮网格是没法做到GPU Instance的,那我们就需要用到GPU动画,将SkinMesh+Animator转为Mesh加Shader实现,因为动画实际上就是顶点的移动,只不过一个在CPU上计算顶点移动,一个在GPU上计算顶点的移动,这里就简单的给出思路,具体的实现有空再写一篇文章。
动画文件Clip实际上就包含了顶点坐标的移动,每一帧都有顶点信息,我们将这些顶点信息收集起来,每一帧都能获得一组坐标信息,然后让GPU读取这些坐标信息并展示出来就好了,那怎么让GPU读到这些信息呢?思考一下,坐标是不是一个Vector3值,而图片的每一个像素点都是由RGB组成,这不是很好的对应上了?当然我们需要做一点简单的映射,毕竟RGB的每一个值都在0-1之间,而Vector3的坐标,可能是任何值,这里不给出算法,仅讲思路,我们只需要映射一下,读取的时候反向映射就得到了,这样自己写一个shader就能实现这个动画的功能了,当然这是最简单的实现方法,更丰富的其他做法可以去看看其他大佬的文章。这里我给出这一步的一个流程图
在这里插入图片描述

还未解决的问题

这里我讲的一些技术总结基本都是一些程序上的,正如我开头说过的,做游戏需要的几个基本技术包括策划,而刚好,我一窍不通!毕竟纯程序出身,策划之类的可以说压根没接触过,要说设计玩法和设计剧情什么的,想象力丰富就可以做到,数值策划这一项就是没有入门的话就是不可能做好,这也是我目前打算学习的东西,如果各位大佬有什么推荐学习数值策划的让小弟学习一下那就最好了。

写在最后

很早就想写一篇文章记录一下游戏开发的一个流程,但是自己又懒,老是不想写,而且也怕写不出什么来,写了又会误解读者,就一直拖着,最后是闲着实在没事,想着总得写点什么吧才写的这篇文章,没有啥很高深的技术,也没有这些技术的具体实现,纯白开水文,大伙就当看个乐子,如果能在思路上帮助到你那就更好了,也欢迎大家评论私聊我,大伙一起学习一起进步,祝各位前程似锦!

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值