Unity脚本设计基础(持续补充中...)

一、常用组件和函数

1:MonoBehaviour的父类

当我们从Unity中打开C#脚本时,可以看到这一行

public class Demo2 : MonoBehaviour

意味着我们在Unity中所有的对象都是继承自MonoBehaviour的

选中MonoBehaviour后点击F12,可以看到

public class MonoBehaviour : Behaviour

MonoBehaviour是继承自Behaviour的,继续点击F12

public class Behaviour : Component

Behaviour是继承自Component的,对Component进行查找,可以看到

public class Component : Object

它其实是继承自Object类的,而继续追踪下去我们可以看到

public class Object
    {
        public Object();

        //
        // 摘要:
        //     Should the object be hidden, saved with the Scene or modifiable by the user?
        public HideFlags hideFlags { get; set; }
        //
        // 摘要:
        //     The name of the object.
        public string name { get; set; }

        //
        // 摘要:
        //     Removes a GameObject, component or asset.
        //
        // 参数:
        //   obj:
        //     The object to destroy.
        //
        //   t:
        //     The optional amount of time to delay before destroying the object.
        [NativeMethodAttribute(Name = "Scripting::DestroyObjectFromScripting", IsFreeFunction = true, ThrowsException = true)]
        public static void Destroy(Object obj, [DefaultValue("0.0F")] float t);

最起始我们其实是创建了Object类的,然后是一层一层的继承关系

2:GameObject对象

我们可以在Component中找到GameObject,而GameObject其实是来自与Object

public sealed class GameObject : Object

通常情况下,GameObject表示场景中的基本单元或者实体,比如声音,碰撞器,管理类都是,可见的状态包括网格,动画网格,精灵对象等,而每个GameObject至少包含一个组件且不可移除,就是Transform组件,transform和gameObject之间

public class Transform : Component, IEnumerable

可以相互引用嵌套。

因此GameObject由组件构成,而在较高层面上,场景则由单一场景内的GameObject的集合构成

涉及GameObject的方法如下、

public GameObject();
public GameObject(string name);
public GameObject(string name, params Type[] components);
public static GameObject CreatePrimitive(PrimitiveType type);
public static GameObject Find(string name);
public static GameObject[] FindGameObjectsWithTag(string tag);
public static GameObject FindGameObjectWithTag(string tag);
public static GameObject FindWithTag(string tag);

gameObject(当前组件所在得游戏物体)中的常用属性和方法

属性:

Name:游戏物体名称,和层级面板中等同

Tag:游戏物体得标签

activeInHierarchy:显示状态

Transform:这个游戏物体的变换组件

方法:

1):GetComponent<T>():获取游戏物体身上的组件,T代表要查找的类型,类型的方法有很多

2):SetActive(bool):修改显示状态

3):Static GameObject Find(string path):一个静态方法,查找游戏物体

部分代码段

