图片导入和相关参数

Unity支持的图片格式

  • BMP 是Windows操作系统的标准图像文件格式,特点是几乎不进行压缩,占用磁盘控件较大
  • TIF 基本不损失图片信息的图片格式 缺点是体积较大
  • JPG 一般用JPEG格式 是损压缩 能够让图像压缩在很小的存储控件 一定程度上会损失图片数据 无透明通道
  • PNG 无损压缩算法的位图格式 压缩比高 生成的文件小 有透明通道
  • TGA 支持压缩 使用不失真的压缩算法 还支持编码压缩 体积小 效果清晰 兼备BMP的图像质量和JPG的体积优势 有透明通道
  • PSD 是Photoshop的专用格式 可以通过一些第三方工具或者自制工具 将PSD界面转为UI界面

其他还支持EXR、GIF、HDR、IFF、PICT等格式,一般常用的格式是JPG、PNG、TGA三种格式。


图片参数相关

Texture Type纹理类型


**Default ** 默认纹理 大部分导入的模型贴图都是该类型

  • sRGB(Color Texture) 启用可以将纹理存储在伽马空间中(对每一个像素做一次幂函数运算)
  • Alpha Source 指定如何生成纹理的Alpha通道
    • None 无论输入纹理是否有Alpha通道 导入的纹理都没有Alpha通道
    • Input Texture Alpha 输入纹理中的Alpha
    • From Gray Scale 从输入纹理RGB值的平均值生成Alpha
  • Alpha is Transprency 启用可以避免边缘上的过滤瑕疵

Normal map 法线贴图格式

  • Create From Grayscale 启用此属性可以从灰度高度贴图创建法线贴图
  • Bumpiness 控制凹凸程度 值越大凹凸感越强
  • Filtering 如何计算凹凸值
  • Editor GUI and Legacy GUI 一般在编辑器中或者GUI上使用的纹理

Sprite(2D and UI) 在2D游戏中或者UGUI中使用的格式

UI系统-NGUI

NGUI

创建NGUI

  • Project面板左键 或者在导航栏 选择NGUI
  • 选择Create 2D UI

UI Root

Scaling Style 分辨率自适应模式

  • Flexible 灵活模式

    • 在该模式下 UI都是以像素为基础,100像素的物体无论在多少分辨率上都是100像素
    • 这就意味着 100像素在分辨率低的屏幕上可能显示正常 但是在高分辨率的屏幕上就很小
  • Flexible模式的配置参数

    • Minimum Height 屏幕高度小于该值时 开始按比例缩放
    • Maximum Height 屏幕高度 大于该值时 开始按比例缩放
    • Shrink Portrait UI 竖屏时 按宽度来适配
    • Adjust By Dpi 使用dpi做计算 建议勾选
  • Constrained 约束模式

    • 在该模式下 屏幕按尺寸比例来适配 不管实际屏幕有多大
    • NGUI会通过合适的缩放来适配屏幕
    • 好处是在各个设备上看到的ui和比例是一样的 但是有可能会因为缩放显示模糊
  • Constrained 参数

    • Content Width 按照该宽度值适配屏幕(制作资源时的默认分辨率宽)
    • Content Height 按照该高度值适配屏幕(制作资源时的默认分辨率高)
    • Fit表示以哪个值来做适配
      • Width:UI会横向填充屏幕
      • Height:UI会纵向填充屏幕
      • 两个都勾选 不会被裁剪 但是会有黑边 当宽高比大于实际宽高比时 按宽度适配 反之按高度适配
      • 两个都不勾选 始终保证屏幕被UI填充满 不会有黑边 但内容可能会被裁剪
  • Constrained On Mobile 混合模式

Unity工程文件夹

Unity工程文件夹

  1. **Assets:**工程资源文件夹(美术资源、脚本等等)
  2. **Library:**库文件夹(Unity自动生成管理)
  3. **Logs:**日志文件夹、记录特殊信息(Unity自动生成管理)
  4. **Packages:**包配置信息(Unity自动生成管理)
  5. **ProjectSettings:**工程设置信息(Unity自动生成管理)

工程路径获取

  • 一般只在编辑模式下使用
  • 游戏发布后这个路径就不存在了
