MainScript.cs

工程的入口CS

Awake

  • Application.runInBackground = true;
  • 默认为false,也就是当程序在后台时暂停。

  • 当打开Strip Engine Code,减少项目内存的时候,即使是low,也会裁剪掉很多cs组件,high的话,会裁剪的更多。比如Unity的组件LensFlare(id=123)、WindZone(id=182),ClassName和ID的对照表。如果项目中又有prefab等用到了这个组件,则会导致Unity Crash。那么在CS中通过声明一个该类型的static变量,则会使得Unity不去裁剪这个组件。需要注意的是AnimatorController组件,在非Editor模式下,其实是RuntimeAnimatorController组件。
  • QualitySettings.vSyncCount = 0;
  • 软件层面是关不掉硬件VSync的,所以软件层面都是通过生命周期函数,每帧判断一下时间,然后决定是否等待。一般游戏都会限制到30FPS,否则虽然帧率高了,但是由于计算量负荷太大,发热就快了。目前,基本操作都是将QualitySettings.vSyncCount设为0,然后通过Application.targetFrameRate来控制游戏FPS,详见在Unity中实现准确的帧率(Patrick:其实在这里我心里有个疑问,硬件层是可以通过双缓冲或者三缓冲来实现,不知道这里的设置是否会影响这个选择,目前我的测试感觉两者好像没关系。但是Unity3d 用户文档圣典1.0中表达的意思,感觉两者有一定关系。)

  • Application.targetFrameRate = 30;
  • Screen.sleepTimeout = SleepTimeout.NeverSleep;
  • 使得游戏运行的过程中不自动锁屏。相应的,一定要做好处理,用户一段时间不操作,降低屏幕暗度,降低游戏帧率和画质等。以防手机过热。

  • SystemInfo.hasHiddenSurfaceRemovalOnGPU
  • 获取手机的设备信息,并根据此进行分级。典型的就是上述这个接口,如果手机支持HSR,那么绘制顺序可以根据状态切换来处理,否则,就要按照不透明从前到后的渲染顺序,以防过度的OverDraw。

  • 通过DLL获取Android手机的extension,这个涉及底层模块,比较复杂,后面再单拉出来聊
  • Camera.AddComponent(Cinemachine.CinemachineBrain)();
  • Cinemachine也是个大模块,先跳过吧。

Start

  • GameObject.Instantiate(Resources.Load("XXX"));
  • 游戏可以选择使用NGUI、UGUI、Faiygui。但是Unity原生支持UGUI,其他的都需要初始化一些东西。所以一般游戏刚打开时候的Loading图都会使用UGUI,对应的Loading图的资源也会直接放到Resources文件夹中,跟着包走(而非AB)。里面包含登录等一些游戏逻辑。

    如果屏幕宽高比大于1.28,小于1.45,则认为它是pad,然后背景图片需要使用高一点的图片。

  • 获取当前App的config文件信息。
  • 比如:渠道信息、App版本号、资源版本号、App下载路径、资源下载路径、App下载的方式、资源下载的方式、库下载的方式、debug/release、登录所需资源的版本、登录所需资源下载的方式等

  • 如果是debug模式,挂载一个Reporter的GameObject,用来打印调试用的日志。如果是非Editor的debug模式,需要将LuaInterface.Debugger.useLog和Debug.unityLogger.logEnabled打开,方便调试,如果是非Editor的release模式,就将其关闭。
  • 调试日志特别影响性能,所以release一定要关闭。看性能也要用release看。print其实是对Debug.Log的封装,详见print和log的区别

  • 键盘监听
  • AssetBundle.LoadFromFile(Path.Combine(Application.persistentDataPath, "login.ab"))
  • AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "login.ab"))
  • 真机默认使用AB模式,安装包中的AB资源会被放到StreamingAssetsPath路径下(原始AssetBundle存放路径),使用热更新下载(API UnityWebRequest)下来的AB资源会被放到persistentDataPath路径下(补丁AssetBundle存放路径,优先从这个路径加载资源)

    从disk中,通过路径从文件同步加载一个AB。支持压缩格式的bundle,比如lzma压缩格式,数据会被自动解压缩到内存中,chunk压缩格式或者未压缩的数据可以直接从disk中被读取。与AssetBundle.LoadFromFileAsync唯一的区别就是同步的,AB被加载后才会返回。

  • LuaManager.Instance.CreateLuaState();
  • 创建LuaState和LuaLooper。

  • PopupMgr.Instance.ShowCanvas(true);
  • 显示游戏初始界面

  • Application.internetReachability
  • 获取当前设备的联网模式,但是不能通过该接口判断是否联网,因为可能只是连了一个热点。非手持设备始终返回NetworkReachability.ReachableViaLocalAreaNetwork

  • System.Timers.Timer t = new System.Timers.Timer(1000)
  • 实例化Timer类,设置间隔时间为1000毫秒;

  • t.Elapsed += new System.Timers.ElapsedEventHandler(timeout);
  • 到达时间的时候执行倒计时事件timeout;

  • t.AutoReset = true;
  • 设置是执行一次(false)还是一直执行(true);

  • timer.Start();
  • 需要调用 timer.Start()或者timer.Enabled = true来启动它, timer.Start()的内部原理还是设置timer.Enabled = true;

  • timer.Close()
  • 调用 timer.Stop()或者timer.Enabled = false来停止引发Elapsed事件, timer.Stop()的内部原理还是设置timer.Enabled = false,最重要的是timer.Enabled = false后会取消线程池中当前等待队列中剩余任务的执行。

  • AssetsManager.Instance.Init(OnAssetsLoadFinish);
  • 在Timer时间内下载完资源后,就开始加载AB了

AssetsManager.cs

从MainScript中触发了两个大的模块,Lua和AB,先看AB

这里涉及到AssetsManager、AssetsInfoManagerr、AssetsInfoInit和ResourceRequest四个大类,主要就是根据版本号,对AB进行下载。

另外,就是这里会下载shader相关的ab,然后根据需要进行warmup,以及下载SRP对应的ab,然后根据条件设置给GraphicsSettings.renderPipelineAsset。并在Camera上挂载PostProcessLayerEA组件和EA_GameMainRendererSetup组件。

下载lua和lua_bin这两个ab,然后通过LuaManager.Instance.CreateLuaState确保LuaState和LuaLooper创建好了,然后通过LuaManager.Instance.StartMain,开始从Lua的入口文件Game.lua,对应的OnInitOK这个入口函数开始执行。

Game.lua

嗯,作为lua小白,先去读了文档Lua 教程,然后再看代码

首先,luajit分为jit模式和interpreter模式。我们的建议是,继续使用luajit,但是对于一般的团队而言,使用interpreter模式。详情参考文章用好lua+unity,让性能飞起来——luajit集成篇/平台相关篇。我们的项目使用的是interpreter模式。所以,在Game.Lua中,先将luajit关闭了。

然后,借用LuaLoop的机制,将函数PreUpdate加入event.lua中的update中,将函数OnUpdate加入event.lua中的update中。

原创技术文章,撰写不易,转载请注明出处:电子设备中的画家|王烁 于 2020 年 4 月 17 日发表,原文链接(http://geekfaner.com/unity/blog18_UnitySourceCode.html)