Unity3D手游开发执行

A survey of garbage collection and the changes CLR 4.0 brings in –
series of what is new in CLR 4.0
导言Introduction
  垃圾回收(Garbage Collection)在.net中是一个很重要的机制.
本文将要谈到CLR4.0对垃圾回收做了什么立异. 为了更好地知道这么些革新,
本文也要介绍垃圾回收的历史.  这样咱们对总体垃圾回收有一个大的印象.
这一个大影像对于我们领会.net架构是有帮扶的.

《腾讯桌球:客户端总计》

  Garbage Collection is an important component of .net. The post will
talk about what has been improved in CLR 4.0. To understand it, I will
take a survey of the history of garbage collection. This way we can have
a big picture of garbage collection. This will help us master .net
architecture in comprehensive manner.

本次分享总括,起源于腾讯桌球项目,不过不仅仅限于项目自身。即使基于Unity3D,很多事物一样适用于Cocos。本文从以下10大点举办阐释:

至于垃圾回收About Garbage collection
  在C++时代,我们需要协调来保管申请内存和假释内存. 于是有了new,
delete关键字. 还有的片段内存申请和刑满释放函数(malloc/free).
C++程序必须很好地保管自己的内存, 不然就会促成内存泄漏(Memory leak).
在.net时代, 微软为开发人士提供了一个强有力的体制–垃圾回收.
垃圾回收机制是CLR的一有的, 我们决不担心内存啥时候释放,
大家可以花更多精力关注应用程序的业务逻辑.
CLR里面的污物回收机制用自然的算法判断某些内存程序不再利用,回收这么些内存并交付大家的程序再使用.

  1. 架构设计

  2. 原生插件/平台相互

  3. 本子与补丁

  4. 用剧本,依然不要?这是一个问题

  5. 资源管理

  6. 特性优化

  7. 异常与Crash

  8. 适配与配合

  9. 调节及开发工具

  10. 连串运营

  In the times of C++, we need to allocate and release memory by
ourselves carefully,  therefore there are new, delete keywords in C++,
and fuctions(malloc/free) to allocate and release memory. C++ program
has to manage its memory well, otherwise there will be memory leak. In
.net, Microsoft provides a strong machanism to developers—Garbage
collection. The Garbage collection is part of CLR. We do not need to
worry about when to release memory. We can spend more time on buisness
logic of applications. The Garbage colleciton of CLR adopts algorithms
to decide which part of memory the program does not need any more, and
then release these memory for further use.

图片 1图片 2图片 3

垃圾回收的功效The functionalities of Garbage collection
  用来管理托管资源和非托管资源所占据的内存分配和自由。In charging of the
releasing and re-allocation of memory of managed and unmanaged
resources.

 

  寻找不再利用的目的,释放其占据的内存, 以及释放非托管资源所占有的内存.
Find the objects no longer needed, release the memory the objects
occupied, and affranchise memory occupied by unmanaged resources.

1.架构设计

  垃圾回收器释放内存之后, 出现了内存碎片, 垃圾回收器移动部分对象,
以博得整块的内存,同时具备的靶子引用都将被调动为指向对象新的存储地方。After
releasing the memory no longer needed, there is memory scrap. Garbage
collector shifts objects to get consecutive memory space, and then the
references of objects will be adjusted according to the shifted address
of objects.

图片 4

下边大家来看望CLR是何许保管托管资源的. Let’s see how CLR takes care of
managed resources.

好的架构利用常见项目的六个人集体开发和代码管理,也利用查找错误和先前时期维护。

托管堆和托管栈Managed heap and Managed stack:
.net
CLR在运转我们的顺序时,在内存中开拓了两块地点作不同的用处–托管栈和托管堆.
托管栈用来存放在局部变量, 跟踪程序调用与返回. 托管堆用来存放引用类型.
引用类型总是存放于托管堆. 值类型一般是身处托管栈上边的.
如若一个值类型是一个引用类型的一有些,则此值类型随该引用类型存放于托管堆中.
哪些东西是值类型? 就是概念于System.ValueType之下的这么些品种:

  • 框架的选项:需要基于公司、项目来进展精选,没有最好的框架,只有最合适的框架。

  • 框架的应用:统一的框架能规范大家的作为,相互之间可以相比平缓切换,可维护性大大升级。除此之外,仍是可以代码解耦。例如StrangeIOC是一个超轻量级和中度可扩展的操纵反转(IoC)框架,专门为C#和Unity编写。已知集团里面使用StrangeIOC框架的游艺有:腾讯桌球、欢乐麻将、植物大战僵尸Online。<https://github.com/strangeioc/strangeioc>

bool byte char decimal double enum float int long sbyte short struct
uint ulong ushort

 

When .net CLR runs our program, CLR declares two ranges of memory for
different purposes. Managed stack is to store local variables, and trace
the call and return of routines. Managed heap is to store reference
types. Usually value types was put on managed stack. If a value type is
a part of a reference type, then the value type will be stored in
managed heap along with the reference type. What are value types? They
are the types defined in System.ValueType:

依赖注入(Dependency Injection,简称DI),是一个首要的面向对象编程的法则来减弱总结机程序的耦合问题。依赖注入还有一个名字称为控制反转(Inversion of Control,英文缩写为IoC)。依赖注入是如此一个历程:由于某客户类只依靠于服务类的一个接口,而不依靠于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运转上下文环境特别组件肩负实例化服务类,然后将其注入到客户类中,保证客户类的正常运转。即对象在被成立的时候,由一个周转上下文环境或专门组件将其所依靠的服务类对象的引用传递给它。也可以说,依赖被注入到目的中。从而,控制反转是,关于一个对象咋样拿到她所依赖的目标的引用,这多少个责任的反转

bool byte char decimal double enum float int long sbyte short struct
uint ulong ushort

 

怎么是援引类型呢? 只要用class, interface, delegate, object,
string讲明的连串, 就是引用类型.  What are reference types? The types
declared with class, interface, delegate, object, stirng, are reference
types.

图片 5

俺们定义一个有些变量, 其品种是援引类型. 当大家给它赋一个值, 如下例:We
declare a local variable, which is a reference type, and we assign a
value to the local variable, like the following:

 

private void MyMethod()
{
   MyType  myType = new MyType();
   myType.DoSomeThing();
}
在此例中, myType 是有些变量, new实例化出来的目标存储于托管堆,
而myType变量存储于托管栈.
在托管栈的myType变量存储了一个针对托管堆上new实例化出来目的的引用.
CLR运行此措施时, 将托管栈指针移动, 为一些变量myType分配空间,
当执行new时, CLR先查看托管堆是否有充裕空间,
充裕的话就只是简短地运动下托管堆的指针, 来为MyType对象分配空间,
若是托管堆没有充分空间, 会引起垃圾收集器工作.
CLR在分配空间此前,知道所有品种的元数据,所以能领略各种门类的深浅,
即占用空间的大小.