Application.dataPath;

Resources 资源文件夹

  • 默认没有这个文件夹 需要自己创建
  • 需要通过Resources相关API动态加载的资源需要放在其中
  • 该文件夹下所有文件都会被打包出去
  • 打包时Unity会对其压缩加密
  • 该文件夹打包后只读 只能通过Resources相关api加载
  • 可以有多个Resources文件夹

StreamingAssets流动资源文件夹

  • 打包出去不会被压缩加密
  • 移动平台只读 pc平台可读写
  • 可以放入一些需要自定义动态加载的初始资源

路径获取

Application.streamingAssetPath;

persistentDataPath持久数据文件夹

  • 不需要我们自己创建
  • 每个平台的路径不同
  • 所有平台可读写 一般用于放置动态下载或者动态创建的文件,游戏中创建或者获取的文件都放在其中
Application.persistentDataPath;

plugins插件文件夹

  • 一般不获取
  • 需要我们自己创建
  • 不同平台的插件相关文件放在其中 比如ios或者android平台

Editos编辑器文件夹

  • 需要我们自己创建
  • 开发Unity编辑器时,编辑器相关脚本放在该文件夹中
  • 该文件夹内容不会被打包出去

Standard Assets默认资源文件夹

  • 默认资源文件夹
  • 一般Unity自带资源都放在这个文件夹下
  • 代码和资源优先被编译

Unity开发的本质

Unity开发的本质

利用反射和引擎提供的各种功能 进行拓展开发

Unity本质上是一个运行中的程序 通过读取对象的信息 来创建场景和物体等

反射:程序在运行时,可以查看其他程序集或者自身的元数据

一个运行的程序查看本身或者其他程序的元数据行为就叫做反射

在程序运行时,通过反射可以得到其他程序集或者自己程序集中的代码信息(例如类,函数,变量对象等等)我们可以获取到之后实例化他们或者执行 操作等等

场景中的对象本质是什么?

GameObject类对象是Unity引擎提供给我们的

游戏场景中所有的对象(图片,模型,摄像机等等)都继承于GameObject对象

List

List

  • List是C#为我们封装好的类
  • 它的本质是一个可变类型的泛型数组
  • List类帮助我们实现了很多方法
List<int> list = new List<int>();
List<int> list2 = new List<int>();
//添加数据
list.Add(1);
//添加另一个list进去
list.AddRange(list2);

//移除指定的元素
list.Remove(1);
//移除指定位置的元素
list.RemoveAt(0);
//清空
list.Clear();

//查
list[下标];
//查看元素是否存在
bool have1 = list.Contains(1);

//正向查找元素位置 找到了返回位置 找不到返回-1
int index = list.IndexOf(1);
//反向
inde = list.LastIndexOf(1);

//获取长度
list.Count;
//获取容器容量
list.Capacity;

MonoBehavior

MonoBehavior基类

  1. 继承了Mono才能够挂载到GameObject上(Unity通过反射去判断是否继承自Mono 继承了才可以挂载)
  2. 继承了Mono的脚本不可以被new 只可以挂载
  3. 继承Mono的脚本 不需要写构造函数,因为我们不会去new他
  4. 一个对象上可以挂载多个Mono脚本(如果没有加DisallowMultipleCpomponent特性)
  5. 继承Mono的类也可以被多次继承,遵循面向对象继承多态的规则

不继承MonoBehavior的类

  1. 不继承Mono的类 不能挂载在GameObject上
  2. 想怎么写就怎么写 使用时需要自己new
  3. 不继承Mono的类一般是单例模式的类(用于管理模块)或者数据结构类(用于存储数据)
  4. 不用保留默认的生命周期函数

MonoBehaviour成员变量

  • gameObject该脚本附着的GameObject
  • transform该脚本附着对象的transform
  • enable 是否激活(控制这个脚本的) 修改物体的激活状态需要使用gameObject.SetActive();

常用方法

  1. 获取对象上的脚本
