C#和Unity学习笔记

7.23
数据类型:
值类型:普通类型(整型,浮点型,布尔型,结构体,枚举)
引用类型:String,字符串,数组,类
引用类型:1.数据的内存(堆区)2.这段内存的引用(地址)
区别:
1.值类型存储在内存栈中,引用类型数据存储在内存堆中,而数据的引用存在内存栈中。
2.栈空间小值类型存储速度快,堆空间大引用类型存储速度慢。
3.值类型系统自动回收,引用类型有垃圾回收机制(GC)回收。垃圾回收机制:当堆区内存无人使用时则回收。
4.值类型继承与System.ValueType,引用类型继承于System.Object
值类型在进行参数传递时为值传递,引用类型我引用传递。 ref:加在实参和形参前面 out:从函数中带出值(在函数中给实参赋值) c#的所有变量字使用前都必须赋值,除out修饰的实参外。
out用法示例(构建射线):
Ray ray = new Ray();
RaycastHit hitInfo;
if(Physic.Raycast(ray,out hitInfo,Mathf.Infinity))
{
//do someting;
}

Invoke(函数名,时间) 相隔多久调用某个函数(只会调用一次)
InvokeRepeating(函数名,第一次调用前等待的时间,相隔多久调用一次):重复调用
isInvoking 是否正在调用
CancelInvoke():取消所有函数的调用
CancelInvoke(String methodName);取消某个函数的调用

c#中的数据结构:
1.数组:缺点大小固定,内存连续,不方便添加删除;
int [][] map = new int[10][10];//定义了一个十行十列的二维数组。
2.ArrayList:数组列表
特点:1.内存连续,可以通过下标访问(this[int index]) 2.大小不固定 3。可以存储不同数据类型的数据。
缺点:频繁的装箱拆箱影响效率 装箱:将值类型转化为引用类型的过程 拆箱:将引用类型转化为值类型的过程
ArrayList arrlist = new ArrayList(); arrlist.Add();//添加元素 arrlist.Remove();//移除元素 int i = (int)arrlist[0];//拆箱
3.List列表
特点:1.内存连续,可以通过下标访问 2.大小不固定 3.只能存储相同数据类型
缺点:不方便添加删除
4.LinkedList:双向链表
特点:1.内存不一定连续,不可以通过下标访问 2.大小不固定 3.只能存储相同数据类型
缺点:不方便访问元素、

7.24
1.String和StringBuilder
String:字符串类(引用类型,在堆上分配内存);做=、+=、-=运算时产生临时的对象保存,使用完使用GC回收,影响效率。
StringBuilder:StringBuilder在当前自身字符串上进行。StringBuilder通过volatile关键字来实现运算不需要产生临时对象。
C# 中 StringBuilder和String的区别:https://www.cnblogs.com/sevensky/articles/1211688.html
详解C中volatile关键字:https://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html

查找游戏物体的方法:
1.GameObject.Find(string objectName)
2.GameObject.FindWithTag(string TagName)
3.GameObject.FindGameObjectWithTag(string TagName)返回数组

访问组件方式:
1.定义public变量,在面板上将游戏物体指定给该变量。
2.GetCompont<组件名称>()
3.GetCompontInChildren<组件名称>()获取子物体的组件
4.GetCompontInParent<组件名称>()获取父物体的组件

委托和事件:c++的函数指针
委托是一种数据类型;
委托类型的定义:
delegate:委托关键字
访问权限:delegate 返回值类型 委托类型名(形参表)
委托变量的定义:委托类型 + 变量名
赋值:用函数名赋值
调用函数:委托变量(实参表)

c#特殊的委托:
Action:指向返回值类型为void且形参个数小于等于4的函数
Func:指向带返回值且形参个数大于等于4的函数

多播委托:委托变量指向多个函数。 +=:再添加一个响应函数;-=:减少一个响应函数

匿名函数:
delegate (形参表)
{
函数体;
} ;
{}和;不能省略。

虚函数和虚属性:
1.虚方法:返回值前加上virtual关键字;
重写:override关键字不可以省略;重写不能改变函数访问的权限;只能重写virtual和abstract方法。
Base关键字:显示调用父类的方法;调用父类的构造函数
New关键字:写在返回值前(当与父类方法名相同时,表示一个新的方法)