StrangeIOC选取MVCS(数据模型 Model,显示视图 View,逻辑控制 Controller,服务瑟维斯(Service)(Service))结构,通过音信/信号举办互相和通信。整个MVCS框架跟flash的robotlegs基本一致,(忽略语言不雷同)详细的参考<http://www.cnblogs.com/skynet/archive/2012/03/21/2410042.html>。

In this sample, myType is a local variable. the object instantiated by
new operation is stored in managed heap, and the myType local variable
is stored in managed stack. The myType local variable on managed stack
has a pointer pointing to the address of the object instantiated by new
operation. When CLR executes the method, CLR moves the pointer of
managed stack to allocate memory for the local variable myType. When CLR
executes new operation, CLR checks first whether managed heap has enough
space, if enough then do a simple action – move the pointer of managed
heap to allocate space for the object of MyType. If managed heap does
not have space, this triggers garbage collector to function. CLR knows
all the metadata of types, and knows the size of all the types, and then
knows how big space the types need.

  • 数据模型 Model:紧要承担数据的蕴藏和大旨数据处理

  • 显示视图 View:重要承担UI界面体现和卡通片表现的拍卖

  • 逻辑控制 Controller:首要承担作业逻辑处理,

  • 劳动瑟维斯(Service)(Service):重要担负独立的网络收发请求等的一部分意义。

  • 音讯/信号:通过音讯/信号去解耦Model、View、Controller、Service(Service)这四种模块,他们之间通过消息/信号举办相互。

  • 绑定器Binder:负责绑定信息处理、接口与实例对象、View与Mediator的应和关系。

  • MVCS Context:可以清楚为MVC各类模块存在的上下文,负责MVC绑定和实例的开创工作。

当CLR完成MyMethod方法的履行时, 托管栈上的myType局部变量被当下删除,
不过托管堆上的MyType对象却不必然立即删除.
这有赖于垃圾收集器的触及条件.前面要介绍此触发条件.When CLR finishs
execution of MyMethod method, the local variable myType on managed stack
is deleted immediately, but the object of MyType on managed heap may not
be deleted immediately. This depends on the trigger condition of garbage
collector. I will talk about the trigger condition later.

图片 6

下边大家询问了CLR咋样保管托管资源.
下边我们来看垃圾收集器怎么着寻找不再采纳的托管对象,并释放其占据的内存. In
previous paragraphs, we learn how CLR manages managed resources. In
following paragraphs, we will see how garbage collector find objects no
longer needed, and release the memory.

腾讯桌球客户端项目框架

污染源收集器怎样寻找不再利用的托管对象,并释放其占据的内存How garbage
collector find objects no longer needed and release memory
前边大家询问了CLR怎么样管理托管栈上的对象.遵照先进后出原则即可相比易于地管理托管栈的内存.
托管堆的治本比托管栈的军事管制复杂多了.下面所谈都是对准托管堆的管理. In
previous paragraphs, we learn how CLR manages the objects on managed
stack. It is easy to manage managed stack as long as you utilize the
rule “first in last out”. The management of managed heap is much more
complicated than the management of managed stack. The following is all
about the management of managed heap.

 

根The root
垃圾收集器寻找不再动用的托管对象时,
其判断依照是当一个对象不再有引用指向它, 就表达此目的是可以释放了.
一些错综复杂的情形下可以出现一个对象指向第二个目的,第二个对象指向第三个目标,…就象一个链表.
那么, 垃圾收集器从哪个地方初始查找不再行使的托管对象呢?
以刚才所说的链表为例, 显然是应当从链表的上马起首查找.
那么,在链表开始的是些什么东东啊? The criteria garbage collector uses to
judge whether an object is no longer needed is that an object can be
released when the object does have any reference. In some complicated
cases, it happends that the first object refers to the second object,
and the second object points to the third object, etc. It is looking
like a chain of single linked nodes. Then the question is : where does
the garbage collector begins to find objects no longer needed? For the
example of the single linked node chain, we can say it is obvious
garbage collector starts from the beginning of the chain. Then the next
question is: what are the stuff at the beginning of the chain.

  • 代码目录的公司:貌似客户端用得相比多的MVC框架,怎么划分目录?

    • 先按工作职能区划,再按照 MVC 来划分。”蛋糕心语”就是利用的这种艺术。
    • 先按 MVC 划分,再按照工作职能区划。”D9″、”宝宝斗场”、”魔法花园”、”腾讯桌球”、”欢乐麻将”使用的这种措施。

是部分变量, 全局变量, 静态变量, 指向托管堆的CPU寄存器.
在CLR中,它们被喻为根. The answer is : local variables, global
variables, static variables, the CPU registers pointing to managed heap.
In CLR, they are called “the roots”.

图片 7

有了始于点, 垃圾收集器接下来咋办呢? Got the roots, what will garbage
collector do next?

 

创设一个图, 一个描述对象间引用关系的图. Build a graph, which shows the
reference relationship among objects.
垃圾收集器首先假定所有在托管堆里面的对象都是不行到达的(或者说没有被引述的,不再需要的),
然后从根上的这多少个变量起始, 针对每一个根上的变量,
找出其引用的托管堆上的目标, 将找到的靶子出席这几个图,
然后再顺着那么些目标往下找,看看它有没有引用此外一个目的,
有的话,继续将找到的目标出席图中,如若没有的话,
就表明这条链已经找到尾部了. 垃圾收集器就去从根上的此外一个变量开始找,
直到根上的富有变量都找过了, 然后抛弃物收集器才告一段落查找. 值得一提的是,
在搜寻过程中, 垃圾收集器有些小的优化, 如:
由于目的间的引用关系可能是相比较复杂的, 所以有可能找到一个目的,
而此对象已经参与图了, 那么垃圾收集器就不再在此条链上继续搜寻,
转去此外的链上继续找. 那样对污染源收集器的性质兼备改正.

按照使用习惯,可以自行选用。个人推举”先按工作功用划分,再遵照MVC 来划分”,使得模块更聚焦(高内聚),第两种方法用多了意识随着项目的运营模块增多,没有第一种那么好保障。

First garbage collector supposes all the objects in managed heap are not
reachable( do not have reference, or no longer needed). Then start from
the variables in the roots. For each of the variable in the roots,
search the object the variable refers to, and add the found object into
the graph, and search again after the found object for next refered
object, etc. Check whether the found object has next reference. If has,
continue to add the next found object into the graph. If not, it means
this is the end of the chain, then stop searching on the chain, continue
on next variable in the roots, keep searching on roots, until all the
searching are finished. In the searching process, garbage collector has
some optimization to improve the performance. Like: Because the
reference relationship could be complicated among objects, it is
possible to find an object that has been added into the graph, then
garbage collector stops searching on the chain, continue to search next
chain. This way helps on performance of garbage collection.

  • Unity项目目录的协会:结合Unity规定的一对特种的用处的文本夹,咱们指出Unity项目文件夹协会情势如下。