GetComponent("脚本名") as 类型;//通过脚本名获取
GetComponent(typeof(脚本名)) as 类型;//根据Type获取
GetComponent<类型>();//推荐使用泛型的方式获取
GetComponents<类型>();//得到挂载的多个脚本 返回一个数组
//另一种写法
List<类型> list = new List<类型>();
GetComponents<类型>(list);
//得到子对象挂载的脚本(也会去找自己身上是否挂载该脚本)
GetComponentInChildren<类型>(false);//true失活也找 默认false
GetComponentsInChildren<类型>(false);//true失活也找 默认false 寻找多个返回一个数组
//得到父对象挂载的脚本
GetComponentInParent<类型>();
GetComponentsInParent<类型>();//寻找多个 返回一个数组
  1. 尝试获取脚本
类型 test;
TryGetComponent<类型>(out test); //返回一个bool 可用if判断

ref和out关键字

ref和out

  • ref和out可以在函数内部 修改外部传入的内容(当传入的值类型参数在函数内部修改时 或引用类型的参数在内部重新声明时 外部的值会发生变化)
  • ref和out是函数参数的修饰符
  • ref可作为参数传入并修改(需要在外部赋值后传入),out只可以修改外部的值 不可以作为参数传入 必须在函数内部赋值
  • ref传入的变量必须初始化 但是在内部 可改可不改
  • out传入的变量不用初始化,但是在内部 必须赋值
public void ChangeString(ref string value){
	value = "测试啦啦啦";
}
string test = "99";
ChangeString(ref test);
Print(test);//输出测试啦啦啦

Resources资源加载

Resources资源加载

  • 通过代码动态加载Resources文件夹下指定路径资源
  • 在一个工程中 Resources文件夹可以有多个 打包时所有Resources文件夹里的资源都会被整合在一起
  • 避免繁琐的拖拽操作

常用的资源类型

  • 预设体对象 GameObject
    • 预设图对象加载需要实例化 其他资源加载一般可以直接用
  • 音效文件 AudioClip
  • 文本文件 TestAsset
  • 图片文件 Texture
  • 其他类型 需要什么就用什么类型

资源加载 普通方法

Object obj = Resources.Load("Cube");
Resources.load<GameObject>("Cube");//泛型

Resources异步加载资源

  • 异步加载不能马上得到加载的资源 至少要等一帧
  • 异步加载就是内部新开一个线程进行资源加载 不会造成主线程卡顿
ResourceRequest rq = Resources.LoadAsync<GameObject>("路径");
//在加载完成后 会调用completed事件 参数AsyncOperation
rq.completed += LoadOver;
private void LoadOver( AsyncOperation rq)
{
    print("加载结束");
    //asset 是资源对象 加载完毕过后 就能够得到它
    obj = (rq as ResourceRequest).asset as GameObject;
}

通过携程加载资源

StartCoroutine(Load());
IEnumerator Load()
{
    ResourceRequest rq = Resources.LoadAsync<GameObject>("路径");
	//携程返回值yield return asyncOperation;等异步操作结束后再执行后续代码
    //ResourceRequest继承自asyncOperation
    //yield return rq;判断资源是否加载结束
    while(!rq.isDone)
    {
        //打印当前的 加载进度 
        //该进度 不会特别准确 过渡也不是特别明显
        print(rq.progress);
        yield return null;
    }
    obj = rq.asset as GameObject;
}

卸载资源

  • 该方法不能释放GameObject对象 因为他会用于实例化对象
  • 只能用于一些 不需要实例化的内容 图片 音效 文本等等
  • 一般情况下很少单独使用它
var tex = Resources.Load<Testure>("Tex/TestJPG");
Resources.UnloadAsset(tex);

卸载未使用的资源

//一般在过场景时和GC一起使用
Resources.UnloadUnusedAssets();
GC.Clollect();

异步加载场景

AsyncOperation ao = SceneManager.LoadSceneAsync("场景名");
ao.completed +=(a)=>{
    Debug.log("场景加载完了");
}

通过携程异步加载场景

在加载场景时 unity会删除当前场景下所有的对象,携程脚本依附的物体如果被删除 那么携程就不会执行了所以需要特殊处理

UI系统-GUI

GUI是什么

  • 全称 即时模式游戏用户交互界面(IMGUI)
  • 在Unity中一般简称为GUI 他是一个代码驱动的UI系统

