C# 反射技术应用
1、.NET可执行应用程序结构
程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。
应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。
反射也可用于创建称为类型浏览器的应用程序,使用户能够选择类型,然后查看有关选定类型的信息。
此外,Jscript等语言编译器使用反射来构造符号表。System.Runtime.Serialization命名空间中的类使用反射来访问数据并确定要永久保存的字段,System.Runtime.Remoting命名空间中的类通过序列化来间接地使用反射。
using System;
using System.Reflection;
namespace ReflectionExample
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
System.Console.WriteLine("列出程序集中的所有类型");
Assembly a = Assembly.LoadFrom("ReflectionExample.exe");
Type[] mytypes = a.GetTypes();
foreach(Type t in mytypes)
{
System.Console.WriteLine ( t.Name );
}
System.Console.ReadLine();
System.Console.WriteLine("列出HelloWorld中的所有方法");
Type ht = typeof(HelloWorld);
MethodInfo [] mif = ht.GetMethods ();
foreach(MethodInfo mf in mif)
{
System.Console.WriteLine(mf.Name);
}
System.Console.ReadLine();
System.Console.WriteLine("实例化HelloWorld,并调用SayHello方法");
Object obj = Activator.CreateInstance(ht);
string [] s = {"ZhenLei"};
Object objName = Activator.CreateInstance(ht,s);
//BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
// BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo msayhello = ht.GetMethod("SayHello");
msayhello.Invoke(obj,null);
msayhello.Invoke(objName,null);
System.Console.ReadLine();
}
}
}
using System;
namespace ReflectionExample
{
/// <summary>
/// HelloWorld 的摘要说明。
/// </summary>
public class HelloWorld
{
string myName = null;
public HelloWorld(string name)
{
myName = name;
}
public HelloWorld() : this(null)
{
}
public string Name
{
get
{return myName;}
}
public void SayHello()
{
if (myName==null)
System.Console.WriteLine ("Hello World");
else
System.Console.WriteLine("Hello," + myName);
}
}
}
3、在设计模式实现中使用反射技术
采用反射技术可以简化工厂的实现。
(1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
(2)抽象工厂:使用反射可以减少抽象工厂的子类。
采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。
采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
(1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。
(2)享元模式:采用反射技术实例化享元可以简化享元工厂。
4.
反射的概述
反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息):
System.Reflection.MemberInfo
System.Reflection.EventInfo
System.Reflection.FieldInfo
System.Reflection.MethodBase
System.Reflection.ConstructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Type
System.Reflection.Assembly
反射的层次模型:
注:层次间都是一对多的关系
反射的作用:
1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型
2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
应用要点:
1. 现实应用程序中很少有应用程序需要使用反射类型
2. 使用反射动态绑定需要牺牲性能
3. 有些元数据信息是不能通过反射获取的
4. 某些反射类型是专门为那些clr 开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的。
反射appDomain 的程序集
当你需要反射AppDomain 中包含的所有程序集,示例如下:
static void Main
{
//通过GetAssemblies 调用appDomain的所有程序集
foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())
{
//反射当前程序集的信息
reflector.ReflectOnAssembly(assem)
}
}
说明:调用AppDomain 对象的GetAssemblies 方法 将返回一个由System.Reflection.Assembly元素组成的数组。
反射单个程序集
上面的方法讲的是反射AppDomain的所有程序集,我们可以显示的调用其中的一个程序集,system.reflecton.assembly 类型提供了下面三种方法:
1. Load 方法:极力推荐的一种方法,Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常
2. LoadFrom 方法:传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息,如果在指定路径找不到程序集抛出异常。
3. LoadWithPartialName:永远不要使用这个方法,因为应用程序不能确定再在载入的程序集的版本。该方法的唯一用途是帮助那些在.Net框架的测试环节使用.net 框架提供的某种行为的客户,这个方法将最终被抛弃不用。
注意:system.AppDomain 也提供了一种Load 方法,他和Assembly的静态Load 方法不一样,AppDomain的load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的AppDomain.尽量避免使用AppDomain的load 方法
利用反射获取类型信息
前面讲完了关于程序集的反射,下面在讲一下反射层次模型中的第三个层次,类型反射
一个简单的利用反射获取类型信息的例子:
using system;
using sytem.reflection;
class reflecting
{
static void Main(string[]args)
{
reflecting reflect=new reflecting();//定义一个新的自身类
//调用一个reflecting.exe程序集
assembly myAssembly =assembly.loadfrom(“reflecting.exe”)
reflect.getreflectioninfo(myAssembly);//获取反射信息
}
//定义一个获取反射内容的方法
void getreflectioninfo(assembly myassembly)
{
type[] typearr=myassemby.Gettypes();//获取类型
foreach (type type in typearr)//针对每个类型获取详细信息
{
//获取类型的结构信息
constructorinfo[] myconstructors=type.GetConstructors;
//获取类型的字段信息
fieldinfo[] myfields=type.GetFiedls()
//获取方法信息
MethodInfo myMethodInfo=type.GetMethods();
//获取属性信息
propertyInfo[] myproperties=type.GetProperties
//获取事件信息
EventInfo[] Myevents=type.GetEvents;
}
}
}
其它几种获取type对象的方法:
1. System.type 参数为字符串类型,该字符串必须指定类型的完整名称(包括其命名空间)
2. System.type 提供了两个实例方法:GetNestedType,GetNestedTypes
3. Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes
4. System.Reflection.Moudle 提供了这些实例方法:GetType,GetTypes,FindTypes
设置反射类型的成员
反射类型的成员就是反射层次模型中最下面的一层数据。我们可以通过type对象的GetMembers 方法取得一个类型的成员。如果我们使用的是不带参数的GetMembers,它只返回该类型的公共定义的静态变量和实例成员,我们也可以通过使用带参数的GetMembers通过参数设置来返回指定的类型成员。具体参数参考msdn 中system.reflection.bindingflags 枚举类型的详细说明。
例如:
//设置需要返回的类型的成员内容
bindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public;
foreach (MemberInfo mi int t.getmembers(bf))
{
writeline(mi.membertype) //输出指定的类型成员
}
通过反射创建类型的实例
通过反射可以获取程序集的类型,我们就可以根据获得的程序集类型来创建该类型新的实例,这也是前面提到的在运行时创建对象实现晚绑定的功能
我们可以通过下面的几个方法实现:
1. System.Activator 的CreateInstance方法。该方法返回新对象的引用。具体使用方法参见msnd
2. System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集
3. System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
4. System.type的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。
5. System.reflection.constructinfo 的Invoke实例方法
反射类型的接口
如果你想要获得一个类型继承的所有接口集合,可以调用Type的FindInterfaces GetInterface或者GetInterfaces。所有这些方法只能返回该类型直接继承的接口,他们不会返回从一个接口继承下来的接口。要想返回接口的基础接口必须再次调用上述方法。
反射的性能:
使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:
1. 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2. 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些 。
http://www.cnblogs.com/skyseraph/archive/2012/03/12/2391601.html
public static string getDate(string text)
{
string str = "";
try
{
string[] strArray = text.Split(new char[] { ' ' });
DateTime time = DateTime.Parse(strArray[5] + "-" + strArray[1] + "-" + strArray[2] + " " + strArray[3]);
str = time.Year.ToString() + "-" + time.Month.ToString() + "-" + time.Day.ToString() + " " + time.Hour.ToString() + ":" + time.Minute.ToString() + ":" + time.Second.ToString();
TimeSpan span = (TimeSpan) (DateTime.Now - time);
str = "刚刚";
if (span.Minutes <= 0)
{
return str;
}
str = span.Minutes.ToString() + "分钟前";
if (span.Hours <= 0)
{
return str;
}
str = span.Hours.ToString() + "小时前";
if (span.Days <= 0)
{
return str;
}
str = span.Days.ToString() + "天前";
if (span.Days > 5)
{
str = time.ToString();
}
}
catch
{
}
return str;
}
-------------------------------Unity3d----------------------------------
这是目前我看到的最精简的,仅一个事件完成拖拽.
/*
* 用到了unity3d非常好的协同机制实现这一点,OnMouseDown事件表示鼠标已作了射线判断得到了对象。
* 拖拽时保持z轴不变,因为屏幕是xy二维的,空间是三维的。
* */
IEnumerator OnMouseDown ()
{
var camera = Camera.mainCamera;
if (camera) {
//转换对象到当前屏幕位置
Vector3 screenPosition = camera.WorldToScreenPoint (transform.position);
//鼠标屏幕坐标
Vector3 mScreenPosition=new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPosition.z);
//获得鼠标和对象之间的偏移量,拖拽时相机应该保持不动
Vector3 offset = transform.position - camera.ScreenToWorldPoint( mScreenPosition);
print ("drag starting:"+transform.name);
//若鼠标左键一直按着则循环继续
while (Input.GetMouseButton (0)) {
//鼠标屏幕上新位置
mScreenPosition = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPosition.z);
// 对象新坐标
transform.position=offset + camera.ScreenToWorldPoint (mScreenPosition);
//协同,等待下一帧继续
yield return new WaitForFixedUpdate ();
}
print ("drag compeleted");
}
}
---------------------------分割线
下面是unity自带的,在Scripts资源包里有拖拽代码,这个拖拽物体必须附加Rigidbody刚体组件。
DragRigidbody.js
var spring = 50.0;
var damper = 5.0;
var drag = 10.0;
var angularDrag = 5.0;
var distance = 0.2;
var attachToCenterOfMass = false;
private var springJoint : SpringJoint;
function Update ()
{
// Make sure the user pressed the mouse down
if (!Input.GetMouseButtonDown (0))
return;
var mainCamera = FindCamera();
// We need to actually hit an object
var hit : RaycastHit;
if (!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), hit, 100))
return;
// We need to hit a rigidbody that is not kinematic
if (!hit.rigidbody || hit.rigidbody.isKinematic)
return;
if (!springJoint)
{
var go = new GameObject("Rigidbody dragger");
var body : Rigidbody = go.AddComponent ("Rigidbody") as Rigidbody;
springJoint = go.AddComponent ("SpringJoint");
body.isKinematic = true;
}
springJoint.transform.position = hit.point;
if (attachToCenterOfMass)
{
var anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
anchor = springJoint.transform.InverseTransformPoint(anchor);
springJoint.anchor = anchor;
}
else
{
springJoint.anchor = Vector3.zero;
}
springJoint.spring = spring;
springJoint.damper = damper;
springJoint.maxDistance = distance;
springJoint.connectedBody = hit.rigidbody;
StartCoroutine ("DragObject", hit.distance);
}
function DragObject (distance : float)
{
var oldDrag = springJoint.connectedBody.drag;
var oldAngularDrag = springJoint.connectedBody.angularDrag;
springJoint.connectedBody.drag = drag;
springJoint.connectedBody.angularDrag = angularDrag;
var mainCamera = FindCamera();
while (Input.GetMouseButton (0))
{
var ray = mainCamera.ScreenPointToRay (Input.mousePosition);
springJoint.transform.position = ray.GetPoint(distance);
yield;
}
if (springJoint.connectedBody)
{
springJoint.connectedBody.drag = oldDrag;
springJoint.connectedBody.angularDrag = oldAngularDrag;
springJoint.connectedBody = null;
}
}
function FindCamera ()
{
if (camera)
return camera;
else
return Camera.main;
}
括号内是译者自己对文章和技术的理解)
(Unity3D是现在越来越流行的3D游戏引擎,它支持JavaScript,c#和Boo语言。如果你是个Unity3D的爱好者,但只会JavaScript。这里有一篇文章关于处理事件和消息传递,也许更适合你。A Useful Messaging System)
你知道C#有一个内置的事件机制吗?这个东东在Unity3D里也非常好用。下面举一个例子。
为了响应一个GameObject的事件分发,你通常要建立一个脚本继承MonoBehaviour并且实现你需要的方法。比如你想对鼠标悬停作出反应,就要创建OnMouseOver方法。通常代码会像这个样子:
C#代码
1.void OnMouseOver () {
2. renderer.material.color = Color.red;
3.}
这样工作没问题。但如果你想通知另外一个对象响应这个事件(OnMouseOver事件)怎么办?
第一种方式是保持另外对象的脚本引用,然后在你的OnMouseOver方法中调用它:
C#代码
1.public MyScript myScript;
2.void OnMouseOver () {
3. myScript.NotifyMouseOver();
4.}
这样做没问题,但是不够好。因为你需要一直保持另外一个对象的引用,如果想通知多个对象要保持多个引用。代码会变得很乱。
Messages 消息
另一个办法是用SendMessage或SendMessageUpwards方法。看上去这是解决问题的最好办法,但是这些方法存在严重的缺陷,以我的观点,你应该尽量不去使用它们。
这些方法的语法并不灵活,你需要传递一个方法名字的字符串,这样做很容易出错。另外这些方法只能用在同一个对象的附属关系中。换句话说你只能在下面几种情况中调用SendMessage或SendMessageUpwards方法,这些方法的脚本被关联到同一个GameObject中,或者被关联到这个GameObject的祖先关系对象中。
Events 事件
幸运的是有一个更好的解决办法,这就是C#内置的事件机制。我不在这里过多的描述机制是如何工作的,你如果有兴趣可以学习相关的知识,访问MSDN手册。(译者推荐另外一篇文章,C# 中的委托和事件)
现在让我们看看如何在Unity3D中使用事件机制。
C#代码
1.using UnityEngine;
2.public class EventDispatcher : MonoBehaviour {
3. public delegate void EventHandler(GameObject e);
4. public event EventHandler MouseOver;
5. void OnMouseOver () {
6. if (MouseOver != null)
7. MouseOver (this.gameObject);
8. }
9.}
如果你不知道这段代码到底干什么,先不要着急。重要的是一旦你把这段代码关联到一个GameObject,只要在整个项目的任何一个脚本中保持这个对象,你就可以像下面这样处理事件:
C#代码
1.private GameObject s;
2.[...]
3.s.GetComponent<EventDispatcher>().MouseOver += Listener;
4.[...]
5.void Listener(GameObject g) {
6. // g is being hovered, do something...
7.}
这种方式比用消息更灵活,因为它可以被用在任何一个脚本中,而不仅仅在同一个对象附属关系中。如果在整个应用中保持一个单例模式的对象,你就可以监听任何从这个对象分发出来的事件。
另外一个重要特点,同一个监听方法可以响应不同对象的事件。通过传递事件源对象的引用作为参数,你总会知道哪个对象分发了事件,就像我的代码展示的那样。(对于这句话可以这样理解,假如游戏中扔一颗导弹炸死了一个小兵并导致坦克减血,小兵死亡和坦克减血这两个事件都触发了同一个监听方法-玩家得分,通过传递进来的事件源对象,就能知道小兵还是坦克触发了玩家得分这个监听方法。)
References, controllers and MVC
现在让我们比较一下第一和第三种方式。在最开始的例子中(第一种方式保持另外对象的脚本引用),你需要在事件分发代码中保持监听者的对象引用,我说了这不是一个好主意。在用内置事件机制,改进的版本中(第三种方式),你需要在监听者代码中保持事件分发者的引用。你也许会问,为什么后者更好?
首先,分发者不需要知道自己事件的监听者是谁,不需要知道有多少监听者。它只负责事件的发送。在最开始的例子中(第一种方式),如果要告诉分发者停止通知监听者,你能想象这种程序判断有多么笨重吗?
事件机制中,是由监听者自己决定监听什么事件,什么时候开始监听,什么时候停止监听。像这样的对象通常用于管理程序的状态或者执行某些游戏逻辑。这个就叫做控制器,借用MVC设计模式的概念。这样我们的代码会更清晰,不易出错。(译者认为观察者设计模式更符合)
最后一点,我喜欢重载“+=”操作符去添加监听方法。现在你也许能够猜到,如果想结束监听某个事件,可以这么写:
C#代码
1.s.GetComponent<EventDispatcher>().MouseOver -= Listener;
当然你可以创建一个通用的EventDispatcher类,实现所有GameObject能够分发的事件。可以参看下面的代码。另外在实现OnGUI事件时要特别小心,如果想知道为什么,读读这篇文章。
C#代码
1.using UnityEngine;
2.using System.Collections;
3.
4./**
5. * A simple event dispatcher - allows to listen to events in one GameObject from another GameObject
6. *
7. * Author: Bartek Drozdz (bartek [at] everyday3d [dot] com)
8. *
9. * Usage:
10. * Add this script to the object that is supposed to dispatch events.
11. * In another objects follow this pattern to register as listener at intercept events:
12.
13. void Start () {
14. EventDispatcher ev = GameObject.Find("someObject").GetComponent<EventDispatcher>();
15. ev.MouseDown += ListeningFunction; // Register the listener (and experience the beauty of overloaded operators!)
16. }
17.
18. void ListeningFunction (GameObject e) {
19. e.transform.Rotate(20, 0, 0); // 'e' is the game object that dispatched the event
20. e.GetComponent<EventDispatcher>().MouseDown -= ListeningFunction; // Remove the listener
21. }
22.
23. * This class does not implement all standards events, nor does it allow dispatching custom events,
24. * but you shold have no problem adding all the other methods.
25. */
26.public class EventDispatcher : MonoBehaviour
27.{
28.
29. public delegate void EventHandler (GameObject e);
30. public delegate void CollisionHandler (GameObject e, Collision c);
31.
32. public event EventHandler MouseOver;
33. void OnMouseOver ()
34. {
35. if (MouseOver != null)
36. MouseOver (this.gameObject);
37. }
38.
39. public event EventHandler MouseDown;
40. void OnMouseDown ()
41. {
42. if (MouseDown != null)
43. MouseDown (this.gameObject);
44. }
45.
46. public event EventHandler MouseEnter;
47. void OnMouseEnter ()
48. {
49. if (MouseEnter != null)
50. MouseEnter (this.gameObject);
51. }
52.
53.
54. public event EventHandler MouseExit;
55. void OnMouseExit ()
56. {
57. if (MouseExit != null)
58. MouseExit (this.gameObject);
59. }
60.
61. public event EventHandler BecameVisible;
62. void OnBecameVisible ()
63. {
64. if (BecameVisible != null)
65. BecameVisible (this.gameObject);
66. }
67.
68. public event EventHandler BecameInvisible;
69. void OnBecameInvisible ()
70. {
71. if (BecameInvisible != null)
72. BecameInvisible (this.gameObject);
73. }
74.
75. public event CollisionHandler CollisionEnter;
76. void OnCollisionEnter (Collision c)
77. {
78. if (CollisionEnter != null)
79. CollisionEnter (this.gameObject, c);
80. }
81.
82. public event CollisionHandler CollisionExit;
83. void OnCollisionExit (Collision c)
84. {
85. if (CollisionExit != null)
86. CollisionExit (this.gameObject, c);
87. }
88.
89.}
Unity3d之MonoBehaviour的可重写函数整理
最近在学习Unity3d的知识.虽然有很多资料都有记录了,可是我为了以后自己复习的时候方便就记录下来吧!下面的这些函数在Unity3d程序开发中具有很重要的作用.
Update
当MonoBehaviour启用时,其Update在每一帧被调用。
LateUpdate
当Behaviour启用时,其LateUpdate在每一帧被调用。
FixedUpdate
当MonoBehaviour启用时,其 FixedUpdate 在每一帧被调用。
Awake
当一个脚本实例被载入时Awake被调用。
Start
Start仅在Update函数第一次被调用前调用。
Reset
重置为默认值。
OnMouseEnter
当鼠标进入到GUIElement(GUI元素)或Collider(碰撞体)中时调用OnMouseEnter。
OnMouseOver
当鼠标悬浮在GUIElement(GUI元素)或Collider(碰撞体)上时调用 OnMouseOver .
OnMouseExit
当鼠标移出GUIElement(GUI元素)或Collider(碰撞体)上时调用OnMouseExit。
OnMouseDown
当鼠标在GUIElement(GUI元素)或Collider(碰撞体)上点击时调用OnMouseDown。
OnMouseUp
当用户释放鼠标按钮时调用OnMouseUp。
OnMouseUpAsButton
OnMouseUpAsButton只有当鼠标在同一个GUIElement或Collider按下,在释放时调用。
OnMouseDrag
当用户鼠标拖拽GUIElement(GUI元素)或Collider(碰撞体)时调用 OnMouseDrag 。
OnTriggerEnter
当Collider(碰撞体)进入trigger(触发器)时调用OnTriggerEnter。
OnTriggerExit
当Collider(碰撞体)停止触发trigger(触发器)时调用OnTriggerExit。
OnTriggerStay
当碰撞体接触触发器时,OnTriggerStay将在每一帧被调用。
OnCollisionEnter
当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionEnter将被调用。
OnCollisionExit
当此collider/rigidbody停止触发另一个rigidbody/collider时,OnCollisionExit将被调用。
OnCollisionStay
当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionStay将会在每一帧被调用。
OnControllerColliderHit
在移动的时,当controller碰撞到collider时OnControllerColliderHit被调用。
OnJointBreak
当附在同一对象上的关节被断开时调用。
OnParticleCollision
当粒子碰到collider时被调用。
OnBecameVisible
当renderer(渲染器)在任何相机上可见时调用OnBecameVisible。
OnBecameInvisible
当renderer(渲染器)在任何相机上都不可见时调用OnBecameInvisible。
OnLevelWasLoaded
当一个新关卡被载入时此函数被调用。
OnEnable
当对象变为可用或激活状态时此函数被调用。
OnDisable
当对象变为不可用或非激活状态时此函数被调用。
OnDestroy
当MonoBehaviour将被销毁时,这个函数被调用。
OnPreCull
在相机消隐场景之前被调用。
OnPreRender
在相机渲染场景之前被调用。
OnPostRender
在相机完成场景渲染之后被调用。
OnRenderObject
在相机场景渲染完成后被调用。
OnWillRenderObject
如果对象可见每个相机都会调用它。
OnGUI
渲染和处理GUI事件时调用。
OnRenderImage
当完成所有渲染图片后被调用,用来渲染图片后期效果。
OnDrawGizmosSelected
如果你想在物体被选中时绘制gizmos,执行这个函数。
OnDrawGizmos
如果你想绘制可被点选的gizmos,执行这个函数。
OnApplicationPause
当玩家暂停时发送到所有的游戏物体。
OnApplicationFocus
当玩家获得或失去焦点时发送给所有游戏物体。
OnApplicationQuit
在应用退出之前发送给所有的游戏物体。
OnPlayerConnected
当一个新玩家成功连接时在服务器上被调用。
OnServerInitialized
当Network.InitializeServer被调用并完成时,在服务器上调用这个函数。
OnConnectedToServer
当你成功连接到服务器时,在客户端调用。
OnPlayerDisconnected
当一个玩家从服务器上断开时在服务器端调用。
OnDisconnectedFromServer
当失去连接或从服务器端断开时在客户端调用。
OnFailedToConnect
当一个连接因为某些原因失败时在客户端调用。
OnFailedToConnectToMasterServer
当报告事件来自主服务器时在客户端或服务器端调用。
OnMasterServerEvent
当报告事件来自主服务器时在客户端或服务器端调用。
OnNetworkInstantiate
当一个物体使用Network.Instantiate进行网络初始化时调用。
OnSerializeNetworkView
在一个网络视图脚本中,用于自定义变量同步。