污染源收集器建好这些图之后, 剩下这么些从没在这么些图中的对象就是不再需要的.
垃圾收集器就足以回收它们占有的空间.After buidling the reference graph
among objects, the objects not in the graph are no longer needed
objects. Garbage collector could release the memory space occupied by
the no longer needed objects.

图片 8

未完待续To be continued…

内部,Plugins匡助Plugins/{Platform}这样的命名规范:

参考文献References
Garbage Collection: Automatic Memory Management in the Microsoft .NET
Framework By Jeffrey Richter 
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

  • Plugins/x86
  • Plugins/x86_64

  • Plugins/Android

  • Plugins/iOS

Garbage Collection Part 2: Automatic Memory Management in the Microsoft
.NET Framework By Jeffrey Richter
http://msdn.microsoft.com/en-us/magazine/bb985011.aspx

假定存在Plugins/{Platform},则加载Plugins/{Platform}目录下的文本,否则加载Plugins目录下的,也就是说,即使存在{Platform}目录,Plugins根目录下的DLL是不会加载的。

Garbage Collector Basics and Performance Hints By Rico Mariani at
Microsoft  http://msdn.microsoft.com/en-us/library/ms973837.aspx

除此以外,资源公司使用分文件夹存储”成品资源”及”原料资源”的主意处理:避免无关资源出席打包,RawResource即原始资源,Resource即成品资源。当然并不限于RawResource这种形式,其他Unity规定的相当文件夹都得以这么,例如Raw
Standard Assets。

http://drowningintechnicaldebt.com/blogs/royashbrook/archive/2007/06/22/top-20-net-garbage-collection-gc-articles.aspx

 

 

  • 店家组件

化妆小游戏
换装小游戏
化妆小游戏
红颜小游戏
古装公主小游戏
化妆仙女小游戏
美容男友小游戏
情人约会小游戏
婚纱礼服小游戏
阿sue小游戏
煮饭小游戏
嫦娥餐厅小游戏
理发小游戏
美甲小游戏
芭比(Barbie)娃娃小游戏
大洋妹小游戏
布置房间小游戏
照顾小宝宝小游戏
祖玛小游戏
老是看小游戏
对对碰小游戏
泡泡堂小游戏
极品玛丽(Mary)小游戏
黄金矿工小游戏
密室逃脱小游戏
魔塔小游戏
找茬小游戏
表露小游戏
双人小游戏
娃娃小游戏
奥特曼小游戏
海绵宝宝小游戏
虹猫蓝兔小游戏
哆啦A梦小游戏
喜羊羊与灰太狼小游戏
搞笑小游戏
恬淡小游戏
铤而走险小游戏
宪章经营小游戏
棋牌小游戏
测试小游戏
政策小游戏
动作小游戏
体育小游戏
神速小游戏
发射小游戏
益智小游戏
归纳小游戏

-   msdk(sns、支付midas、推送灯塔、监控Bugly)

-   apollo

-   apollo
    voice 
-   xlua

脚下我们的腾讯桌球、四国军棋都联网了apollo,然则如若服务器不行使apollo框架,不指出客户端接apollo,而是径直接msdk收缩二次封装信息的丢失和带动的失实,方便未来提拔维护,并且减弱导入无用的代码。

 

  • 其三方插件选型
-   NGUI

-   DoTween

-   GIF

-   GAF

-   VectrosityScripts

-   PoolManager

-   Mad
    Level Manger 

 

2.原生插件/平台相互

图片 9

即便大多时候使用Unity3D举办游玩开发时,只需要使用C#进展逻辑编写。但奇迹不可制止的需要使用和编辑原生插件,例如有些第三方插件只提供C/C++原生插件、复用已有的C/C++模块等。有一些功力是Unity3D实现持续,必须要调用Android/iOS原生接口,比如获取手机的硬件音信(UnityEngine.SystemInfo没有提供的局部)、调用系统的原生弹窗、手机激动等等

 

2.1C/C++插件

图片 10

编排和动用原生插件的多少个关键点:

  • 开创C/C++原生插件
-   导出接口必须是C ABI-compatible函数
-   函数调用约定
  • 在C#中标识C/C++的函数并调用
-   标识
    DLL 中的函数。至少指定函数的名称和包含该函数的 DLL
    的名称。 
-   创建用于容纳
    DLL 函数的类。可以使用现有类,为每一非托管函数创建单独的类,或者创建包含一组相关的非托管函数的一个类。

-   在托管代码中创建原型。使用 **DllImportAttribute** 标识 DLL
    和函数。 用 **static** 和 **extern** 修饰符标记方法。

-   调用
    DLL 函数。像处理其他任何托管方法一样调用托管类上的方法。
  • 在C#中成立回调函数,C/C++调用C#回调函数
-   创建托管回调函数。

-   创建一个委托,并将其作为参数传递给 C/C++函数。**平台调用会自动将委托转换为常见的回调格式。**

-   确保在回调函数完成其工作之前,垃圾回收器不会回收委托。

 

那么C#与原生插件之间是如何贯彻相互之间调用的呢?在弄了解这些题目从前,我们先看下C#代码(.NET上的次第)的施行的进程:(更详尽一点的介绍可以瞻仰我事先写的博客:http://www.cnblogs.com/skynet/archive/2010/05/17/1737028.html

  1. 将源码编译为托管模块;

  2. 将托管模块组成为顺序集;

  3. 加载公共语言运行时CLR;

  4. 施行顺序集代码。

注:CLR(公共语言运行时,Common Language
Runtime)
和Java虚拟机一样也是一个运行时环境,它负责资源管理(内存分配和破烂收集),并确保应用和底部操作系统之间必要的分开。

为了提升平台的可靠性,以及为了达成面向事务的电子商务应用所要求的安静级别,CLR还要承担其他一些任务,比如监视程序的运行。遵照.NET的说教,在CLR监视之下运行的次序属于“托管”(managed)代码,而不在CLR之下、间接在裸机上运行的利用或者零部件属于“非托管”(unmanaged)的代码

这么些过程自己总计为下图:

图片 11


.NET上的程序运行

回调函数是托管代码C#中的定义的函数,对回调函数的调用,实现从非托管C/C++代码中调用托管C#代码。那么C/C++是怎样调用C#的呢?大致分为2步,可以用下图表示:

图片 12

  • 将回调函数指针注册到非托管C/C++代码中(C#中回调函数指委托delegate)

  • 调用注册过的托管C#函数指针

相比较托管调用非托管,回调函数形式有点复杂一些。回调函数卓殊适合重复执行的天职、异步调用等景色下选取

由地点的牵线可以领略CLR提供了C#程序运行的条件,与非托管代码的C/C++交互调用也由它来成功。CLR提供二种用于与非托管C/C++代码举办互动的建制:

  • 平台调用(Platform
    Invoke,简称PInvoke或者P/Invoke),它使托管代码可以调用从非托管DLL中导出的函数。

  • COM
    互操作,它使托管代码可以通过接口与组件对象模型 (COM)
    对象交互。考虑跨平台性,Unity3D不利用那种措施。

 平台调用倚重于元数据在运作时追寻导出的函数并封送(马尔斯hal)其参数。 下图呈现了这一历程。

图片 13

瞩目:1.除关系回调函数时以外,平台调用方法调用从托管代码流向非托管代码,而绝不会以相反方向流动。 即便平台调用的调用只可以从托管代码流向非托管代码,可是数据还可以够看成输入参数或输出参数在六个方向流动。2.图中DLL表示动态库,Windows平台指.dll文件、Linux/Android指.so文件、Mac
OS
X指.dylib/framework文件、iOS中只可以使用.a。后文都使用DLL代指,并且DLL使用C/C++编写

当”平台调用”调用非托管函数时,它将相继执行以下操作:

  • 追寻包含该函数的DLL。

  • 将该DLL加载到内存中。

  • 探寻函数在内存中的地址并将其参数推到堆栈上,以封送所需的数码(参数)。

注意

只在第一次调用函数时,才会查找和加载 DLL 并查找函数在内存中的地址。iOS中使用的是.a已经静态打包到最终执行文件中。

  • 将控制权转移给非托管函数。

 

 2.2Android插件

图片 14

Java同样提供了这么一个恢宏机制JNI(Java
Native Interface),可以与C/C++相互通信。

注:

  • JNI wiki-https://en.wikipedia.org/wiki/Java\_Native\_Interface,这里不深远介绍JNI,有趣味的可以自行去切磋。要是您还不亮堂JNI也不用怕,就像Unity3D使用C/C++库一样,用起来如故相比简单的,只需要驾驭这一个东西即可。并且Unity3D对C/C++桥接器这块做了包装,提供AndroidJNI/AndroidJNIHelper/AndroidJavaObject/AndroidJavaClass/AndroidJavaProxy方便使用等,具体运用前边在介绍。JNI提供了多少的API实现了Java和任何语言的通信(主倘诺C&C++)。从Java1.1先河,JNI标准成为java平台的一有些,它同意Java代码和其它语言写的代码举办互动,保证本地代码能做事在任何Java 虚拟机环境下。”

  • 用作文化增加,提一下Android
    Java虚拟机。Android的Java虚拟机有2个,最起初是Dalvik,后边Google在Android
    4.4体系新增一种接纳运行情势ART。ART与Dalvik
    之间的要紧区别是其具有超前 (AOT) 编译格局。 遵照 AOT
    概念,设备安装使用时,DEX 字节代码转换仅进行五遍。 相相比较于
    Dalvik,这样可实现真正的优势 ,因为 Dalvik 的即时 (JIT)
    编译方法需要在历次运行应用时都举行代码转换
    。下文中用Java虚拟机代指Dalvik/ART。

 

C#/Java都得以和C/C++通信,那么通过编制一个C/C++模块作为桥接,就使得C#与Java通信成为了也许,如下图所示:

图片 15

注:C/C++桥接器本身跟Unity3D没有一贯涉及,不属于Android和Unity3D,图中位居Unity3D中是为了代指libunity.so中实现的桥接器以表示真实的景象。

通过JNI既可以用于Java代码调用C/C++代码,也可用来C/C++代码与Java(Dalvik/ART虚拟机)的交互。JNI定义了2个关键概念/结构:JavaVMJNIENVJavaVM提供虚拟机创设、销毁等操作,Java中一个进程可以创造两个虚拟机,可是Android一个历程只可以有一个虚拟机JNIENV是线程相关的,对应的是JavaVM中的当前线程的JNI环境,只有附加(attach)到JavaVM的线程才有JNIENV指针,通过JNIEVN指针可以赢得JNI效能,否则不可知调用JNI函数。

图片 16

C/C++要拜访的Java代码,必须要能访问到Java虚拟机,获取虚拟机有2中艺术:

  • 在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM*
    jvm, void* reserved)
    ,第一个参数会传播JavaVM指针。
  • 在C/C++中调用JNI_CreateJavaVM(&jvm,
    (void**)&env, &vm_args)创建JavaVM指针

所以,我们只需要在编制C/C++桥接器so的时候定义**JNI_OnLoad(JavaVM* jvm, void*
reserved)方法即可,然后把JavaVM指针保存起来作为上下文使用**。

赢得到JavaVM之后,还无法直接获得JNI函数去取得Java代码,必须透过线程关联的JNIENV指针去拿到。所以,作为一个好的支付习惯在每一回得到一个线程的JNI相关功用时,先调用AttachCurrentThread();又或者每一次经过JavaVM指针获取当前的JNIENV:java_vm->GetEnv((void**)&jni_env, version),一定是已经附加到JavaVM的线程。通过JNIENV可以收获到Java的代码,例如你想在地点代码中走访一个对象的字段(field),你可以像上面这样做:

  1. 对于类,使用jni_env->FindClass取得类对象的引用

  2. 对此字段,使用jni_env->GetFieldId赢得字段ID

  3. 动用相应的办法(例如jni_env->GetIntField)获取字段的值

类似地,要调用一个措施,你step1.得拿到一个类对象的引用obj,step2.是措施methodID。这一个ID经常是指向运行时内部数据结构。查找到它们需要些字符串相比较,但假如您实在去实践它们赢得字段或者做方法调用是非凡快的。step3.调用jni_env->CallVoidMethodV(obj, methodID, args)

从地点的以身作则代码,大家可以见见使用原来的JNI模式去与Android(Java)插件交互是多的麻烦,要和谐做太多的作业,并且为了性能需要自己考虑缓存查询到的方法ID,字段ID等等。幸运的是,Unity3D已经为我们封装好了那么些,并且考虑了性能优化。Unity3D紧要提供了一晃2个级其余包裹来增援高效编写代码:

图片 17