public class L2_6Demo : MonoBehaviour
{
    //transform和gameObject之间可以相互引用嵌套
    private GameObject gO;   //改为private,外部就无法看到了
    public Transform tS;
    void Start()
    {
        获取当前组件所在得游戏物体
        print(gameObject);  
        print(gO);   
        print(gameObject.transform.position); 
        print(gO.transform.position);  //因为gO已经定义为GameObject类型,所以也可以直接引用transform

        print(tS);
        print(tS.position);
        print(tS.gameObject); 
        
        Transform tempTransform = gameObject.GetComponent<Transform>();   
        GameObject gO = gameObject.GetComponent<GameObject>();   
        //    <>里面要填写你要获取的物体类型,此处填什么就返回什么类型
        //比如上面一个是Transform类型的,后面写了,前面返回类型就是Transform
        
        //下面写了Gameobject类型的,前面回来也就必须是Gameobject
        print(tempTransform.position);
        print(gO.name);  //后面报错了,因为Gameobject严格的来说不算组件
        //所以正常情况下,我们都是用Transform来进行泛型返回值的规定
        
        BoxCollider boxCollider = gameObject.GetComponent<BoxCollider>();
        print(boxCollider.isTrigger);

        gameObject.SetActive(false);   //设置显示,false是隐藏我们的物体
    }

3:Transform组件

对Transform进行父类查询可以看到

public class Transform : Component, IEnumerable

Transform中的方法非常多,我们将每一条都列出来

public Vector3 localPosition { get; set; }
public Vector3 eulerAngles { get; set; }
public Vector3 localEulerAngles { get; set; }
public Vector3 right { get; set; }
public Vector3 up { get; set; }
public Vector3 forward { get; set; }
public Quaternion rotation { get; set; }
public Vector3 position { get; set; }
public Quaternion localRotation { get; set; }
public Transform parent { get; set; }
public Matrix4x4 worldToLocalMatrix { get; }
public Matrix4x4 localToWorldMatrix { get; }
public Transform root { get; }
public int childCount { get; }
public Vector3 lossyScale { get; }
public bool hasChanged { get; set; }
public Vector3 localScale { get; set; }
public int hierarchyCapacity { get; set; }
public int hierarchyCount { get; }
public void DetachChildren();
public Transform Find(string n);
public Transform FindChild(string n);
public Transform GetChild(int index);
public int GetChildCount();
public IEnumerator GetEnumerator();
public int GetSiblingIndex();
public Vector3 InverseTransformDirection(Vector3 direction);
public Vector3 InverseTransformDirection(float x, float y, float z);
public Vector3 InverseTransformPoint(float x, float y, float z);
public Vector3 InverseTransformPoint(Vector3 position);
public Vector3 InverseTransformVector(Vector3 vector);
public Vector3 InverseTransformVector(float x, float y, float z);
public bool IsChildOf([NotNullAttribute("ArgumentNullException")] Transform parent);
public void LookAt(Transform target, [DefaultValue("Vector3.up")] Vector3 worldUp);
public void LookAt(Vector3 worldPosition, [DefaultValue("Vector3.up")] Vector3 worldUp);
public void LookAt(Vector3 worldPosition);
public void LookAt(Transform target);
public void Rotate(float xAngle, float yAngle, float zAngle);
public void Rotate(Vector3 eulers, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 eulers);
public void Rotate(float xAngle, float yAngle, float zAngle, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 axis, float angle, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 axis, float angle);
public void RotateAround(Vector3 point, Vector3 axis, float angle);
public void RotateAround(Vector3 axis, float angle);
public void RotateAroundLocal(Vector3 axis, float angle);
public void SetAsFirstSibling();
public void SetAsLastSibling();
public void SetParent(Transform p);
public void SetParent(Transform parent, bool worldPositionStays);
public void SetPositionAndRotation(Vector3 position, Quaternion rotation);
public void SetSiblingIndex(int index);
public Vector3 TransformDirection(float x, float y, float z);
public Vector3 TransformDirection(Vector3 direction);
public Vector3 TransformPoint(float x, float y, float z);
public Vector3 TransformPoint(Vector3 position);
public Vector3 TransformVector(float x, float y, float z);
public Vector3 TransformVector(Vector3 vector);
public void Translate(float x, float y, float z);
public void Translate(float x, float y, float z, [DefaultValue("Space.Self")] Space relativeTo);
public void Translate(Vector3 translation);
public void Translate(Vector3 translation, [DefaultValue("Space.Self")] Space relativeTo);
public void Translate(float x, float y, float z, Transform relativeTo);
public void Translate(Vector3 translation, Transform relativeTo);


常用的属性如下:

childCount:子物体的数量

Parent:父物体的Transform组件

Root:最高级别父物体

print(transform.childCount);   
        print(transform.parent);
        print(transform.root);
        print(transform.eulerAngles);            //这里挂载到update上,实时旋转信息会更新
        