GUI的作用

  • 作为程序员的调试工具,创建游戏内的调试工具
  • 为脚本组件创建自定义监视面板
  • 创建新的编辑器窗口和工具 以及拓展unity本身(一般用作内置游戏工具)
  • 不要用它为玩家制作ui功能

GUI的工作原理

  • 在继承Mono的脚本中的特殊函数里
  • 调用GUI提供的方法 类似生命周期函数
private void OnGUI(){
    //GUI的相关代码
}

OnGUI

  • 它每帧执行 相当于是专门绘制GUI界面的函数
  • 一般只在其中执行GUI相关界面绘制和操作逻辑
  • 该函数在OnDisable之前 LateUpdate之后执行
  • 只要是继承Mono的脚本 都可以在OnGUI中绘制GUI

GUI基本控件

GUI控件绘制的共同点

  • 他们都是GUI公共类中提供的静态函数 直接调用即可
  • 他们的参数都大同小异
    • 位置参数:Rect参数 xy位置 wh尺寸
    • 显示文本:string 参数
    • 图片信息:Texture参数
    • 综合信息:GuiConten参数
    • 自定义样式:GUIStyle参数
  • 每一种控件都有多种重载,都是各个参数的排列组合,必备参数是 位置信息和显示信息

文本控件

//创建一个 位置为0 0 宽带100 高度30的文本控件
GUI.Label(new Rect(0,0,100,30), "我爱吃肉");
//可在面板上设置参数
public Rect rect;
public GUIContent content;
public GUIStyle style;//字体样式
GUI.Label(rect, content,style);

按钮控件

//创建一个 位置为0 0 宽带100 高度30的按钮 返回float
GUI.Button(new Rect(0,0,100,30), "我爱吃肉");
//可在面板上设置参数
public Rect rect;
public GUIContent content;
public GUIStyle style;//字体样式
if(GUI.Button(rect, content,style)){
    Debug.Log("按钮被点击");
}
//长按按钮
if(GUI.RepeatButton(rect, content,style)){
    Debug.Log("按钮被长按");
}

多选框

private bool isSel;
//第二个参数bool  多选框的状态bool 返回值是否被点击
isSel = GUI.Toggle(rect,isSel,"效果开关");

//一组单选实现
int nowSelIndex = 0;
if(GUI.Toggle(rect,nowSeleIndex==1;,"效果开关1")){
    //如果被选中nowSeleIndex等于1
    nowSeleIndex==1;
}
if(GUI.Toggle(rect,nowSeleIndex==2;,"效果开关2")){
    //如果被选中nowSeleIndex等于1
    nowSeleIndex==2;
}
if(GUI.Toggle(rect,nowSeleIndex==3;,"效果开关3")){
    //如果被选中nowSeleIndex等于1
    nowSeleIndex==3;
}

输入框

public Rect rect;
string inputText;
//参数里的string是显示的内容  int最大长度
inputText = GUI.TextField(rect,inputText,5);
//密码输入
string inputPW;
//*替代字符
inputPW = GUI.PasswordField(rect,inputPW,'*')

拖动条

//水平拖动条
public Rect rect;
float sliderValue;
//第一个float 当前的值
//第2个和第3个float 最小值和最大值
GUI.HorizontalSlider(rect,sliderValue,0f,100f);
//垂直拖动条
GUI.VerticalSlider(rect,sliderValue,0f,100f);

绘制图片

public Rect rect;
public Texture texture;//图片
GUI.DrawTexture(rect,texture);
public bool alpha = true;//是否启用透明度
public ScaleMode mode = ScaleMode.StretchToFill;//缩放模式
public float wh =0; //自定义宽高比
GUI.DrawTexture(rect,texture,mode,alpha,wh);

框绘制

public Rect rect;
//可以在框中显示文字
GUI.Box(rect,"123");

GUI符合控件

工具栏

private int toolbarIndex = 0;
private string[] toolbarInfos = new string[]{"选项1","选项2","选项3"};
public Rect rect;
toolbarIndex = GUI.Toolbar(rect,toolbarIndex,toolbarInfos);

选择网络

