最近学了下Unity,先跟官方教程走了个3D碰撞球的小游戏的教程。然后实现了“合成同学小游戏“,借鉴合成大西瓜的游戏机制。
Unity介绍
unity是一个游戏引擎,帮助快速开发游戏。个人觉得unity的一大优势是跨平台编译(虽然其它平台也可能有跨平台编译),比如”合成同学小游戏“是2D休闲类游戏,第一需求是就是便捷性,因此web是最合适的平台。
Unity WebGL编译
unity WebGl编译可以直接产出js、data、css、html、wasm和图片使游戏可以直接运行在web端。
在编译对象的时候有三种压缩方式br、gzip和不压缩。br是google提出的web内容压缩格式压缩率最高也是unity默认的格式。我摸索的上线模式就是把这些生成的内容以http文件传输的方式提供给客户端访问。既然br(Brotli)的压缩率最高自然而然就作为了第一选择,但我在使用过程中遇到了一些问题,最终选择了更稳定的gzip,下面讲一下具体原因。
safari使用不灵?使用br压缩方式遇到的问题
因为上线服务的方式就是把编译出的js、data、css、html放到服务器服务,这些编译内容以index.html为核心组织,客户端GET domain:port/index.html后index.html中的js代码会在客户端浏览器执行对其它js、data、css资源进行GET请求。当所有内容正确在客户端载入时游戏就可以玩了。
但对于内容的压缩格式,在http协议中要客户端和服务端要对压缩格式进行约定。
1 | 客户端先发起请求在Header中添加: |
1 | 服务端在返回的Header中添加: |
但我在使用python写了一版br http服务端代码后发现window上能正常运行,但在Safari上客户端的http请求Accept-encoding没有br),怀疑是兼容性问题,遂搁置问题转向gzip。
Unity editor
“下面来聊聊unity本身”
unity editor本身由六大部分组成
1.hierarchy
2.project
3.console
4.game
5.scene
6.inspector
从游戏角度看组织结构如下:
scene
gameObject1
component1(transform)
component2(rigidbody)
component3(collier)
component4(C# script)
gameObject2
gameObject2
unity中的类和实例
类和实例是在编程中一个常见的概念关于类和实例:
1.在代码中通过Instantiate()函数实例化(Instantiate中传入的也是实例,Instantiate返回对该实例的拷贝)
2.在unity中hierarchy中的内容都是实例,
3.C#脚本中声明并在inspector中拖拽赋值的实例变量
此外GameObject是类,gameObject是实例
刚体和碰撞
刚体(rigidbody)该component给游戏对象增加物理属性,如重力重量
碰撞(collider)只有两个游戏对象都启动这个component时才会检测到碰撞,碰撞分为两类
1.Collision,造成物理碰撞,可以在碰撞时执行OnCollision函数。
OnTriggerEnter
2.Trigger,取消所有物理碰撞,可以在碰撞时执行OnTrigger函数。
OnTriggerEnter、OnTriggerStay、OnTriggerExit
这两种方式通过在inspector中点击is trigger切换
实例间的通信
实例间的通信方法
1.A调用B的情况:
1.1 GameObject.Find(“B”)得到所有名为B的实例的脚本对象通过其访问函数进行访问
1.2 或者在Fruit脚本中增加 public Game;并将Game实例拖拽过去dd
1.3 将B中要调用的内容使用static预实例化
2.A实例内产生B的情况:
因为实例在脚本中instancelize 因此可以直接对该实例操作
遇到的其他问题
1.对象碰撞逻辑重复执行导致陷入死循环
问题描述:因为游戏逻辑是两个相同对象碰撞后合成一个更大的对象,但碰撞发生时两个对象都调用OnTriggerEnter2D分别产生的一个更大的对象,两个更大的对象又彼此碰撞无限循环
解决办法:在碰撞发生时通过object.GetInstanceID(),比较两个对象的id只有id更小的才能执行合并操作。
2.A和B、C同时碰撞
预期 实际
问题描述:A和B、C同时碰撞生成了两个更大的对象,但预期是只能和其中一个发生碰撞合成一个更大的对象
解决办法:使用static建立了一个hash,key为实例id,在合并前先查看实例是否存在。合并在该hash中移除相应实例id