        print("当前坐标"+transform.position);    //print和Debug.Log是等价的,实时获取位置信息
        print("当前旋转"+transform.rotation);    //这里改变旋转角度并不会实时显示
        print("当前缩放"+transform.localScale);
        transform.position = new Vector3(num,0,0);       //vector3中已经定义过了X,Y,Z,因此只需要在此处输入坐标即可
        num+=0.01f;

常用的方法如下:

Find(string):查找子物体

Translate(Vetor3):朝着一个坐标移动

Rotate(Vetor3):旋转一个角度

LookAt(Transform):看向目标

print(transform.Find("C"));                       //查找子物体
transform.Translate(new Vector3(0.01f , 0, 0));   //游戏物体会依据给定方向进行位移,输入-0,01f则是向反方向位移
transform.Rotate(new Vector3(3,0,0));     //vector3中的类型可以填int和float
transform.LookAt(transform.parent);         //原本朝向前方的立方体,会立即看向球的方向

4:GetComponent类函数

如果用户需要直接访问某一对象上的特定单一组件,且已知数据类型,则可以通过使用GetComponent函数进行引用,一旦引用,则可像常规对象一样访问该组件。该函数可以访问与GameObject绑定的组件

public class L3_2Demo : MonoBehaviour
{
    private SpriteRenderer spriteRenderer;

    void Start()
    {
        spriteRenderer=gameObject.GetComponent<SpriteRenderer>(); 
        spriteRenderer.sprite =null;    //将sprite组件清空
        spriteRenderer.color= Color.black;//通过C#来改变颜色组件
    }

首先指定SpiteRenderer类型为Private,名称为spiteRenderer

其次在Start函数中进行派生类型转换。

这样的规定下,我们可以直接使用spiriteRenderer来访问和设置GameObject的一系列组件

我们可以从Component获取这些组件,这是和从Unity中添加列表对应的,当然了,Unity中的组件远不止这些。

public Component rigidbody2D { get; }
public Component camera { get; }
public Component light { get; }
public Component animation { get; }
public Component constantForce { get; }
public Component renderer { get; }
public Component audio { get; }
public Component networkView { get; }
public Component collider { get; }
public Component collider2D { get; }
public Component rigidbody { get; }
public Component hingeJoint { get; }

Component族函数

public Component AddComponent(string className);
public Component AddComponent(Type componentType);
public T AddComponent<T>() where T : Component;
public Component GetComponent(string type);
public T GetComponent<T>();
public Component GetComponent(Type type);
public T GetComponentInChildren<T>();
public T GetComponentInChildren<T>([Internal.DefaultValue("false")] bool includeInactive);
public Component GetComponentInChildren(Type type);
public Component GetComponentInParent(Type type, bool includeInactive);
public Component GetComponentInParent(Type type);
public T GetComponentInParent<T>();
public T GetComponentInParent<T>([Internal.DefaultValue("false")] bool includeInactive);
public void GetComponents<T>(List<T> results);
public Component[] GetComponents(Type type);
public T[] GetComponents<T>();
public void GetComponents(Type type, List<Component> results);
public void GetComponentsInChildren<T>(List<T> results);
public T[] GetComponentsInChildren<T>();
public void GetComponentsInChildren<T>(bool includeInactive, List<T> results);
public T[] GetComponentsInChildren<T>(bool includeInactive);
public Component[] GetComponentsInChildren(Type type, [Internal.DefaultValue("false")] bool includeInactive);
public Component[] GetComponentsInChildren(Type type);
public T[] GetComponentsInParent<T>();
public void GetComponentsInParent<T>(bool includeInactive, List<T> results);
public T[] GetComponentsInParent<T>(bool includeInactive);
public Component[] GetComponentsInParent(Type type, [Internal.DefaultValue("false")] bool includeInactive);
public Component[] GetComponentsInParent(Type type);
public bool TryGetComponent(Type type, out Component component);
public bool TryGetComponent<T>(out T component);

所有的方法都可以在具体的操作中使用,但是制作游戏内容时,不会用到太多的方法,只需要掌握常用的一些方法,其他的需要时再学习

5:生命周期函数

常用的生命周期函数如下

Awake():唤醒事件,一开始就执行,只执行一次

OnEnable():启用事件,每次启用都执行一次,当脚本组件被启用的时候执行一次。

Start():开始事件,执行一次。

FixedUpdate():固定更新事件,执行N次,0.02s执行一次。所有物理相关的更新都在这个事件上处理。

Update():更新事件,执行N次,每帧执行一次。

LateUpdate():执行后更新事件,执行N次,在update()和fixedupdate()事件执行完毕后再执行,可以确保当前帧的各个对象,update和fixedUpdate已被调用完成,因此它常常被用于更新相机运动,特别是第三人称相机,以使相机可于当前帧的最新位置尾随对象

OnDisable():禁用事件,每次禁用都执行一次。在OnDestroy()事件也会执行。

OnDestroy():销毁事件,执行一次,当组件被销毁时执行。

代码段