public Rect rect;
private int selectionGridIndex = 0;
private string[] SelectionGridInfos = new string[]{"选项1","选项2","选项3"};
//2 一行最多显示2个
selectionGridIndex = GUI.SelectionGrid(rect,selectionGridIndex,SelectionGridInfos,2)

控件分组

  • 用于批量控制控件的位置
  • 可以理解为 包裹着的控件加了一个父对象
  • 可以通过控制分组来控制包裹控件的位置
public Rect groupPos;
GUI.BeginGroup(groupPos);
GUI.Button(new Rect(0,0,100,30)."按钮1");
GUI.Button(new Rect(30,0,100,30)."按钮2");
GUI.Button(new Rect(60,0,100,30)."按钮3");
GUI.EndGroup(groupPos);

滚动列表

public Vector2 nowPos//内容的当前位置
public Rect scPos;//ScrollView的位置和大小
public Rect showPos;//内容的位置和尺寸 要比ScrollView大
nowPos = GUI.BeginScrollView(scPos,nowPos,showPos)
private string[] toolbarInfos = new string[]{"选项1","选项2","选项3","按钮4"};
GUI.Toolbar(new Rect(0,0,300,50),toolbarInfos,0);
GUI.Toolbar(new Rect(0,60,300,50),toolbarInfos,0);
GUI.Toolbar(new Rect(0,120,300,50),toolbarInfos,0);
GUI.Toolbar(new Rect(0,180,300,50),toolbarInfos,0);
GUI.EndScrollView();

窗口

public Rect rect;

//1是窗口id
GUI.Window(1,rect,DrawWindow,"测试窗口")   
    
GUI.Window(2,rect,DrawWindow,"测试窗口")      
//委托函数 里面是窗口里的内容
//rect以窗口里的0,0为远点
private void DrawWindow(int id){ //id=1
	GUI.Button(rect,"按钮")
}

模态窗口

  • 模态窗口 可以让窗口以外的控件失效
  • 可以理解为窗口再最上层
GUI.ModalWindow(1,rect,DrawWindow,"模态窗口");

拖动窗口

public Rect rect;
public Rect windowPos;
//窗口返回值Rest
windowPos = GUI.Window(1,windowPos,DrawWindow,"测试窗口");   
private void DrawWindow(int id){ //id=1
	GUI.Button(rect,"按钮")
     //该ip写在窗口的委托函数中调用 可以让窗口被拖动
     GUI.DrageWindow();
    //重载 可以决定窗口中哪一部分位置可以被拖动 默认所有位置都可以被拖动
    GUI.DrageWindow(new Rect(0,0,1000,20));
}

自定义皮肤样式

全局颜色

//全局的着色 影响背景和文本的颜色
//不常用 添加了style也会呗覆盖
GUI.color = Color.red;
GUI.contentColor = Color.yellow;//文本颜色 颜色会和全局着色相乘
GUI.backgroundColor = Color.yellow;//背景颜色 颜色会和全局着色相乘
GUI.Button(rect,"red按钮")
GUI.color = Color.white;//可以再写一个来修改
GUI.Button(rect,"white按钮")

整体皮肤样式

//全局的皮肤样式 默认是null
//可以去创建GUI Skin文件 里面是各种控件的gui style
GUI.skin = null;

GUILayout自动布局

  • GUILayout可以点出GUI中的各种控件
  • 会自动布局 自动调整控件的大小 不需要传入Rect
  • 主要用于编辑器开发
  • 可以和GUI配合使用
GUILayout.BeginHorizontal(new Rect(100,100,100,100));//水平绘制 可以修改大小范围等等
GUILayout.Button("测试按钮");
GUILayout.Button("测试按钮");
GUILayout.Button("测试按钮");
GUILayout.EndHorizontal();

GUILayoutOption布局规则

GUILayout.Button("测试按钮"GUILayoutOption可变参数可传入多个);
//控件的固定宽高
GUILayoutOption.Width(300);
GUILayoutOption.Height(200);
//允许控件的最小宽高
GUILayout.MinWidth(50);
GUILayout.MinHeight(50);
//允许控件的最大宽高
GUILayout.MaxWidth(100);
GUILayout.MaxHeight(100);
//允许或禁止水平拓展
GUILayout.ExpandWidth(true);//允许
GUILayout.ExpandHeight(false);//禁止
GUILayout.ExpandHeight(true);//允许
GUILayout.ExpandHeight(false);//禁止

