一、常用组件和函数
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属性的最大优势在于它可以直接访问任何脚本文件,且无需使用到任何局部变量或对象引用