标签搜索

UnityC#笔记

anker
2021-06-27 / 0 评论 / 14 阅读 / 正在检测是否收录...

书本阅读时的一些概要笔记。

  1. C#运行时和虚拟机非常相似,可能和原生宿主的C/C++进行交互。C#有不同的版本,不同的Unity支持的版本不一样。另外,Mono和.Net框架自带的类库不同。 Unity 2017.1可使用.NET4.6和C#6。 也可以使用.net3.5和C#3。而C#3/6版本 分别对应的就是VS2008/2015版本。

  2. Centos安装C#环境
  3. 了解IL2CPP和Mono区别。IL2CPP是Mono的替代品。

  4. 在不指定基类时,默认继承自System.Object, 于是有了几个基础方法。
  5. C#3版本中,var关键字实现的是编译期就可以确定的类型。而C#4的dynamic定义的变量,是真正的动态类型。类型LPC的mixed类型。但在Unity中只能使用C#3
  6. 引用和值类型对象主要差别是,一个来自托管堆分配,后者一般来自栈分配。前者涉及GC机制和昂贵的内存申请和初始化操作,后者不需要。比如class是引用类型,而struct是值类型。 值类型不可当作基类,他没有额外的类型信息。于是有了引用和值类型的区别。
  7. 在堆上分配的值类型:数组中的元素、引用类型中的值类型字段、迭代器块中的局部变量、闭包情况下匿名函数(lamda)中的局部变量。因为变量这些需要在栈销毁后还要用到。
  8. 引用类型举例:

    • 自定义引用类型:Class、Interface 、Delegate。
    • 内建的引用类型有:Dynamic、Object(System.Object) 、string (System.String, 只读)
    • 类库中的其他引用类型: System.Collections.Generic.List类、System.Text.Decoder等。
  9. 值类型

    • 结构类值类型(派生自System.ValueType)

      • 数字型结构: 常见的System.Int32 , System.Float, System.Decimal等
      • 布尔结构:System.Boolean
      • 自定义结构(使用struct关键字定义的)。使用new关键字创建,但不是从堆分配!
      • 内置的DateTime类型其实也是结构类型, 他有自己的方法。
    • 枚举类型。(派生自System.Enum, 而System.Enum又派生自System.ValueType)
      如Sytem.IO.FileAttributes、System.Drawing.FontStyle等.

    值类型的特征:

    1. 不能派生出其他类型。因此不能加新的虚方法或者抽象方法。
    2. 不需要从其他类型中派生。
    3. 值不可变。值类型没有提供更改其值的成员,称为不可变。
    4. 值传递。在传参、返回中复制。因为最好不要太大。
    5. 有未装箱和已装箱两种表示方式。装箱指把值类型转化为引用类型。比如转化为obect类型。
    6. 值类型派生自System.ValueType,而System.ValueType派生自System.Object. System.ValueType重写了GetHashCode\Equals两个方法。
  10. 值类型的装箱和拆箱:

    • 装箱. 就是将不在托管堆且不受GC机制影响的的值类型变量,转化为引用类型。本质是在托管堆中分配内存(所以托管堆对象都有额外的类型对象指针和同步索引块)。然后复制值得到堆中。最后返回引用。
    • 拆箱.就是获得已装箱对象中各地址。不包含复制。当拆箱一个struct后,如果使用到这个结构中字段时,才进行复制这个字段。
  11. Unity的引用类型

    • UnityEngine.Object类:所有Unity中的对象都继承自UnityEngine.Object类。所有派生自这个类的公开变量都会被显示在监视器(inspector)窗口中。开发者可以很方便的通过编辑器修改这些值。这个类也提供了静态的创建、查找、销毁方法。
    • UnityEngine.Component类:他是UnityEngine.Object类的子类。同时他也是所有可以添加到游戏对象GameObject上的组件(Component)的基类。基本上他和游戏对象有明确的绑定关系,他提供了获取游戏对象标签、Transform组件、调用游戏对象及其子对象的方法、获得游戏对象及其子对象上其他的组件。常用方法是GetComponect<T>GetComponects<T>BroadcastMessage方法等。获取组件一般第一次调用后缓存目标对象的引用,来提交效率。
    • UnityEngine.Behaviour类:继承自UnityEngine.Component. 这个中间类可以控制开启和禁用引擎的每帧Update回调。
    • UnityEngine.MonoBehaviour类:他继承自UnityEngine.Behaviour。所有的脚本都派生自MonoBehaviour类。每完成一个C#脚本时都要显式继承这个类。而且不能使用new来创建MonoBehaviour类及其子类的对象实例。可以使用gameObject.AddComponent<T>()接口来动态把脚本挂载到指定的游戏对象,从而间接创建实例。这个类提供了协程控制、引擎帧更新等回调、GUI事件回调。引擎回调顺序如下:

      • 当前场景中所有游戏对象的Reset、Awake、OnEnable方法,会在所有的Start、Update等方法之前调用。
      • 第一帧更新前,调用Start, 他在所有对象的Update前调用。Awake(prefab实例化后)、OnEnable、Start完成了一个脚本的初始化。
      • OnApplicationPause方法,检测到暂停状态时,会在当前帧结束后调用本方法 。
      • Update(每帧,比如用来角色移动)、LateUpdate(每帧,比如渲染前移动相机,在Update之后调用)、FixedUpdate(定时器更新,比如给刚体定时加动力)
    • 协程。由于脚本是单线程的。于是引入通过C#语言的迭代器实现的协程。一般在Update返回时执行。

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      //MonoBehaviour挂载到游戏对象身上时类名和文件名需要一致
      public class ParentBehaviourScript : MonoBehaviour
      {
          private IEnumerator WaitAndPrint(float waitTime)
          {
              //System.Console.WriteLine 只输出到Editor.log日志文件
              //System.Console.WriteLine("start WaitAndPrint: {0}", waitTime);
      
              //继承MonoBehaviour可使用print, 日志文件和窗口都有输出
              print(Time.time + ":Call WaitAndPrint");
      
              //如果yield返回WaitForSeconds,根据时间算出挂起帧数
              yield return new WaitForSeconds(waitTime);
              print(Time.time + ":Done WaitAndPrint");
          }
          private IEnumerator TestWWW(string url)
          {
              print(Time.time + ":Call TestWWW");
      
              //如果yield返回的WWW对象,那么在完成加载后再唤醒此协程
              WWW www = new WWW(url);
              yield return www;
      
              print(Time.time + ":Done TestWWW");
          }
          
        // Use this for initialization
        IEnumerator Start ()// 这个的返回值已经变化为IEnumerator,不是默认的void
          {
              //Debug.Log, 日志文件和窗口都有输出,即使不继承MonoBehaviour也可用
              Debug.Log(Time.time + ":Start be called First Time");
      
              //启动一个协程但不挂起自己和不等待他执行完成
              StartCoroutine(TestWWW("https://www.baidu.com"));
      
              //yield返回一个协程,挂起自己,启动协程并等他执行完后唤醒自己
              yield return StartCoroutine(WaitAndPrint(2));
              print(Time.time + ":Done Start");
          }
      
          void ApplyDamage(float damage)
          {
              Debug.Log("ApplyDamage be called:" + damage);
          }
          // Update is called once per frame
          void Update () {
              //通过广播调用自己及所有子对象脚本的ApplyDamage方法
              //BroadcastMessage("ApplyDamage", 5.0f);
          }
      }
    • xx
  12. yy
0

评论 (0)

取消