注:Unity3D中对应的C/C++桥接器包含在libunity.so中。

  • Level
    1:AndroidJNI、AndroidJNIHelper,原始的卷入相当于大家地点自己编辑的C#
    Wrapper。AndroidJNIHelper 和AndroidJNI自动完成了众多职责(指找到类定义,构造方法等),并且选用缓存使调用java速度更快。AndroidJavaObject和AndroidJavaClass基于AndroidJNIHelper 和AndroidJNI创设,但在拍卖自动完成部分也有诸多谈得来的逻辑,这一个类也有静态的版本,用来走访java类的静态成员。更详尽接口参考帮忙文档:http://docs.unity3d.com/ScriptReference/AndroidJNI.htmlhttp://docs.unity3d.com/ScriptReference/AndroidJNIHelper.html

  • Level
    2:AndroidJavaObject、AndroidJavaClass、AndroidJavaProxy,这些3个类是基于Level1的卷入提供了更高层级的包裹使用起来更简约,这个在第三部分详尽介绍。

 

2.3iOS插件

图片 18

iOS编写插件比Android要简明很多,因为Objective-C也是
C-compatible的,完全匹配标准C语言。
这一个就能够分外简单的包一层 extern
“c”{},用C语言封装调用iOS效能,流露给Unity3D调用。并且可以跟原生C/C++库一样编成.a插件。C#与iOS(Objective-C)通信的法则跟C/C++完全一致:

图片 19

 

 

除外,Unity
iOS帮助插件自动集成形式。所有位于Asset/Plugings/iOS文件夹中后缀名为.m ,
.mm , .c ,
.cpp的文本都将自行并入到已成形的Xcode项目中。不过,最后编进执行文书中。后缀为.h的文件不能够被含有在Xcode的档次树中,但她们将现出在对象文件系统中,从而使.m/.mm/.c/.cpp文件编译。这样编写iOS插件,除了需要对iOS
Objective-C有早晚通晓之外,与C/C++插件没有差异,反而更简便。

 

3.本子与补丁

图片 20

其他游戏(端游、手游)都应当提供娱乐内更新的门径。一般娱乐分为全量更新/整包更新、增量更新、资源立异。

  • 全量

android游戏内总体安装包下载(ios跳转到AppStore下载)

 

  • 增量:紧要指android省流量更新
-   可以使用bsdiff生成patch包

-   应用宝也提供增量更新sdk可供接入

 

  • 资源

Unity3D通过应用AssetBundle即可兑现动态更新资源的功效。

 

手游在促成这块时索要专注的几点:

  1. 玩耍公布出一定要提供娱乐内更新的途径。尽管是删掉测试,保不准这中间需要展开资源如故BUG修复更新。很多玩家并不知道怎么着翻新,而且Android手机应用分发平台多样,分发平台我也不会跟官方同步更新(特别是小的散发平台)。

  2. 履新效能要提供强制更新、非强制更新配置化选项,并点名哪些版本能够不强更,哪些版本必须强更。

  3. 当游戏提供非强制更新效能之后,现网一定会设有两个版本。即便需要针对不同版本做不同的翻新,例如配置文件A针对1.0.0.1修改了一项,针对1.0.0.2修改了另一项,2个本子需要各自更新对应的修改,需要协调实现立异策略IIPS不提供那一个功能。当需要复杂的革新策略,推荐自己编排更新服务器和客户端逻辑,不采取iips组件(其实自己实现也很简短)。

![](https://images2015.cnblogs.com/blog/92071/201604/92071-20160419000347366-1630977637.png)

没有运营经验的人会选择二进制,认为二进制安全、更小,这对端游/手游外网只存在一个版本的游戏适合,对一般不强升版本的手游并不适合,反而会对更新和维护带来很大的麻烦。
  1. 安排利用XML或者JSON等文本格式,更利于多版本的匹配和更新。最先河腾讯桌球客户端采取的二进制格式(由excel转换而来),可是随着运营配置格式需要追加字段,那样老版本程序就解析不了新的二进制数据,给兼容和更新带来了很大的劳顿。这样就要求地点提到的针对性不同步做不同更新,又或者配备一始发就留下好丰硕的扩张项,其实不管怎么预留扩展也很难跟上急需的变型,而且一起先会把配置表复杂化但是实际只有一张或者几张才会变动结构。
 
  1. iOS版本的送审版本需要连续一定的蕴藏新情节的服务器,现网服务器还不含有新内容。送审通过之后,上架游戏现网服务器会展开翻新,iOS版本需要连接现网服务器而非送审服务器,但是这中间又无法改改客户度,这一个切换需要通过服务器下发开关举行控制。例如通过点名送审的iOS游戏版本号,客户端判断当地版本号是否为送审版本,假诺是连连送审服务器,否则连接现网服务器。

 

4.用剧本,依然不要?这是一个问题

图片 21

福利更新,缩短Crash(特别是采取C++的cocos引擎)

透过下面一节【版本与补丁】知道要贯彻代码更新是这个辛勤的,正式这多少个原因客户端支付的压力是相比大的,倘使出现了比较严重的BUG必须发强制更新版本,使用脚本可以解决这么些题材。

是因为Unity3D手游更新资金相比较大,而且目前腾讯桌球要求不可以强制更新,这导致新本子的活动覆盖率提高相比慢、现身问题将来难以修复。针对这个场馆,考虑引入lua进行活动开发,后续宣布移动及修复bug只需要发表lua资源,举行资源革新即可,大大降低了发表和修复问题的成本。

可选方案还有使用Html5开展活动开发,近期娱乐中早就预埋了Html5运动入口,并且一度用来发过”玩家调查”、”腾讯棋牌宣传”等。不过与lua相比,不可以形成与Unity3D的纵深融合,体验不如使用lua,例如无法操作游戏中的ui、不可以不辱使命复杂界面的打造、不可能复用已有的职能、玩家付费充值跟已部分也会有差别

 

打闹脚本之王——Lua

在商店里面魔方相比较喜欢用lua,火隐忍者(手游)unity+ulua,全民水浒cocos2d-x+lua等等都有应用lua举办付出。我们可以动用集团内部的xlua组件,也足以采纳ulua<http://ulua.org/>、UniLua<https://github.com/xebecnan/UniLua>等等。

 

5.资源管理

图片 22

 

5.1资源管理器

图片 23

 


业务并非直接行使引擎或者系统原生接口,而是包装一个资源管理器负责:资源加载、卸载


兼容Resource.Load与AssetBundle资源相互变更需要,开发期间拔取Resource.Load情势而不要打AB包效能更高


加载资源时,不管是一道加载仍然异步加载,最好是拔取异步编码格局(回调函数或者音信布告机制)。若是啥时候资源由本地加载改为从服务器按需加载,而玩耍中的逻辑都是一头模式编码的,改起来将特别痛苦。其实异步编码情势很简短,不比同步格局复杂。

 

5.2资源类型

图片 24

 

  • 图片/纹理(对性能、包体影响最大要素)

  • 音频

-   背景音乐,腾讯桌球使用.ogg/.mp3

-   音效,腾讯桌球使用.wav
  • 数据
-   文本

-   二进制
  • 动画/特效

 

5.3图片-文件格式与纹理格式

图片 25

常用的图像文件格式有BMP,TGA,JPG,GIF,PNG等;
常用的纹理格式有R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等。

 

文件格式是图像为了存储音信而使用的对信息的奇异编码情势,它存储在磁盘中,或者内存中,不过并不可能被GPU所识别,因为以向量总括见长的GPU对于这一个复杂的测算无能为力。那些文件格式当被游戏读入后,依然需要通过CPU解压成R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,
A8R8G8B8等像素格式,再传递到GPU端举行应用。

纹理格式是能被GPU所识其它像素格式,能被急迅寻址并采样。举个例子,DDS文件是游戏支付中常用的文件格式,它其中能够分包A4R4G4B4的纹理格式,也足以蕴涵A8R8G8B8的纹路格式,甚至可以分包DXT1的纹理格式。在此处DDS文件有点容器的意味。OpenGL
ES
2.0协理上述提到的R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,A8R8G8B8等纹理格式,其中
R5G6B5,A4R4G4B4,A1R5G5B5每个像素占用2个字节(BYTE),R8G8B8各个像素占用3个字节,A8R8G8B8每个像素占用
4个字节。

 

按照OpenGL
ES的滑坡纹理有广阔的如下两种实现:

1)ETC1(Eric(Eric)sson
texture compression),ETC1格式是OpenGL
ES图形标准的一有的,并且被所有的Android设备所支撑。