Inspector窗口

Inspector窗口可编辑的变量

  • Inspector显示的可编辑内容就是脚本的成员变量
  • 私有(private)的和保护(protected)的默认不会显示 可在变量前面加上强制序列化字段特性[SerializeField]使其显示出来
  • 公共的(public)默认会在Inspector窗口中显示出来,如果不想让其显示可在变量前增加特性[HideInInspector]
  • 大部分的类型都可以显示编辑,字典不可以被Inspector窗口显示
  • 可让自定义类型可以被访问 加上序列化特性[System.Serializable]
//在inspector中显示字段
public int test;
//不再inspector显示公共的字段
[HideInInspector]
public int test1;
//在inspector显示私有和保护的字段
[SerializeField]
private int test2;
//让自定义类型可以被访问
[System.Serializable]
public class test3{
    public int age;
    public bool sex;
} 
public test3 test4;

一些辅助特性

  1. 分组说明特性Header 为成员分组
[Header("基础属性")]
public int age;
public bool sex;
[Header("战斗属性")]
public int atk;
public int def;
  1. 悬停注释Tooltip为变量添加说明
[Tooltip("闪避")]
public int miss;
  1. 间隔特性Space 让两个字段出现间隔
[Space()]
  1. 修饰数值的滑条范围Range
[Range(0,10)]//[Range(最小值,最大值)]
public float luck;
  1. 多行显示字符串 不写参数默认显示3行
[Multiline(5)]
public string tips;
  1. 滑动条显示字符串 不写参数默认就是超过3行显示滚动条
[TextArea(3,4)]//最少显示3行,最多4行,超过4行显示滚动条
public string myLife;
  1. 为变量添加快捷方法ContextMenuItem
//[ContextMenuItem("显示按钮名", "方法名")]
[ContextMenuItem("重置钱", "Test")]
public int money;
private void Test()
{
    money = 99;
}
  1. 为方法添加特性能够在Inspector中执行[ContextMenu(“测试函数”)]
[ContextMenu("哈哈哈哈")]
private void TestFun()
{
    print("测试方法");
}

Lambda表达式和闭包

ambda表达式

  • 使用起来和匿名函数相同
Action a = ()=>{
	Console.WriteLine("无参无返回值");
};
Action<int> a1 = (int value )=>{Console.WriteLine("有参无返回值"+value);};
// 可以省略类型 如果只有一个参数 可以省略括号
a1 = value =>{Console.WriteLine("有参无返回值"+value);};
//有返回值 有参数
Func<int,string> f1= value => {return "1"+value;}; 

闭包

  • 内层的函数可以用用包含在外层函数的变量
  • 即使外层函数的执行已经终止
  • 注意:
    • 该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值
class Test{
    public Action action;
    public Test(){
        int value = 10;//value是临时的 一般情况下函数执行完就会被回收
        action = ()=>{
            //引用了临时变量value
            //此时value的生命周期被改变 value只有action=null时才会被释放
            Console.WriteLine(value);
        }
        
        for(int i = 0; i < 10; i++){//i临时变量
            action += ()=>{
                Console.WriteLine(i); //调用Action()打印999999999  i的最终值
            } 
        }
    }    
}

LineRenderer画线

LineRenderer 画线

LineRenderer是Unity提供的一个用于画线的组件使用它我们可以在场景中绘制线段

一般可以用于

  • 绘制攻击范围
  • 武器红外线
  • 辅助功能
  • 其他画线功能

LinRenderer组件属性

Loop 是否连接终点和起点

Positions线段的点

  • Size 点的数量 两个点构成一个线段 xyz轴对应世界坐标
  • width 可以修改线的粗细 通过曲线

Color 颜色

Corner Vertices 角顶点,圆角 增加此属性可以使线角看起来更圆

End Cap Vertices 终点和起点的圆角

Use World Space 是否使用世界坐标系

Materials 线使用的材质球