抽象函数:在函数返回值前加abstrac关键字(C++的纯虚函数)只有声明,没有定义。
抽象类:含一个及以上抽象方法的类称为抽象类
1.抽象类不能实例化对象,但可以创建抽象类的引用;2.继承于抽象类的类必须实现抽象类的全部抽象方法(必须添加override关键字)才能创建实例 。

密封:
密封函数:在返回值前加Sealed关键字,表示这个方法不能被重写
密封类:表示这个类不能被继承

静态:
静态函数:可以通过类名调用(静态构造函数不能包含访问修饰符)
静态类:所有的方法必须为静态;构造函数只能调用一次;静态类只能继承system.Object。

接口(Interface)
一般以I字开头,表示为接口;接口中只能有属性和方法,索引擎和event。不能有字段;接口不能创建实例,但可以创建引用;接口只能继承为接口;接口的成员不能加访问权限;接口中不能有构造函数。
继承接口的类必须实现接口中的所有方法,不能加override关键字。

抽象类和接口的区别:
1.抽象类和接口都不能直接实例化。抽象类变量必须指向所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2.抽象类要被子类继承,接口要被类实现(才能用)
3.接口只能做方法声明,抽象类中可以做方法声明也可以做方法实现。
4.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5.抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父的抽象方法,那么该子类只能是抽象类。同样实现接口的时候,如不能全部实现接口方法,那么该类只能是抽象类
6.抽象方法只能声明,不能实现。接口是设计的结果,抽象0是重构的结果。
7.抽象类中可以没有抽象方法。
8.如果一个勒种有一个抽象方法,那么这个类只能是抽象类。
9.抽象方法要被实现,所以不能是静态的,也不能是私有的。
10.接口可以继承接口,并可以多继承接口,但类只能单继承。

抽象类使用来捕捉子类的通用特性的。他不能被实例化,只能被用作子类的超类,抽象类是被用来创建继承层级里子类的模板。
接口是抽象方法的集合。如果一个类实现了某个接口,那么他就继承了这个接口的抽象方法,这就像契约模式,接口是一种形式,自身不做任何事情。

如果你拥有一些方法并想让他们中的一些有默认实现,那么使用抽象类吧。
如果你想实现多重继承,那么你必须使用接口。如果基本功能再不断改变,抽象类走起(不改变基本功能->接口)。
如果用了接口又要不断改变功能,那么需要改变所有实现了该接口的类。

热更新:在不需要重新安装程序的条件下对原有游戏内容进行更新
XLua(热更新解决方案):
1、lua和C#间的交互
2、实现lua脚本中内容在C#脚本中的映射

在C#脚本中运行lua代码
使用XLUA在C#中运行Lua代码的过程
1、加载lua文件
2、将lua文件中内容转化成字符床
3、通过lua虚拟机运行lua代码

lua虚拟机:
如果要在unity中运行lua代码,必须创建lua虚拟机(LuaEnv的对象)
注意:尽量保证当前运行时只有一个lua虚拟机(1、节约内存 2、放置访问同一个文件时报错)

使用lua虚拟机加载unity文件中的lua文件
在C#脚本中使用lua虚拟机使用 “require”关键字调用lua代码时会自动调用虚拟机中的loader 加载器
loader :是XLUA中的一个委托对象,包含一系列委托方法(将指定文件解析成 byte[])
通过AddLoader( customloader 函数)将自定义loader添加到委托的事件列表中(多播委托)

如果XLUA中的加载器无法使用,可以添加自定义加载器
自定义loader:在XLUA中的loader(委托对象) 中添加事件
当我们使用“require”关键字获取lua代码时,会逐一调用所有loader方法,直到有返回值产生,否则返回错误提示
自定义loader的样式 : 返回值为byte[] 参数为ref string filepath 的一个函数
public byte[] LoaderBySelf(ref string filepath)
函数中的参数 ref string filepath 表示require关键字后添加的路径

在C#脚本中运行lua代码
使用XLUA在C#中运行Lua代码的过程
1、加载lua文件
2、将lua文件中内容转化成字符床
3、通过lua虚拟机运行lua代码