2)PVRTC
(PowerVR texture compression),支持的GPU为Imagination
Technologies的PowerVR SGX系列。
3)ATITC (ATI texture compression),支持的GPU为Qualcomm的Adreno系列。
4)S3TC (S3 texture
compression),也被称为DXTC,在PC上普遍被应用,可是在活动设备上或者属于特种事物。襄助的GPU为NVIDIA
Tegra序列。

 

图片 26

 

5.4资源工具

图片 27

有了标准就可以做工具检查,从源头到打包

  • 资源导入检查

  • 资源打包检查

 

6.性能优化

图片 28

掉帧重要针对GPU和CPU做分析;内存占用大首要针对美术资源,音效,配置表,缓存等分析;卡顿也需要对GPU和CPU峰值分析,此外IO或者GC也易导致。

图片 29

6.1工欲善其事,必先利其器

图片 30

 

  • Unity
    Profiler
  • XCode instruments

  • Qualcomm Adreno
    Profiler

  • NVIDIA
    PerfHUD ES Tegra

 

6.2CPU:最佳标准裁减统计

图片 31

  • 复用,UIScrollView
    Item复用,制止频繁创制销毁对象
  • 缓存,例如Transform

  • 运算裁剪,例如碰撞检测裁剪

-   粗略碰撞检测(划分空间——二分/四叉树/八叉树/网格等,降低碰撞检测的数量)

-   精确碰撞检测(检查候选碰撞结果,进而确定对象是否真实发生碰撞)

-   休眠机制:避免模拟静止的球
  • 逻辑帧与渲染帧分离

  • 分帧处理

  • 异步/多线程处理

 

6.3GPU:最佳标准缩小渲染

图片 32

  • 纹理压缩

  • 批处理减弱DrawCall(unity-Static
    Batching和Dynamic Batching,cocos 百事可乐BatchNode)

  • 缩小无效/不必要绘制:屏幕外的剪裁,Flash脏矩阵算法,

  • LOD/特效分档

  • NGUI动静分离(UIPanel.LateUpdate的消耗)

  • 操纵角色骨骼数、模型面数/顶点数

  • 降帧,并非所有场景都需要60帧(腾讯桌球游戏场景60帧,其他场景30帧;天天酷跑,在伊始游戏前,FPS被限制为30,游戏最先未来FPS才为60。每一日飞车的FPS为30,可是当用户一段时间不点击界面后,FPS自动降)

 

6.4内存:最佳标准缩短内存分配/碎片、及时放出

图片 33

  • 纹理压缩-Android
    ETC1、iOS PVRTC 4bpp、windows DXT5
  • 对象池-PoolManager

  • 集合空闲图集

  • UI九宫格

  • 去除不用的本子(也会占据内存)

 

6.5IO:最佳条件裁减/异步io

图片 34

 

  • 资源异步/多线程加载

  • 预加载

  • 文本缩短

  • 客观规划资源集合打包,并非texturepacker打包成大图集一定好,会追加文(Gavin)件io时间

 

6.6网络:其实也是IO的一种

图片 35

动用单线程——共用UI线程,通过事件/UI循环驱动;依然多线程——单独的网络线程?

  • 单线程:由游戏循环(事件)驱动,单线程情势比使用多线程形式开发、维护简单很多,不过性能比多线程要差一些,所以在网络IO的时候,需要小心别阻塞到游戏循环。表达,假使网络IO不复杂的境况下,推荐应用该形式。
-   在UI线程中,别调用可能阻塞的网络函数,优先考虑非阻塞IO

-   这是网络开发者经常犯的错误之一。比如:做一个简单如
    gethostbyname()
    的调用,这个操作在小范围中不会存在任何问题,但是在有些情况中现实世界的玩家却会因此阻塞数分钟之久!如果你在
    GUI 线程中调用这样一个函数,对于用户来说,在函数阻塞时,GUI
    一直都处于 frozen 或者 hanged
    状态,这从用户体验的角度是绝对不允许的。 
  • 多线程:单独的网络线程,使用独立的网络线程有一个百般掌握的便宜,主线程可以将脏活、累活交给网络线程做使得UI更通畅,例如音信的编解码、加解密工作,那一个都是老大耗时的。不过使用多线程,给开发和保安带来一定财力,并且只要没有一定的阅历写出来的网络库不那么平稳,容易失误,甚至导致游戏崩溃。下边是几点注意事项:
-   千万千万别在网络线程中,回调主线程(UI线程)的回调函数。而是网络线程将数据准备好,让主线程主动去取,亦或者说网络线程将网络数据作为一个事件驱动主线程去取。当年我在用Cocos2d-x +
    Lua做魔法花园的手机demo时,就采用的多线程模式,最初在网络线程直接调用主线程回调函数,经常会导致莫名其妙的Crash。因为网络线程中没有渲染所必须的opengl上下文,会导致渲染出问题而Crash。

6.6包大小

图片 36

 

  • 动用压缩格式的纹理/音频

  •  尽量不要采取System.Xml而使用较小的Mono.Xml

  •  启用Stripping来减小库的深浅

  •  Unity
    strip level(strip by byte code)

  •  Unity3D输出APK,取消X86架构

  •  iOS Xcode strip开启

 

6.7耗电

图片 37

下边影响耗电的多少个元素和影响度摘自公司内部的一篇作品。