    private void Awake() 
    {
        print("Awake");//只执行一次
    }
    private  void OnEnable() 
    {
        print("Enable");   //每次重新激活cube的时候都会重新使用函数
    }
    private void OnDisable() 
    {
        print("OnDisable");  //每次禁用cube的时候都会执行一次
    }
    void Start()
    {
        print("Start");     //只执行一次
    }

    void Update()
    {
        print("Update"); //每帧执行一次
        //渲染上一帧的事件
    }
    private void LateUpdate() 
    {
        print("LateUpdate");
    }

    private void FixedUpdate()
    {
        print("FixedUpdate");
    }
    private void OnDestroy() 
    {
        print("Ondestroy");    //当cube被销毁的时候会触发,同时ondisable也会执行
    }

Invoke函数的调用和执行

Invoke(string methodName , float time );输入一个方法名称,过几秒执行一次

invokeRepeating(string methodName , float time ,float repeatRate):重复调用

Calcel Invoke(string methodName):取消调用,使用无参重载就是取消全部

代码段

    void Start()
    {
        Invoke("Demo",3);        //延迟3S后启动Demo函数
        
        InvokeRepeating("Demo",2,1);  //延迟2S后执行,每次间隔一秒执行一次
        
    }

    private void CancelDemo () 
    {
        CancelInvoke("Demo");   //单独书写一个方法,再和invoke结合
    }
    
    public void Demo()
    {
        print("Demo");
    }

6:协程函数

为什么需要协程?
主程序已经在执行某个任务,希望同时运行其他逻辑,而不是多线程的同时

协程函数的定义

Public IEnumerator Demo()             //协程特定返回值
{
   Debug.Log(“做一些事情”);            
   Yield return new WaitForSeconds(1.0f);         //等待一秒钟
   Debug.Log(“做一些事情”);          //协程不会因为前面返回而不执行后面的代码
}

协程函数的使用

Coroutine StartCoroutine(Demo(“这是参数”))

执行一个协程,参数直接调用协程方法即可,可以用一个变量接受返回值用于后续停止该协程

我们在生命周期函数中调用协程,但是协程的运行顺序和主程序无关,可以理解为开了一个分支专门运行这个协程,如果我们打开了多个协程,这些协程之间也无关。

 协程函数的停止

协程如果运行到最后一行,意味着停止,但是如果我们想主动停止

StopAllCoroutines():结束全部协程

StopCoroutine:结束某个协程

        StopCoroutine(IEnumerator routine):和协程一样使用,但是如果协程有参数就不能使用

        StopCoroutine(Coroutine routine);参数填写协程变量

        StopCoroutine(string methodName):参数填写协程方法的名

代码段

 void Start()
    {
  
        //Coroutine cor =StartCoroutine(Demo(10));  //通过构建此类cor,来停止
        //StopCoroutine(cor);
        
        //StartCoroutine(Demo(10));  //第二种写法,好一点,可以传输参数
        StartCoroutine("Demo2");
        StartCoroutine("Demo3");
        StartCoroutine("Demo4");
    }
  
    //常规函数
    public int GetNum()  //用来接收Demo返回值的
    {
        return 0;
    } 
    
    //协程函数
    public IEnumerator Demo(int num)
    {
        print("先执行的");
        yield return new WaitForSeconds(3.0f);  //等待一秒执行
        print("等待一秒执行的");
        yield return null;                      //下一帧继续执行
        print("最后执行的");
    }

    //协程可以做动画
    public IEnumerator Demo2()
    {
        while (true)
        {
            //暂停0.1秒
            yield return new WaitForSeconds(0.1f);        //等待0.1秒执行旋转
            transform.Rotate(new Vector3(5,0,0));    //使用transform的旋转工具,每0.1秒转5°
        } 
        
    }

      public IEnumerator Demo3()
    {
        transform.position = new Vector3(10,10,10);
        yield return Demo2();                       //使用类型可以返回另一个协程,此时执行完成坐标后直接返回到Demo2
    }

