Unity游戏开发UI框架(1)
最近有点累了,所以写一些文章放松一下。
简单说一下我的一些不成熟的关于学习游戏开发的想法吧。这个框架是来自某培训机构的一位姓朱的老师教给我的,如果是我同期的U3D开发的同学大概就知道我说的是谁了,再此非常感谢老朱!
说一下自己的学习曲折道路吧,希望不要和我一样走弯路。在新手阶段,也就是说没有真正的在商业项目中磨炼不到一两年的,不要去造*!能看懂,能用,并且会用是最重要的!程序员,没有一定的代码积累是很难达到随心所欲的行云流水的一般的写出高质量的代码的。等有了一定的积累,然后再去修改一部分开源插件的功能,甚至说重新提炼出属于自己的写代码思路和架构。
入行游戏开发的程序员经常犯的一个错误就是在深度不足的时候,就去拓展广度。这其实严格意义上来说,是非常非常不好的一种学习方法。程序员的学习,一定是深度优先。达到了一定的深度,再去学习相关的东西,那么提升的非常快,高效!否则的,三步一坑五步一坎儿。
注意:当熟悉了C#语言,一定要长期坚持练习数据结构和算法!!!!一定要长期坚持练习数据结构和算法!!!!一定要长期坚持练习数据结构和算法!!!!(三遍了!)
前期的学习:C#基本语法最重要的,是面向对象这一方面的学习,这是游戏开发的核心部分。接口、类、委托,前期写多少代码都是不够的!必须一直写,一直练!然后可以看看C#的语法糖,有惊喜~接着就开始研究Unity的一些常用的组件:碰撞器、寻路组件、Animation、UGUI等等,其中各种教学视频数不胜数。这里不多说了,然后开始研究Unity常用的API。这里可能会需要一定的基础的关于高数、物理相关知识,但是仅仅是基础而已。
这些组件基本了解一遍了,开始自己写Demo。不要管框架不要管任何东西,先写一个Demo,只要能实现你想要的游戏功能就可以!!!接下来,对于急于找工作的小伙伴来说,就要深入研究UGUI或者NGUI是重点的!百分之九十九的新手程序刚入工作都是在处理UI方面的事情。什么叫做深入了解,就是同一个UI的功能,考虑实现他的功能的时候,需要考虑它的效率问题。(老生常谈的NGUI的WrapContent,不知道的自己百度一下他的实现原理。)甚至,ScrollView滑动的的时候,一般来说他的item是直线的,怎么让他弧形滑动,按照预定的曲线方向滑动等等。怎么提高他的效率,都需要自己去重写一部分逻辑和功能才能实现。(当然有这种插件)
这一部分面试:会问各种奇葩的东西,没办法只能扫题了。注意:算法和数据结构一定会有算法笔试题的!尤其是大厂的面试,算法和数据结构是核心,其他的Untiy之类的反而不会问。
前端开发什么组件不学:shader相关的都不学习!材质球知道,会用即可!粒子系统不学!说白了美术向的组件,都可以不学!很简单,时间精力有限!这些玩意对于 **新手** 前端程序来说,没什么用处!但是,Animation和Animator相关的代码API得会用!!!Unity编辑器相关的代码,不看!
另外:提一下NGUI和UGUI到底学习哪一个,我的回答是都行!现在大部分游戏公司都在换皮,很多老项目都是用的NGUI。但是不意味着新项目就不使用NGUI了,本身NGUI和UGUI的作者是同一个人,原理相差不大,并且NGUI插件是开源的!等需要深入研究的时候,NGUI源码是不得不研究的一个东西。相比UGUI,我个人觉得NGUI的*度更高一些,尤其写一些UI框架的时候,NGUI非常合适。例如:实现自动的Panel进行UI预制体的层级显示(对深度排序),可以直接获取depth进行在UI基类中实现排序。
接下来,需要了解资源打包相关的知识。面试这个东西是加分项,实际上在框架中都会写好固定的打包逻辑。但是你还是得会!AB包,以及现在新出来的寻址加载系统。这个东西是和Lua热更相关的,不知道很不好找工作。
AB相关涉及到:C#和Unity的文件读取,面试很可能会问深度拷贝(文件流,字节流,using的几种用法,如何释放等等)Json相关的东西。最好自己能写一个简单的文件打包器。
接下来就得说Lua了。这个玩意,现在基本算是找工作必备的东西了,不会不代表找不到工作,但是不好找!前提是C#必须得熟悉,不然写完了C#在去学习lua,两头懵逼。Lua语法非常随心所欲,属于那种没有规则的规则。Lua核心部分都是在table,也就是表。
然后Lua热更:XLua,uLua,toLua之类的相关的插件。这玩意,基本在工作中用不到,但是实际上面试有的会问。因为好的框架会把这些都封装好了,不用我们多做什么东西。
Lua核心部分:面试常问的,Lua几种数据类型,模型匹配,迭代器和泛型for的几个之间的区别。模块与包。尾调函数,闭包。元方法,元表。最重要的如何使用表table来实现面向对象!!!(反射和协程我是真的没用到,也没遇到有面试问这个的。)
买书学习的建议:看Lua程序设计,黄色封皮的那本!!!个人感觉那本书讲的简单易懂一些!否则的话,直接baidu.com~~
说一下关于粒子特效、模型K动画相关的。这两个部分,一个属于特效师,一个属于建模,部分特效也可能负责K模型动作。如果有想要走特效方面的技术美术的,粒子系统是绕不过去的!Unity编辑器相关的代码也是绕不过去的!写工具要用的。特效很重要的一部分在Shader。这里多提一句:Unity入门精要——冯乐乐,新入行的技术美术必看的东西。然后说一下连连看(ASE等以及现在bug不少的ShaderGraph),连连看在我们的现在项目中已经使用了,想转TA的学不学自行决定。其他的:小破站的闫令qi大佬的课程,以及庄懂的技术美术课程。至于非要买课花钱,我不说什么,您有钱您随意……Shader短期收效慢,说白了很难在短期内拉出去能干活,需要一个长期积累和实践的东西。
不废话了,直接说框架。
基本游戏流程:
1、打开游戏需要检测是否需要热更(涉及热更相关的东西就不说了太多了,百度就可以了)加载loading界面。下载资源完成
2、进入登录界面,执行登录方面以及注册方面的校验逻辑。
3、退出登录场景(状态),进入主城(主界面),然后正八经进入游戏开始玩了。
上面的虽然都是废话,但是整个游戏UI的控制,其实就是一直进行这样一个简单的循环。
退出上一个场景(可能需要做一些事情:清理内存,销毁一些不必要的预制体)——进入新的场景(可能需要做一些事情:加载Loading界面,加载状态内的资源,例如场景中的一些房子模型,人物模型等等)——加载完成(关闭loading界面)
下面三个是常用的一些工具或者框架中简单但是挺重要的模块,因为简单就不过多介绍了。
1、小工具之类的东西:单例基类。不多介绍,这个不会的话可能真的需要自己去补一下C#基础知识了啊~~
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AutoSingleton<T> :MonoBehaviour where T:MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
GameObject go = new GameObject(typeof(T).ToString());
instance = go.AddComponent<T>();
}
return instance;
}
}
}
2、小工具:拓展方法,递归查找子物体;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public static class ExpandFunc
{
public static Transform FindChildWithName(this Transform self,string targetName)
{
if (self.name == targetName)
return self;
if (self.childCount < 1)
return null;
Transform target;
for (int i = 0; i < self.childCount; i++)
{
target = self.GetChild(i).FindChildWithName(targetName);
if (target)
return target;
}
return null;
}
}
3、框架中经常用到的一个部分,消息传递:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate void LoadDel(float num);//可以自定义泛型委托;
public static class MessageManager
{
//用于存储 想要执行的委托字典;
private static Dictionary<string, LoadDel> m_loadDic = new Dictionary<string, LoadDel>();
//将消息或者委托注册到字典中
public static void AddListener(string funcName, LoadDel loadDel)
{
if (m_loadDic.ContainsKey(funcName))
{
m_loadDic.Remove(funcName);
}
m_loadDic.Add(funcName, loadDel);
}
//执行的时候,就可以通过string把委托从字典取出来,执行,num是一个参数,可以根据自己的需要自定义泛型委托或者固定参数的委托;
public static void DoFunc(string funcName, float num)
{
LoadDel temDel = null;
if (m_loadDic.TryGetValue(funcName, out temDel))
{
temDel(num);
MDebug.Log("执行了方法:" + funcName);
}
}
public static void RemoveFunc(string funcName)
{
m_loadDic.Remove(funcName);
}
public static void ClearAllFunc()
{
m_loadDic.Clear();
}
}
一、状态(通常可以理解为一个状态,就是一个场景,或者在一个模块中想要干的一系列事情。)
由此可知,加载场景就需要两个东西:第一加载场景管理类,第二状态管理类。这两个是有区别的,第一个是从硬盘中把场景资源加载进来,第二个是决定管理这些状态什么时候加载,什么时候卸载。这两个管理类暂时先不说,之后详细介绍,也是核心的部分!
1)状态基类:
public abstract class BaseScene
{
//开始加载
public void Start()
{
UIManager.LoadPanel(); //通过UI管理类加载LoadingPanel;
OnStart();
}
//退出场景
public void Stop()
{
OnStop();
}
//场景加载完成,这个参数的用处,之后会介绍的;
public void LoadComplete(params object[] args)
{
OnLoadComplete(args);
}
protected abstract void OnStart();
protected abstract void OnStop();
protected abstract void OnLoadComplete(params object[] args);
}
2)先简单举一个例子,作为具体实现状态基类的方法,当进入登录场景的时候,实现具体的虚方法,会在基类BaseScene中调用。
public class LoginStateScene : BaseScene
{
protected override void OnLoadComplete(params object[] args)
{
//关于UIManger以后介绍;
UIManager.LoadPanel(PanelNameEnum.LoginPanel, PanelNameEnum.None);
}
protected override void OnStart()
{
}
protected override void OnStop()
{
UIManager.DestoryPanel(PanelNameEnum.LoginPanel);
}
}
这两个没什么难度,就是简单的继承而已。在之后要写的状态管理类中,就会发现进入一个场景之前,想要执行Stop方法,然后执行场景的Start方法。这个流程就是在状态管理类中控制的;
至于UIManager这管理类先不要去管它。之后会详细介绍UI代码如何处理;接下来可能需要先介绍一下AB包管理器了(本来想着直接用本地加载算了,不用ab包了。后来想着反正都写了框架,多介绍一点是一点吧);