使用lua虚拟机加载unity文件中的lua文件
在C#脚本中使用lua虚拟机使用 “require”关键字调用lua代码时会自动调用虚拟机中的loader 加载器
如果XLUA中的加载器无法使用,可以添加自定义加载器
自定义loader:在XLUA中的loader(委托对象) 中添加事件
当我们使用“require”关键字获取lua代码时,会逐一调用所有loader方法,直到有返回值产生,否则返回错误提示
自定义loader的样式 : 返回值为byte[] 参数为ref string filepath 的一个函数
public byte[] LoaderBySelf(ref string filepath)
函数中的参数 ref string filepath 表示require关键字后添加的路径

在函数实现的功能包括:
1、判断文件是否存在
2、将文件中内容解析成byte[]并返回
注意:通过require关键字加载的文件只能是lua脚本,如果加载其他类型的文件需要使用自定义loader(只要能返回byte[])

移动相机动作在哪个函数里,为什么在这个函数里?
LateUpdate,是在所有的update结束后才调用,比较适合用于命令脚本的执行。官网上例子是摄像机的跟随,都是所有的update操作完才进行摄像机的跟进,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。

8.13
Unity学习资料整理分享
Unity User Manual 手册 :https://docs.unity3d.com/Manual/index.html
Unity - Scripting API(API 详解):https://docs.unity3d.com/ScriptReference/index.html
LearnOpenGL 中文翻译版(超棒~) : https://learnopengl-cn.github.io/intro/
Unity 3D中的内存管理:https://onevcat.com/2012/11/memory-in-unity3d/
【Unity技巧】Unity中的优化技术 - candycat - CSDN博客:https://blog.csdn.net/candycat1992/article/details/42127811
Unity3D热更新全书-PageZero - 疯光无线 - 博客园:https://www.cnblogs.com/crazylights/p/3897742.html
猫都能学会的Unity3D Shader入门指南:https://blog.csdn.net/zhuangyou123/article/details/26077783
C# Socket编程 同步以及异步通信 - BLoodMaster - 博客园:https://www.cnblogs.com/BLoodMaster/archive/2010/07/02/1769774.html

Unity内存管理
程序代码:库剥离的方法
托管堆:频繁new或Instantiate和Destroy会影响游戏性能。解决:内存池的使用
本地堆:Unity最初的设计目的还是面向台式机,几乎无限的内存和虚拟内存使得这样的占用似乎不是问题,但是这样的内存策略在之后移动平台的兴起和大量移动设备游戏的制作中出现了弊端,因为移动设备能使用的资源始终非常有限。因此在面向移动设备游戏的制作时,尽量减少在Hierarchy对资源的直接引用,而是使用Resource.Load的方法,在需要的时候从硬盘中读取资源,在使用后用Resource.UnloadAsset()和Resources.UnloadUnusedAssets()尽快将其卸载掉。总之,这里是一个处理时间和占用内存空间的trade off,如何达到最好的效果没有标准答案,需要自己权衡。

8.14
内存池的原理:
频繁的new和delete需要频繁的对内存进行切割和合并,十分耗时。
内存碎片:连续的new和delete把一大块连续的内存分割成不连续的小内存。
解决—>内存池技术:大小固定、提前申请、重复利用

优化相关:
主要这几方面:
CPU
问题:过多的Draw Calls;复杂的脚本或者物理模拟
解决:减少Draw Calls

顶点处理
问题:过多的顶点;过多的逐顶点计算
解决:优化几何体;使用LOD(Level of detail)技术;使用遮挡剔除(Occlusion culling)技术

像素处理
问题:多的fragment,overdraws;过多的逐像素计算
解决:控制绘制顺序;警惕透明物体;减少实时光照

带宽
问题:尺寸很大且未压缩的纹理;分辨率过高的framebuffer
解决:减少纹理大小;利用缩放

sdk相关的知识
第三方SDk 包括渠道SDK,用户系统,支付系统,广告系统,统计系统,分享系统等等。

第三方SDK:
验证流程:
三方SDK向SDK-SERVER请求token,请求到token后,APP向GAME-SERVER请求access token,GAME-SERVER向AnySDK Server转发请求,再由AnySDK Server向SDK-SERVER请求access token。access后原路返回通知APP。
优点:可快速轻松接入
缺点:数据要经过三方服务器;对验证服务器没有完全自主的控制权;一些其他的诡异的SDK。

你可能感兴趣的:(unity3D学习)