     public IEnumerator Demo4()
    {
      //5s之后取消协程
      yield return new WaitForSeconds(5);
      
      StopAllCoroutines();  //取消全部
    }
}

7:常用时间工具函数和数学工具函数

时间工具函数:

Time.time:表示从游戏运行到现在的时间,会随着游戏的暂停而停止计算

Time.deltaTime:表示从上一帧到当前帧的时间,以秒为单位

Time.realtimeSinceStartup:表示从游戏开始后的总时间,即使暂停也会增加,也就是现实时间

Time.timeScale:时间缩放,默认值为1,如果设置<1,表示时间减慢,如果>1表示时间加快,0表示游戏暂停。

        Time.timeScale = 0;  //游戏时间一直为0,而真实的时间会一直继续
        Time.timeScale =3;     //时间加快
private void Update() 
    {
        //时间工具类

        //每帧上升0.01m
        transform.Translate(new Vector3(0,0.01f,0));
        
        //每秒上升0.01m,方向×速度×一帧花费的时间,用来解除不同帧率电脑的反应时间问题
        transform.Translate(new Vector3(0,0.01f,0)*1* Time.deltaTime); 

        print("游戏时间"+Time.time);
        print("帧时间"+Time.deltaTime);
        print("真实时间"+Time.realtimeSinceStartup);

        print(Time.time);   //游戏运行时间
        print(Time.deltaTime);  //从上一帧到当前帧的时间
    }

数学工具类函数:

Mathf.Abs(int num):返回绝对值

Mathf.Max(int a,int ,b):返回更大的值

Mathf.Min(int a,int ,b):返回更小的值

Mathf.Round(2.5f):返回四舍五入后得到的值

Mathf.Ceil(2.5f):返回向上取整的值

Mathf.Floor(2.5f):返回向下取整的值

Random.Range(0,5):返回随机值

  (1)如果是int重载:返回0-4的随机值,包含0,不包含5

  (2)如果是float重载,返回0-5的随机值,包含0且包含5

        int num1 =Mathf.Abs(-6);//绝对值
        int num2 =Mathf.Max(1,2,3);//最大值
        int num3 =Mathf.Min(1,2,3);//最小值
        float num4 =Mathf.Round(2.5f);//四舍五入
        float num5 =Mathf.Ceil(2.4f);//向上取整
        float num6 =Mathf.Floor(2.4f);//向下取整

        int num =Random.Range(0,5);   //会返回0-4,包含左边,不包含右边
        print(num);

        float num1=Random.Range(0,5.0f);  //两边都会返回
        print(num1);

二、单例模式和静态模式

1:单例模式

某些类的实例化方式和其他类有所不同,大多数的类针对属性集和行为定义了模板,并可在场景中多次实例化为GameObject,而有些类则必须作为单一实体存在,比如GameManager、HighScoreManager、AudioManager、SaveGameManager,它们任何时候都只能包含一个类的实例,不然会混淆对象含义,此类对象就称作单例对象

使用GameManger来举例,实际GameManger负责游戏中的全部高层功能项,比如游戏是否处于暂停状态,是否满足胜利条件等

单例的创建和使用过程如下:

using UnityEngine;
usaing System.Collections;

public class GameManager:MonoBehaviour

{
  public static GameManager Instance   //创建单例
  {
    get
       {
         return instance; 
       }

  }
  public int HighScore=0;
  public bool IsPaused=false;
  public bool InputAllowed=true;

}
void Awake()
{
  if(instance)
    {
      DestroyImmediate(gameObject)
      return;     //对实例变量进行检测,可确定内存中是否存在现有的实例,如果存在,则删除,保证其唯一性
    }  
    instance= this;   /让此单例激活并唯一
    DontDestroyOnLoad(gameObject); //让此类对象在场景中持久存在
}

*GameManager类使用了Awake()而非Start(),Start是首帧调用,而Awake是对象创建时开始调用,如果GameObjectD启动了禁用状态下的场景,则Start函数不会被调用,直到该对象处于活动状态,对于默认条件下处于活动状态下的对象,Start函数在场景开始时被调用,且位于Awake之后

GameManager的全局静态Instance属性的最大优势在于它可以直接访问任何脚本文件,且无需使用到任何局部变量或对象引用

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Laker404

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值