Unity3D脚本编程--基本概念

               

1. 简介

    在Unity3D中,游戏对象(GameObject)的行为是由附加其上的脚本来控制的,游戏开发者通过编写脚本来控制游戏中的所有对象,如移动Camera等。GameObject可以被附加不同类型的组件,但每种类型的组件只能有一个或没有。脚本本质上也是一种组件。

     在Unity3D中默认的脚本代码如下所示:    

<span style="font-family:Arial;"><span style="font-family:Arial;">// ***** C# script *****using UnityEngine;using System.Collections;public class ffc : MonoBehaviour// Use this for initialization void Start () {  } / Update is called once per frame void Update () { }}//***** Java script *****#pragma strictfunction Start () {}function Update () {}</span></span>

    由此可见,脚本代码与大家熟悉的Java代码类似,即都是由以下两部分组成:

    • 变量

    • 函数

   • 其它代码:在任何函数之外的代码在物体被加载的时候运行。这个可以用来初始化脚本状态。

  MonoBehaviour是所有脚本的基类,每个Javascript脚本自动继承MonoBehaviour,使用C#或Boo时,需要显式继承MonoBehaviour.       

1.1 脚本成员变量

      脚本变量就是指类的成员变量(即在JavaScript或C#或Boo中定义的成员变量,而不是基类MonoBehaviour中定义的变量),在Unity3D中将成员变量设为公有的时候,当把它附加到游戏对象后,可以在游戏对象的监视面板中的脚本组件那栏里面看到该“公有变量”,即可以在编辑器中直接对该公有变量进行赋值,同时在Debug状态下也可以在面板中看到它的值。

1.2 基类可被继承的成员变量(内置变量)

           变量名                                                                      描述                                                                               
transform The Transform attached to this GameObject (null if there is none attached).
rigidbody The Rigidbody attached to this GameObject (null if there is none attached).
camera The Camera attached to this GameObject (null if there is none attached).
light The Light attached to this GameObject (null if there is none attached).
animation The Animation attached to this GameObject (null if there is none attached).
constantForce The ConstantForce attached to this GameObject (null if there is none attached).
renderer The Renderer attached to this GameObject (null if there is none attached).
audio The AudioSource attached to this GameObject (null if there is none attached).
guiText The GUIText attached to this GameObject (null if there is none attached).
networkView The NetworkView attached to this GameObject (Read Only). (null if there is none attached)
guiTexture The GUITexture attached to this GameObject (Read Only). (null if there is none attached)
collider The Collider attached to this GameObject (null if there is none attached).
hingeJoint The HingeJoint attached to this GameObject (null if there is none attached).
particleEmitter The ParticleEmitter attached to this GameObject (null if there is none attached).
gameObject The game object this component is attached to. A component is always attached to a game object.
tag The tag of this game object.


1.3 基类可被继承的类函数    

   类函数                                描述                                   
Destroy Removes a gameobject, component or asset.
DestroyImmediate Destroys the object obj immediately. It is strongly recommended to use Destroy instead.
DontDestroyOnLoad Makes the object target not be destroyed automatically when loading a new scene.
FindObjectOfType Returns the first active loaded object of Type type.
FindObjectsOfType Returns a list of all active loaded objects of Type type.
Instantiate Clones the object original and returns the clone.

1.4 基类可被继承的函数

            类函数                                     描述                                
GetComponent Returns the component ofType type if the game object has one attached, null if it doesn't.
function GetComponent (type :Type) : Component
GetComponent Returns the component withnametype if the game object has one attached, null if it doesn't.
function 
GetComponent (type :string) : Component
GetComponentInChildren Returns the component of Type type in the GameObject or any of its children using depth first search.
GetComponentsInChildren Returns all components of Type type in the GameObject or any of its children.
GetComponents Returns all components of Type type in the GameObject.
CompareTag Is this game object tagged tag?
SendMessageUpwards Calls the method named methodName on every MonoBehaviour in this game object and on every ancestor of the behaviour
SendMessage Calls the method named methodName on every MonoBehaviour in this game object.
BroadcastMessage Calls the method named methodName on every MonoBehaviour in this game object or any of its children.
GetInstanceID Returns the instance id of the object.
ToString Returns the name of the game object.

1.5 基类可重写函数

1.5.1  常规更新事件

     函数名                                                                        描述
Update Update is called every frame, if the MonoBehaviour is enabled.
LateUpdate LateUpdate is called every frame, if the Behaviour is enabled.
LateUpdate is called after all Update functions have been called.
This is useful to order script execution. For example a follow camera
should always be implemented in LateUpdate because it tracks
objects that might have moved inside Update.
FixedUpdate This function is called every fixed framerate frame, if the MonoBehaviour is enabled.

1.5.2 初始化事件

         函数名                                                            描述                                                                                     
Awake Awake is called when the script instance is being loaded.
Start Start is called just before any of the Update methods is called the first time.
Reset Reset to default values.

1.5.3 GUI元素或Collider碰撞体事件

      函数名                                                    描述                                                                         
OnMouseEnter nMouseEnter is called when the mouse entered the GUIElement or Collider.
OnMouseOver OnMouseOver is called every frame while the mouse is over the GUIElement or Collider.
OnMouseExit OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider.
OnMouseDown OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider.
OnMouseUp OnMouseUp is called when the user has released the mouse button.
OnMouseUpAsButton OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. 
OnMouseDrag OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse.

1.5.4 Collider碰撞体事件

         函数名                                                              描述                          
OnTriggerEnter OnTriggerEnter is called when the Collider other enters the trigger.
OnTriggerExit OnTriggerExit is called when the Collider other has stopped touching the trigger.
OnTriggerStay OnTriggerStay is called once per frame for every Collider other that is touching the trigger.

1.5.5 Collider碰撞体或rigibody刚体事件

          函数名                                                       描述                                                                                                      
OnCollisionEnter OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider.
OnCollisionExit OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider.
OnCollisionStay OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider.

2. 控制游戏对象(GameObject)

    在Unity3D中,可以在监视器面板中修改物体的组件属性,但是更多的时候,需要使用脚本来进行动态操作。

2.1 访问组件

    最常见的一个情形是需要使用脚本访问附加到相同游戏对象(GameObject)上的另一个组件(当前脚本就是一个组件,其他的组件也就是另一个组件了)。一个组件实质上是一个类的实例,因而首先需要做的是获取想要操作的组件实例的引用。这个通过GetComponent函数来实现。典型的,可能会想要将一个组件赋值给一个变量,如下代码所示:  

void Start () {    Rigidbody rb = GetComponent<Rigidbody>();}

     一旦获取了组件实例的引用,就可以对它的属性进行想要的操作,同时也可以调用它的一些功能函数。

     如果想要访问另一个脚本文件,也可以使用GetComponent,只需使用脚本的类名作为该函数的组件类型参数(因为脚本本来就也是一个组件)。

// You can access script components in the same way as other components.function Start () var someScript : ExampleScript; someScript = GetComponent (ExampleScript); someScript.DoSomething ();}


    如果想要去获取一个并没有添加到当前游戏对象的组件,GetComponent函数会返回null,如果试图去改变一个null对象上的任何值,将会发生null引用错误。

    由于一些组件类型经常使用,unity提供了一些内置的变量来访问它们,参见1.2(内置变量),其示例代码如下:

void Start () {   transform.position = Vector3.zero;}

2.2 访问其他对象

     虽然游戏对象(GameObject)都有各自的组件(包括脚本)进行处理,使用代码进行跟踪其他物体是常有的事。例如,一个追赶的敌人可能需要知道玩家的位置,Unity提供了一系列的方法来获取其他对象,以适合不同的场合。

2.2.1 将对象【静态】链接到公有成员变量

    最直接的办法是将一个游戏对象添加到脚本的公有成员变量上,直接在编辑器中将需要访问的游戏对象拖到对应脚本组件的那个公有成员变量上,Unity3D会自动根据变量的类型将添加的游戏对象中相同的组件类型映射到该变量。

    例如将一个游戏对象拖给一个Transform的成员变量,就会自动的将游戏对象的Transform组件和该变量映射起来。
直接将对象和变量链接起来在处理需要有永久链接的对象的时候是最有用的方法。同时也可以使用一个数组变量和几个相同类型的对象链接起来,但是这种链接必须在Unity3D编辑器中完成,而不能在运行时进行

2.2.2 【动态】定位其它对象

2.2.2.1 查找子物体

      如果一个游戏场景中有很多同一类型的对象,例如敌人、路点(waypoints)和障碍物。这些对象在游戏中需要由一个特定的脚本来监视和响应。这个时候使用变量来链接这些对象太过麻烦。对于这种情况,通常更好的方法是将一系列的对象添加到一个父对象下面,这些子对象可以通过使用父对象的Transfrom组件来获得。

public class WaypointManager : MonoBehaviour {     public Transform waypoints;     void Start() {         waypoints = new Transform[transform.childCount];         int i = 0;         for (Transform t in transform) {            waypoints[i++] = t;         }     }  }  

    同时也可以使用Tranfrom.Find来查找某个具体的子对象。使用Transform来进行对象查找操作是因为每一个游戏对象都有Transfrom组件。

2.2.2.2 通过名称或标签访问对象

   只要有一些信息,在层级场景中的任何位置定位到该游戏对象是可能的。单个对象可以通过GameObject.Find函数进行查找。如下:  

GameObject player;void Start() {   player = GameObject.Find("MainHeroCharacter");}

   某个对象或者一系列的对象也可以分别通过GameObject.FindWithTag和GameObject.FindObjectsWidthTag函数进行定位。

2.2.2.3 查找特定类型的对象

     static Object  FindObjectOfType(Type  type)
     返回指定类型对象中的第一个活动的加载对象, 需要注意的是这个函数很慢(可能是由于要在整个场景中进行遍历),不推荐每一帧都使用这个函数,在大多数情况下可以使用单件模式,例如:
      Camera cam = FindObjectOfType(typeof(Camera)) as Camera;
      由于该函数返回的类型是Object,所以需要使用as进行一下强制转换。


      static Object[ ] FindObjectsOfType(Type type);
      返回指定类型的加载活动对象的列表,速度也慢

       HingeJoint[ ]  hinges = FindObjectsOfType(typeof(HingeJoint))  as  HingeJoint[ ];

3. 创建和销毁对象

     在运行时创建和销毁对象是常有的事。在Unity3D中,可以使用Instantiate函数对现有的一个对象做一个拷贝来创建一个新的游戏对象。

     实例化更多通常用于实例投射物(如子弹、榴弹、破片、飞行的铁球等),AI敌人,粒子爆炸或破坏物体的替代品。

// Instantiates 10 copies of prefab each 2 units apart from each othervar prefab : Transform;for (var i : int = 0;i < 10; i++) { Instantiate (prefab, Vector3(i * 2.0, 0, 0), Quaternion.identity);}
    值得注意的是用于进行拷贝的对象并不一定需要放置在场景中。更普遍的做法是将一个预设(Prefab)拖到脚本的对应公有成员变量上,实例化的时候直接对这个成员变量进行实例化即可。

// Instantiate a rigidbody then set the velocityvar projectile : Rigidbody;function Update () // Ctrl was pressed, launch a projectile //按Ctrl发射炮弹 if (Input.GetButtonDown("Fire1")) {  // Instantiate the projectile at the position and rotation of this transform  //在该变换位置和旋转,实例化炮弹  var clone : Rigidbody;  clone = Instantiate(projectile, transform.position, transform.rotation);  // Give the cloned object an initial velocity along the current object's Z axis  //沿着当前物体的Z轴给克隆的物体一个初速度。  clone.velocity = transform.TransformDirection (Vector3.forward * 10); }}

    实例化也能直接克隆脚本实例,整个游戏物体层次将被克隆,并且返回被克隆脚本的实例。

   同时也有一个Destroy函数在帧更新函数完成后或设定的一个延时时间后销毁一个对象。

// Kills the game object//销毁游戏物体Destroy (gameObject);// Removes this script instance from the game object//从游戏物体删除该脚本实例Destroy (this);// Removes the rigidbody from the game object//从游戏物体删除刚体Destroy (rigidbody);// Kills the game object in 5 seconds after loading the object//加载物体5秒后销毁游戏物体Destroy (gameObject, 5);// When the user presses Ctrl, it will remove the script// named FooScript from the game object//当按下Ctrl将从游戏物体删除名为FooScript的脚本function Update () if (Input.GetButton ("Fire1") && GetComponent (FooScript))  Destroy (GetComponent (FooScript));}

    注意到Destroy函数可以销毁单独的组件而不对游戏对象本身产生影响,一个通常易犯的错误是Destroy(this); 这句代码仅仅销毁脚本组件,而不销毁该脚本所附加在的对象。

4. 协程(Coroutines)

     一个coroutine就像一个可以暂停执行并将控制权返回给Unity3D的函数,但是在下一帧的时候又可以在它停止的位置继续执行。在C#中,这样声明一个coroutine:

IEnumerator Fade() {     for (float f = 1f; f <= 0; f -= 0.1f) {        Color c = renderer.material.color;        c.alpha = f;        renderer.material.color = c;        yield return;     }  }  

    实质上它是一个返回类型为IEnumerator的函数,同时在函数体中增加了yield return这句代码。yield return这行就是会在执行的时候暂停、在下一帧的时候恢复执行的位置。要启动coroutine,需要使用StartCorutine函数。

void Update() {     if (Input.GetKeyDown("f")) {        StartCoroutine("Fade");     }  } 

    默认的情况下,一个coroutine在它暂停后的下一帧恢复,但是也可以使用WaitFroSeconds来引入一个延时。

IEnumerator Fade() {   for (float f = 1f; f <= 0; f -= 0.1f) {    Color c = renderer.material.color;    c.alpha = f;    renderer.material.color = c;    yield return new WaitForSeconds(.1f);   }  }  

    这个可以用于产生一个随时间变化的效果,同时也是一个用于进行优化的有效方法。游戏中的许多人物需要周期性的执行,最常用的做法是将它们包含在Update函数中。但是Update函数通常每秒会调用多次。当有的任务并不需要这么频繁的被调用的时候,可以将它放在一个coroutine中按一定时间进行调用,而不是每一帧都调用。


参考:http://game.ceeger.com/Script/


           

猜你喜欢

转载自blog.csdn.net/qq_44884706/article/details/89418861