不常用属性

Alignment 对其方式

  • View 视点 线段对这摄像机
  • Transform Z 线段面向其Z轴

Texture Mode纹理模式

  • Stretch拉伸 沿整条线映射纹理一次
  • Tile 瓷砖平铺 不停的重复纹理
  • Distribute Per Segment 分配执行
  • Repeat Per Segment 重复显示

Shadow Bias 阴影偏移

Generate Lighting Data 生成光源数据

Lighting 光照影响

  • Cast Shadows是否开启阴影
  • Receive Shadows 接收阴影

Probes光照探针

特殊语法

var

  • var是一种特殊的变量类型 可以用来表示任意类型的变量
  • var不能作为类的成员 只能用于临时变量的声明
  • var必须初始化
  • 可以声明为自定义的匿名类型
var a = 5;//int
var str = "122";//string
//匿名类型
var v = new {age = 10,money = 11,name="明"}
Console.Write(v.age);

设置对象的初始值

class Test{
    public int Age{get;set;}
    public string Name{get;set;}
}
Test t = new Test(){Age = 5,Name = "路飞"};
//可省略括号
Test t2 = new Test{Age = 5,Name = "路飞"};

设置集合的初始值

int[] array = new int[]{1,2,3,4,5};
List<int> listInt = new List<int>(){1,2,3,4,5};
List<Test> listTest = new List<Test>(){
    new Test(),
    new Test{Age = 15,Name = "阿拉拉"}
}

可空类型

  • 值类型不可以为空
  • 可空类型可以让值类型为空 声明时在类型后加?
  • 使用时需要判断是否为空
int a = null;//报错
int? b = null;
if(b.HasValue){ //可空类型其实是一个泛型结构体包裹了int HasValue是可空类型提供的方法
    Console.WriteLine(b);
}

安全获取可空类型的值

int? value = null;
//不填参数返回这个参数的默认值 0  也可以指定一个默认值 作为参数填入
Console.WriteLine(value.GetValueOrDefault());

可空类型语法糖

object o = null;
if(o!=null){o.Tostring()}
//可以直接写成
o?.ToString();//如果是空则不会执行ToSring

空合并操作符

  • 空合并操作符??
  • 左边值??右边值
  • 如果左边值为null 就返回右边值 否则返回左边指
  • 只要是可以为null的类型就可以使用
int? a = null;
int b = a == null ? 100 : a.Value;//三目运算符写法
int c = a??100;  //如果a为null返回100 否则返回a

内插字符串

  • 关键符号:$
  • 用$来构造字符串,让字符串中可以拼接变量
string name = "肥伦";
Console.WriteLine($"好好学习{name}");
//等同于
Console.WriteLine("好好学习{0}",name);
Console.WriteLine("好好学习"+name);

单句逻辑简略写法

if(true)return;
for(int i = 0;i<5;i++)Console.WriteLine(i);

public int add(int x,int y) => x + y;
public int Age{get=>age;set=>age=10;}

坐标系转换

Unity坐标转换

世界坐标系的点 转换为 本地坐标系的点

//受到缩放影响
transform.InverseTransformPoint(世界坐标);

世界坐标系的方向 转换为 本地坐标系的方向

//不受缩放影响
transform.InverseTransformDirection(世界坐标);
//受缩放影响
transform.InverseTransformVector(世界坐标);

本地坐标系的点 转换为 世界坐标系的点

//受缩放影响
transform.TransformPoint(本地坐标);

本地坐标系的方向 转换为 世界坐标系的方向

//受缩放影响
transform.TransformVector(本地坐标);
//不受缩放影响
transform.TransformVectorDirection(本地坐标);

屏幕坐标和世界坐标转换

//得到主摄像机对象 上的深度 进行设置
Camrea.main.depth = 10;
//世界坐标转屏幕坐标(物体在这个摄像机上的屏幕坐标)
//xy对应屏幕坐标 z对应的是这个3d物体距离摄像机有多远
Vector3 v = Camera.main.WorldToScreenPoint(obj.transform.position);
//屏幕坐标转世界坐标
Vector3 mp = Input.Mouseposition;
//需要对z轴赋值 因为屏幕坐标是一个2D的
//如果Z为0 相当于是视口的交点
mp.z = 10;
Vector3 v = Camera.main.ScreenToWorld(mp);