图片 38

 

 

7.异常与Crash

图片 39

7.1防御式编程

图片 40

 

  • 地下的输入中珍爱你的次序
-   检查每一输入参数

-   检查来自外部的数据/资源
  • 断言
  • 错误处理

  • 隔栏

 

防不胜防,不管什么守护总有失手的时候,这就需要特别捕获和反馈。

 

7.2特别捕获

图片 41

可怜捕获已经有广大第三零部件可供对接,这里不介绍组件的而接入,而是大概谈一下十分捕获的规律。

图片 42

出于众多荒唐并不是发出在支付工作者调试阶段,而是在用户或测试工作者采取阶段;这就需要相关代码维护工作者对于程序很是捕获收集现场消息。异常与Crash的监督和反馈,这里不介绍Bugly的采纳,依照apollo或者msdk的文档接入即可,没有太多可以说的。这里紧要透过Bugly介绍手游的几类相当的捕获和分析:

  • Unity3D
    C#层异常捕获:相比简单使用Application.RegisterLogCallback/Application.RegisterLogCallbackThreaded(在一个新的线程中调用委托)注册回调函数。特别注意:管教项目中唯有一个Application.RegisterLogCallback注册回调,否则后边注册的会覆盖前面注册的回调!回调函数中stackTrace参数包万分调用栈。

public void HandleLog(string logString, string stackTrace, LogType type)

{

    if (logString == null || logString.StartsWith(cLogPrefix))

    {

        return;

    }

   

    ELogLevel level = ELogLevel.Verbose;

    switch (type)

    {

   

        case LogType.Exception:

            level = ELogLevel.Error;

            break;

        default:

            return;

    }

   

    if (stackTrace != null)

    {

        Print(level, ELogTag.UnityLog, logString + "\n" + stackTrace);

    }

    else

    {

        Print(level, ELogTag.UnityLog, logString);

    }

}

 

  • Android
    Java层很是捕获

try…catch显式的破获分外一般是不引起游戏Crash的,它又称作编译时分外,即在编译阶段被处理的不得了。编译器会强制程序处理所有的Checked非凡,因为Java认为那类非凡都是足以被处理(修复)的。假设没有try…catch这么些可怜,则编译出错,错误提醒类似于”Unhandled exception type xxxxx”。
UnChecked非常又称作运行时这多少个,由于并未对号入座的try…catch处理该特别对象,所以Java运行环境将会终止,程序将退出,也就是我们所说的Crash。这为啥不会加在try…catch呢?

  • 没辙将装有的代码都添加try…catch

  • UnChecked非通常常都是相比较严重的特别,或者说已经损坏了运行条件的。比如内存地址,即使我们try…catch住了,也无法掌握知晓哪些处理该特别,才能保证程序接下去的运转是不利的。

Uncaught非凡会导致应用程序崩溃。那么当崩溃了,我们是否足以做些什么吧,就像Application.RegisterLogCallback注册回调打印日志、上报服务器、弹窗提醒用户?Java提供了一个接口给我们,可以完成那个,这就是UncaughtExceptionHandler,该接口含有一个纯虚函数:

public abstract void uncaughtException (Thread thread, Throwableex)

Uncaught十分暴发时会终止线程,此时,系统便会布告UncaughtExceptionHandler,告诉它被结束的线程以及相应的丰富,然后便会调用uncaughtException函数。假使该handler没有被显式设置,则会调用对应线程组的默认handler。假诺我们要捕获该特别,必须贯彻我们团结的handler,并透过以下函数举行设置:

public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)

特别注意:多次调用setDefaultUncaughtExceptionHandler设置handler,前面注册的会覆盖前边注册的,以最后两次为准。实现自定义的handler,只需要继承UncaughtExceptionHandler该接口,并落实uncaughtException方法即可。

static class MyCrashHandler implements UncaughtExceptionHandler{  

    @Override  

    public void uncaughtException(Thread thread, final Throwable throwable) {  

        // Deal this exception

    }

}

在此外线程中,都可以透过setDefaultUncaughtExceptionHandler来设置handler,但在Android应用程序中,全局的Application和Activity、Service(Service)都同属于UI主线程,线程名称默认为”main”。所以,在Application中应该为UI主线程添加UncaughtExceptionHandler,那样所有程序中的Activity、瑟维斯(Service)(Service)中出现的UncaughtException事件都得以被处理。

捕获Exception之后,我们还需要知道崩溃堆栈的信息,这样有助于我们解析崩溃的原委,查找代码的Bug。分外对象的printStackTrace方法用于打印相当的仓库音讯,遵照printStackTrace方法的出口结果,我们得以找到非常的源头,并跟踪到非常联机触及的经过。

public static String getStackTraceInfo(final Throwable throwable) {

    String trace = "";    try {

        Writer writer = new StringWriter();

        PrintWriter pw = new PrintWriter(writer);

        throwable.printStackTrace(pw);

        trace = writer.toString();

        pw.close();

    } catch (Exception e) {        return "";

    }    return trace;

}

  • Android
    Native
    Crash:后边我们清楚能够编写和运用C/C++原生插件,除非C++使用try…catch捕获非常,否则一般会直接crash,通过捕获信号进行拍卖。
  • iOS
    分外捕获:

跟Android、Unity类似,iOS也提供NSSetUncaughtExceptionHandler 来做特别处理。

#import "CatchCrash.h"

   

@implementation CatchCrash

   

void uncaughtExceptionHandler(NSException *exception)

{

    // 异常的堆栈信息

    NSArray *stackArray = [exception callStackSymbols];

    // 出现异常的原因

    NSString *reason = [exception reason];

    // 异常名称

    NSString *name = [exception name];

    NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@",name, reason, stackArray];

    NSLog(@"%@", exceptionInfo);

       

    NSMutableArray *tmpArr = [NSMutableArray arrayWithArray:stackArray];

    [tmpArr insertObject:reason atIndex:0];

   

    [exceptionInfo writeToFile:[NSString stringWithFormat:@"%@/Documents/error.log",NSHomeDirectory()]  atomically:YES encoding:NSUTF8StringEncoding error:nil];

}

   

@end

而是内存访问错误、重复释放等不当引起崩溃就不可能了,因为这种不当它抛出的是信号,所以还非得要专门做信号处理。

  • windows
    crash:同样windows提供SetUnhandledExceptionFilter函数,设置最高超级的不得了处理函数,当程序出现其余未处理的分外,都会触发你设置的函数里,然后在特别处理函数中拿到程序相当时的调用堆栈、内存新闻、线程音讯等。

 

 

8.适配与配合

图片 43

 

8.1UI适配

图片 44

 

  • 锚点(UIAnchor、UIWidgetAnchor属性)

  • NGUI UIRoot统一安装缩放比例

  • UIStretch

 

