1.定义一个自己的窗口:EditorWindow.GetWindow(窗口类型,窗口是否浮动,窗口的标题)
要引用using UnityEditor;
例如:using UnityEngine;
using System.Collections;
using UnityEditor;//注意要引用
public class MyWindow: EditorWindow
{
[MenuItem("Window/MyWindow")]//在unity菜单Window下有MyWindow选项
static void Init()
{
MyWindow myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", true);//创建窗口
myWindow.Show();//展示
}
}
2.Selection类是编辑器类,使用需要using UnitryEditor;且脚本要放在Editor文件夹。
(2018版本可以使用Window->PackageManager管理Packages中的文件夹)
3.打包apk
(1)安装JDK与SDK(android-sdk-windows)SDK下载地址:http://www.androiddevtools.cn
(2)配置JDK路径
变量值:C:\Java\jdk1.6.0_22\bin
(3)打开Edit-Preferences选项-External Tools-Android(填好SDK与JDK的路径)
(4)切换到Android平台下打包
4.using Random = UnityEngine.Random;解决UnityEngine与C# System中Random的冲突
5.摄像机
益智游戏:相机处于静态显示全部视角
第一人称射击游戏:相机作为玩家角色的子对象
赛车游戏:相机跟随玩家的车辆
创建多个小视图:导弹控制器、小地图、后视镜
Camera.main.layerCullDistances脚本函数设置每一层的剔除距离
Render Texture 渲染纹理:可以方便地创建体育场大屏幕、监控摄像机、倒影等等效果。用来创建一个直播监视器
渲染路径:影响灯光和阴影:Deferred Lighting延时光照(最高保真度):有很多实时灯光,使用延时光照(仅在unity上有用,在移动端无效)
Forward Rendering正向渲染:在默认设置中,少数最亮的灯 光在逐像素计算光照模式下渲染
Vertex Lit顶点光照(最低保真度):用于旧机器或受限制的移动平台上
6.light光照
某个地方的光照是不变的:光照贴图
7.判断点击的是否是UI
在窗口端进行判断时使用:
If(Input.GetMouseButtonDown(0)&&!EventSystem.current.IsPointerOverGameObject()){…}
在Android上运行时使用:
if(Input.touchCount>0&&Input.GetTouch(0).parse==TouchPhase.Began)
{
If(!EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId()))
{ ……}
}
8.协程:等待一个加载完成 yield return www;
void Start(){
StartCoroutine(TestFunc());
}
IEnumerator TestFunc(){
Debug.log(1);
yield return StartCoroutine(TestFunc1());
for(int i=0;i<10;i++)
{
Debug.Log(3);
}
}
IEnumerator TestFunc1(){
for(int i=0;i<10;i++)
{
Debug.Log(2);
}
yield return new WaitForSeconds(10);
Debug.Log(4);
}
答案为:1
2(输出10次)
4
3(输出10次)
注:1.在协同中yield return 另一个协同时必须有返回值即执行完毕才能执行之后的代码。
2.协同程序慎用
3.同一时刻、一个脚本实例中可以有多个暂停的协程,但只有一个运行着的协程
4.函数体全部执行完后,协程结束
9.委托与事件:声明一个事件类似于声明一个进行了封装的委托类型的变量。
delegate可以引用静态函数,也可以引用非静态函数。
class Heater
{
public delegate void BoilHander(int param);
public event BoilHander boilHander;
private int temperature;
public void BoilWater()
{
for(int i=0;i<100;i++)
{
temperature=i;
if(temperature>95)
{
If(boilEvent!=null)
boilEvent(temperature);
}
}
}
}
class Alarm
{
public void MakeAlert(int param)
{
Console.WriteLine(“Alarm:嘀嘀嘀,水已经{0}度了:”,param);
}
}
class Display
{
public static void ShowMsg(int param)
{
Console.WriteLine(“Display:水快开了,当前温度:{0}度。”,param);
}
}
static void Main(string[] args){
Heater ht=new Heater();
Alarm al=new Alarm();
Display dis=new Display();
ht.boilHander+=al.MakeAlert; //注册方法
ht.boilHander+=(new Alarm()).MakeAlert;//给匿名对象注册方法
ht.boilHander+=dis.ShowMsg;//注册静态方法
ht.BoilWater();
}
输出结果:
Alarm:嘀嘀嘀,水已经 96 度了:
Alarm:嘀嘀嘀,水已经 96 度了:
Display:水快烧开了,当前温度:96度。
Alarm:嘀嘀嘀,水已经 97 度了:
Alarm:嘀嘀嘀,水已经 97 度了:
Display:水快烧开了,当前温度:97度。
Alarm:嘀嘀嘀,水已经 98 度了:
Alarm:嘀嘀嘀,水已经 98 度了:
Display:水快烧开了,当前温度:98度。
Alarm:嘀嘀嘀,水已经 99 度了:
Alarm:嘀嘀嘀,水已经 99 度了:
Display:水快烧开了,当前温度:99度。
10.并行与线程
命名空间:using System.Threading;
使用Stopwatch要引用System.Diagnostics命名空间
var stopWatch = new StopWatch(); //创建一个Stopwatch实例
stopWatch.Start(); //开始计时
stopWatch.Stop(); //停止计时
stopWatch.Reset(); //重置StopWatch
stopWatch.Restart(); //重新启动被停止的StopWatch
stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒
Parallel并行
a.Parallel.Invoke(Run1,Run2);//Run1,Run2是两个函数方法
b.Parallel.For(0,10000,item=>{for(int i=0;i<60000;i++){int sum=0;sum+=item;}});// 并行且同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面,会比普通的for循环浪费时间。
c.Parallel.Foreach()
List<int> list=new List<int>();
list.Add(0);
Parallel.ForEach(list,item=>
{
DoWork(item);
});
并行集合(线程安全集合):
引用System.Collections.Concurrent命名空间,ConcurrentBag<T>泛型集合,其用法和List<T>类似,ConcurrentBag中的数据并不是按照顺序排列的,顺序是乱的,随机的
Public static void ConcurrentBagWithPallel()
{
ConcurrentBag<int> list=new ConcurrentBag<int>();
Parallel.For(0,10000,ITEM=>{List.Add(item);});
Console.WriteLine(“ConcurrentBag’s count is {0}”,list.Count());
}
输出的答案为:ConcurrentBag’s count is 10000
Parallel Linq的用法:
AsParallel()这个方法可以应用与任何集合,包括List<T>集合,从而提高查询速度和系统性能
List<Custom> customs = new List<Custom>();
var result = customs.Where<Custom>(c => c.Age > 26).ToList();
var result2 = customs.AsParallel().Where<Custom>(c => c.Age > 26).ToList();(更优)
ToLookup方法是将集合转换成一个只读集合,所以在大数据量分组时性能优于List
var groupByAge = customs.GroupBy(item => item.Age).ToList();
var lookupList = customs.ToLookup(i => i.Age);(更优)
Task的基本使用:需要引用System.Threading.Tasks命名空间
构造函数创建Task:
var task1=new Task(()=>{});//关键字var只能出现在局部变量声明或者是脚本代码中
task1.Start();//构造函数定义的Task必须手动启动
通过静态工厂创建Task:
Var task2=Task.Factory.StartNew(()=>{}); //自动启动
Task的生命周期:
Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过
WaitinToRun:等待任务调度器分配线程给任务执行
RanToCompletion:任务执行完毕
Task的任务控制:
Task.Wait();等待任务执行完成
Task.WaitAll();等待所有的任务执行完成
Task.WaitAny();等待任何一个任务执行完成
Task.ContinueWith();第一个Task完成后自动启动下一个Task,实现Task的延续
取消Task:通过cancellation的tokens来取消一个Task
var tokenSource=new CancellationTokenSource();
tokenSource.Cancel();
Task的嵌套分为关联嵌套与非关联嵌套
非关联嵌套:
var pTask=Task.Factory.StartNew(()=>{
var cTask=Task.Factory.StartNew(()=>{
Thread.Sleep(2000);
Console.WriteLine(“Children task finished!”);
});
Console.WriteLine(“Parent task finished!”);
});
pTask.Wait();
Console.WriteLine(“Flag”);
Console.Read();
输入答案为:
Parent task finished!
Flag
Children task finished!
关联嵌套:
var pTask=Task.Factory.StartNew(()=>{
var cTask=Task.Factory.StartNew(()=>{
Thread.Sleep(2000);
Console.WriteLine(“Children task finished!”);
},TaskCreationOptions.AttachedToParent);
Console.WriteLine(“Parent task finished!”);
});
pTask.Wait();
Console.WriteLine(“Flag”);
Console.Read();
输入答案为:
Parent task finished!
Children task finished!
Flag
11.继承、封装与多态
继承:当类或方法有一定相同的属性,为了减少代码的冗余,可以使用继承关系。
封装:能够有效的避免外部错误对内部造成的“交叉感染”,使软件错误可以局部化。
减少耦合
类内部的结构可以自由修改
可以对成员进行更精确的控制
隐藏信息,实现细节
多态:引用变量到底是哪个类的实例,调用的是哪个类的实现方法都是在运行时确定的,程序具有多个运行状态,这就是多态。
接口与抽象类是多态的体现形式
接口:接口不能直接实例化
接口中没有方法体的实现
继承接口的任何非抽象类型都必须实现接口的所有成员
接口支持多重继承
抽象:抽象用abstract来修饰
抽象方法没有方法体
抽象方法必须在抽象类中
抽象类只能作为基类,无法实例化
抽象类中可以有非抽象成员
抽象类的派生类必须实现抽象方法体(大括号内的内容)
父类是抽象类,子类继承了这个类,必须把抽象类中的抽象方法重写
12.骨骼动画
骨骼动画包括:骨骼层次数据、网格Mesh数据、网格蒙皮数据(Skin Info)、骨骼的动画关键帧数据
动画融合时的上下半身速度分离控制:分2层,0层播放基础移动动画
1层设Mask(配置上半身节点),weight设1(会完全覆盖0层动作)
13.打包图集
需要下载TexturePacker包,导入unity3d中(或者使用自带的SpritePacker)
动态加载图集:[ExecuteInEditMode]不运行程序,也能执行脚本
14.xLua热更新
1.需要在Unity中添加HOTFIX_ENABLE宏之后,打开的步骤(File->Building Setting->Scripting Define Symbols下添加)
2.执行XLua/Generate Code才能正常运行
3.运行XLua/Hotfix Inject In Editor
4.将xLua-master中的XLua和plugins导入项目中,将xLua-master中的Tools复制到项目的根目录下
5.在需要修改的C#脚本前加[HotFix]
15.lambda表达式
委托:
public delegate int deleFun(int x,int y);
public static int Add(int a,int b)
{
return a+b;
}
Static void Main(string[] args)
{
deleFun dele=new deleFun(Add);
Console.WriteLine(dele.Invoke(3,4)); //7
}
匿名方法:
public delegate int deleFun(int x,int y);
static void Main(string[] args)
{
deleFun dele=delegate(int x,int y){return x+y;};
Console.WriteLine(dele.Invoke(3,4)); //7
}
Lambda表达式:
public delegate int deleFun(int x,int y);
static void Main(string[] args)
{
deleFun dele=(x,y)=>{return x+y;};
Console.WriteLine(dele.Invoke(3,4)); //7
}
泛型委托:
static void Main(string[] args)
{
Func<int,int,int> dele=(x,y)=>{return x+y;};
Console.WriteLine(dele.Invoke(3,4)); //7
}
16.unity的打包
Unity的资源来源有三个方面:1.unity自动打包资源 2.Resources 3.AssetBundle
自动打包资源:
场景中直接使用到的资源,直接存放在Assets下,在场景加载的时候自动加载,静态加载的。
Resources:
在Assets下建一个Resources文件夹,不论是否被用到,都会被打包,通过Resources.Load方法动态加载。
AssetBundle:
通过编辑器脚本将资源打包,AssetBundle与游戏包分离,可以通过WWW类来加载。
17.字典与哈希表(Hashtable)
1.单线程程序中使用Dictionary,有泛型优势,读取速度较快,容量利用更充分,无需装箱拆箱。
2.多线程用Hashtable,允许单线程写入,多线程读取,Hash table进一步调用Synchronized()方法可以获得安全的类型,字典非线性安全,必须人为使用lock语句进行保护,效率大减
3.Dictionary有按插入顺序排列数据的特性(注:当调用Remove()删除过节点后顺序被打乱)
Hashtable中的key/value均为object类型,由包含集合元素的存储桶组成。
优点:索引的方式,速度非常快
应用场合:对象缓存,树递归算法的替代,需提升效率的场合
Hashtable是System.Collections命名空间提供的一个容器
Dictionary是System.Collection.Generic命名空间下的
4.哈希表的简单操作:
添加:HashtableObject.Add(key,value);
删除:HashtableObject.Remove(key);
移除所有元素:HashtableObject.Clear();
判断哈希表是否包含特定键:HashtableObject.Contains(key);
5.遍历Hashtable(哈希表中的每个元素都是DictionaryEntry类型)
第一种:System.Collections.Hashtable ht=new System.Collections.Hashtable();
foreach(DictionaryEntry de in ht)
{
Console.WriteLine(de.Key);
Console.WriteLine(de.Value);
}
第二种:System.Collections.IDictionaryEnumerator d=ht.GetEnumerator();
while(d.MoveNext())
{
Console.WriteLine(“key:{0} value:{1}”,d.Entry.Key,d.Entry.Value);
}
允许一个线程写,多个线程读
System.Collections.Hashtable htSyn=System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
字典的元素类型是键类型和值类型的KeyValuePair
18.如何提高代码的健壮性
1.尽早释放无用的对象
19.树的结构
1.二叉树:每个结点至多只有二棵子树(不存在度大于2的结点)
二叉树的第i层至多有2^(i-1)个结点
深度为k的二叉树至多有2^k-1个结点
叶子数为n0,度为2的结点数为n2,则n0=n2+1
2.满二叉树和完全二叉树
满二叉树:深度为h,层数为k,则h=k
叶子数为2^h
第k层的结点数为2^(k-1)
总结点数为2^k-1
完全二叉树:若设二叉树的深度为h,除第h层外,其他各层的结点数都达到最大,第h层的结点都集中在最左边
具有n个结点的完全二叉树的深度为log2(n+1)
3.二叉查找树(二叉排序树、二叉搜索树):对树进行中序遍历,可得到有序的数列。
若左子树不为空,则左子树上所有的结点的值均小于它的根结点的值
若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值
左、右子树也分别为二叉排序树
没有键值相等的结点
二叉查找树的高度决定了二叉查找树的查找效率。