字符串string

String

  • 字符串的本质是一个Char数组
  • 可使用String类内部的索引器 直接使用[下标]来得到对应的字符
  • 也可通过.Length获取长度
string str = "test";
//string类 索引器
Console.WriteLine(str[0]);//t char类型
str.Length//获取字符串长度

字符串转char数组

char[] chars = str.ToCharArray(); //字符串转字符数组
string str3 = new string(chars)//字符数组转字符串

字符串拼接

string.Format("{0}{1}",11,33); //1133

正向查找字符位置

str = "我爱吃肉";
int index = str.IndexOf("吃肉");//2
index = str.IndexOf("吃菜");//-1

反向查找

运算符重载

运算符重载

  • 让自定义类和结构体能够使用运算符
  • 使用关键字operator
  • 不能使用ref和out
  • 只可以有两个参数
  • 如果是++ 或者– 则是一个参数
  • 条件运算符需要成对出现< >
class Point{
	public int x;
	public int y;
    //重载+
	public static Point operator +(Point p1,Point p2){
		Point p = new Point();
		p.x = p1.x+p2.x;
		p.y = p1.y+p2.y;
		return p;
	}
    //重载 重载运算符
    //顺序要相同 p+3  3+p报错
    public static Point operator +(Point p1,int value){
		Point p = new Point();
		p.x = p1.x+value;
		p.y = p1.y+value;
		return p;
	}
}

预制体(Prefabs)

可以重复使用的对象,修改预制体可应用到所有的对象

如果只修改某一个预制体 可解除预制体(Unpack Prefab)后修改

删除预制体后 场景中存在的预制体会变成红色 也可以解除预制体(Unpack Prefab)

预处理指令

预处理器指令

  • 预处理器指令 指导编译器 在实际编译开始之前对信息进行预处理
  • 预处理器指令 都是以#开始
  • 预处理器指令不是语句,所以他们不以分号;结束
  • 目前我们经常用到的 折叠代码块 就是预处理器指令

常见的预处理器指令

  • #define 定义一个符号,类似一个没有值的变量
  • #undef 取消define定义的符号 让其失效
  • 两者都是写在脚本文件最前面 一般配合if指令或者特性使用
//定义一个符号
#define Unity5
#define Unity2017
#define Unity2019
//取消定义一个符号
#undef Unity5
  • #if , #esif , #else , #endif 和if语句规则一样,一般配合#define定义的符号使用
  • 告诉编译器进行编译代码的流程控制
  • 在Unity中通常会用来进行一些平台或者版本的判断,可以根据不同的平台或版本使用不同的代码逻辑
//有if就要有endif
#if Unity5   //如果发现有Unity5这个符号 那么其中包含的代码 就会被编译器编译
        Console.WriteLine("版本为Unity5");
#elif Unity2017 || Unity2019 //可以通过逻辑或 和逻辑与 进行多种符号的组合判断
        Console.WriteLine("版本为Unity2017或者Unity2019");
#else
        Console.WriteLine("其他版本");
#endif
  • #warning , #error 告诉编译器是报警告还是报错误
  • 一般还是配合if使用
//有if就要有endif
#if Unity5   //如果发现有Unity5这个符号 那么其中包含的代码 就会被编译器编译
        Console.WriteLine("版本为Unity5");
#elif Unity2017 || Unity2019 //可以通过逻辑或 和逻辑与 进行多种符号的组合判断
#warning 这个版本太新辣
        Console.WriteLine("版本为Unity2017或者Unity2019");
#else
#error 这个版本不合法
        Console.WriteLine("其他版本");
#endif

异常捕获

异常捕获

我们通过异常捕获 可以避免当代码报错时造成程序卡死

//基本语法
try
{
   //填写希望进行异常捕获的代码 如果报错 会执行catch中的代码来捕获异常
}
catch
{
    //可通过catch(Exception e)可通过e得到具体的错误信息
}
//可选部分
finally
{
    //最后执行的代码 不管有没有出错都会执行
}