8.2兼容

图片 45

 

  • shader兼容:例如if语句有的机型补助不佳,Googlenexus 6在shader中运用了if就会crash
  • 字体兼容:android复杂的条件,有的手机厂商和rom会对字体举办优化,去掉android默认字体,假设不打包字体会不具体粤语字

 

9.调节及开发工具

图片 46

9.1日志及跟踪

图片 47

事实表明,打印日志(printf调试法)是相当实惠的法子。一个好用的日记调试,必备以下多少个效用:

  • 日记面板/控制台,格式化输出

  • 没完没了级别(verbosity
    level):ERROR、WARN、INFO、DEBUG

  • 频道(channel):按效能等举办模块划分,如网络频道只收到/突显网络模块的音信,频道指出使用枚举举行命名。

  • 日记同时会输出到日志文件

  • 日记上报

 

9.2调剂用绘图工具

图片 48

调节绘图用工具指开发及调试期间为了可视化的绘图用工具,如腾讯桌球开发调试时会使用VectrosityScripts可视化球桌的大体模型(实际碰撞线)援救调节。这类工具得以节约大量岁月及便捷定位问题。平时调试用绘图工具包含:

  • 补助绘制基本图形,如直线、球体、点、坐标轴、包围盒等

  • 支撑自定义配置,如颜色、粒度(线的粗细/球体半径/点的深浅)等

 

9.3戏耍内置菜单/作弊工具

图片 49

在支付调试期间提供娱乐举办中的一些布局选项及作弊工具,以造福调试和提高功能。例如腾讯桌球游戏中提供:

  • 玩耍内物理引擎参数调整菜系;

  • 修改球杆瞄准线长度/反射线数量、修改签到奖励领取天数等作弊工具

只顾游戏内的具有支付调试用的工具,都需要通过编译宏开关,保证发表版本不会把工具代码包含进去

 

9.4Unity扩展

图片 50

Untiy引擎提供了充分有力的编辑器扩充效率,基于Unity
Editor可以兑现充足多的效率。公司内部、外部都有那一个的开源扩充可用

供销社外部,如GitHub上的:

UnityEditor-MiniExtension

Unity-Resource-Checker

UnityEditorHelper

MissingReferencesUnity

Unity3D-ExtendedEditor

信用社内部:

TUTBeautyUnityUnityDependencyBy

 

 

10.品类运营

图片 51

 

  • 机关构建
-   版本号——主版本号.特性版本号.修正版本号.构建版本号


    -   \[构建版本号\]应用分发平台升级判断基准


-    自动构建


    -   Android

    -   iOS
        — XUPorter 

   

 集团之中接入SODA即可,提议搭建自己的构建机,开发期间每天N
Build排队会死人的,其它也得以搭建自己的搭建构建平台

 

  • 总括上报
-   Tlog上报


    -   玩家转化关键步骤统计(重要)

    -   Ping统计上报

    -   游戏业务的统计上报(例如桌球球局相关的统计上报)


-    灯塔自定义上报

 

  • 营业模板
-   配置化

-   服务器动态下发

-   CDN拉取图片并缓存

 

图片 52

上线前的checklist

项目

要点

说明

指标

灯塔上报

1. 灯塔自带统计信息
2. 自定义信息上报

灯塔里面包含很多统计数据,需要检查是否ok

1. 版本/渠道分布
2. 使用频率统计
3. 留存统计(1天留存、3天留存、7天留存、14天留存)
4. 用户结构统计(有效用户、沉默用户、流失用户、回流用户、升级用户、新增用户)
5. 硬件统计(机型+版本、分辨率、操作系统、内存、cpu、gpu)
6. Crash统计(Crash版本、Crash硬件、Crash次数等)
等等

信鸽推送

   

能够针对单个玩家,所有玩家推送消息

米大师支付

   

正常支付

安全组件

1. TSS组件接入
2. 隐藏内部符号表:C++开发的代码使用strip编绎选项,抹除程序的符号
3. 关键数据加密,如影子变量+异或加密算法

根据安全中心提供的文档完成所有项

接入安全组件,并通过安全中心的验收

稳定性

crash率

用户crash率:发生CRASH的用户数/使用用户数
启动crash率:启动5S内发生crash用户数/使用用户数

低于3%

弱网络

 

断线重连考虑,缓存消息,重发机制等等

客户端的核心场景必须有断线重连机制,并在有网络抖动、延时、丢包的网络场景下,客户端需达到以下要求:
一. 不能出现以下现象:
1、游戏中不能出现收支不等、客户端卡死/崩溃等异常情况;
2、游戏核心功能(如登录、单局、支付等)不能有导致游戏无法正常进行的UI、交互问题;
3、不能有损害玩家利益或可被玩家额外获利的问题;
4、需要有合理的重连机制,避免每次重连都返回到登录界面。
二. 需要对延时的情况有相应的提示

兼容性

   

通过适配测试

游戏更新

1. 整包更新
2. 增量更新

 

特别说明:iOS送审版本支持连特定环境,与正式环境区别开,需要通过服务器开关控制

性能

内存、CPU、帧率、流量、安装包大小

 

【内存占用要求】
Android平台:在对应档次客户端最低配置以上,均需满足以下内存消耗指标(PSS):
1档机型指标:最高PSS<=300MB (PSS高于这个标准会影响28%用户的体验,约1800万)
2档机型指标:最高PSS<=200MB(PSS高于这个标准会影响45%用户的体验,约3000万)
3档机型指标:最高PSS<=150MB(PSS高于这个标准会影响27%用户的体验,约1800万)
iOS平台:在对应档次客户端最低配置以上,均需满足以下内存消耗指标(PSS):
1档机型指标:消耗内存(real mem)不大于250MB(高于这个标准会影响53%用户的体验,约1900万)
2档机型指标:消耗内存(real mem)不大于200MB(高于这个标准会影响47%用户的体验,约1700万)
【CPU占用要求】
Android平台:CPU占用(90%)小于60%
iOS平台:CPU占用(90%)小于80%
【帧率要求】
1档机型(CPU为四核1.4GHZ,RAM为2G)或以上机型:游戏核心玩法中,最小FPS应不小于25帧/秒
2档机型(CPU为两核1.1GHZ,RAM为768M)或以上机型:游戏核心玩法中,最小FPS应不小于25帧/秒
3档机型(CPU为1GHZ,RAM为768M)或以上机型:游戏核心玩法中,最小FPS应不小于18帧/秒
【流量消耗要求】
游戏核心玩法流量消耗情况(非一次性消耗)应满足以下条件:
1.对于分局的游戏场景,单局消耗流量不超过200KB
2.对于不分局游戏场景或流量与局时有关的场景,10分钟消耗流量不超过500KB

 

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图