初级知识

 脚本概览

Unity内部的脚本,是通过附加自定义脚本对象到游戏物体组成的。在脚本对象内部不同的函数被特定的事件调用。最常用的列在下面:

Update:这个函数在渲染第一帧之前被调用,这里是大部分游戏行为代码被执行的地方,除了物理代码。

FixedUpdate:这个函数在每个物理时间被调用一次,这是处理基于物理游戏的地方。

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

你也能定义事件句柄,它们的名称都以On开始,(例如OnCollisionEnter)。

 

常用操作

大多数游戏物体的操作是通过游戏物体的Transform或Rigidbody来做的,在行为脚本内部它们可以分别通过transform和rigidbody访问,因此如果你想绕着Y轴每帧旋转5度,你可以如下写:

function Update(){

transform.Rotate(0,5,0);

}

如果你想向前移动一个物体,你应该如下写:

function Update(){

transform.Translate(0,0,2);

}

跟踪时间

Time类包含了一个非常重要的类变量,称为deltaTime,这个变量包含从上一次调用Update或FixedUpdate(根据你是在Update函数还是在FixedUpdate函数中)到现在的时间量。

所以对于上面的例子,修改它使这个物体以一个恒定的速度旋转而不依赖于帧率:

function Update(){

transform.Rotate(0,5*Time.deltaTime,0);

}

移动物体:

function Update(){

transform. Translate (0, ,0,2*Time.deltaTime);

}

如果你加或是减一个每帧改变的值,你应该将它与Time.deltaTime相乘。当你乘以Time.deltaTime时,你实际的表达:我想以 10米/秒移动这个物体不是10米/帧。这不仅仅是因为你的游戏将独立于帧而运行,同时也是因为运动的单位容易理解。( 米/秒)

另一个例子,如果你想随着时间增加光照的范围。下面的表达式,以2单位/秒改变半径。

function Update (){

light.range += 2.0 * Time.deltaTime;

}

当通过力处理刚体的时候,你通常不必用Time.deltaTime,因为引擎已经为你考虑到了这一点。

 

访问其他组件

组件被附加到游戏物体,附加Renderer到游戏物体使它在场景中渲染,附加一个Camera使它变为相机物体,所有的脚本都是组件,因为它们能被附加到游戏物体。

最常用的组件可以作为简单成员变量访问:

Component             可如下访问

Transform             transform

Rigidbody             rigidbody

Renderer              renderer

Camera                camera (only on camera objects)

Light                 light (only on light objects)

Animation             animation

Collider              collider

…等等。

对于完整的预定义成员变量的列表。查看Component,Behaviour和MonnoBehaviour类文档。如果游戏物体没有你想取的相同类型的组件,上面的变量将被设置为null。

任何附加到一个游戏物体的组件或脚本都可以通过GetComponent访问

transform.Translate(0,3,0);  //等同于

GetComponent(Transform).Translate(0, 1, 0);

注意transfom和Transform之间大小写的区别,前者是变量(小写),后者是类或脚本名称(大写)。大小写不同使你能够从类和脚本名中区分变量。

应用我们所学,你可以使用GetComponent找到任何附加在同一游戏物体上的脚本和组件,请注意要使用下面的例子能够工作,你需要有一个名为 OtherScript的脚本,其中包含一个DoSomething函数。OtherScript脚本必须与下面的脚本附加到相同的物体上。

function Update(){

otherScript = GetComponent(OtherScript); //这个在同一游戏物体内找到名为OtherScript的脚本

otherScript.DoSomething(); //并调用它上加的DoSomething

}


向量

Unity使用Vector3类同一表示全体3D向量,3D向量的不同组件可以通过想x,y和z成员变量访问。

var aPosition : Vector3;
aPosition.x = 1;
aPosition.y = 1;
aPosition.z = 1;

你也能够使用Vector3构造函数来同时初始化所有组件。

var aPosition = Vector3(1, 1, 1);
Vector3也定义了一些常用的变量值。
var direction = Vector3.up; // 与 Vector3(0, 1, 0);相同

单个向量上的操作可以使用下面的方式访问:

someVector.Normalize();

使用多个向量的操作可以使用Vector3类的方法;

theDistance = Vector3.Distance(oneVector, otherVector);

(注意你必须在函数名之前写Vector3来告诉JavaScript在哪里找到这个方法,这适用于所有类函数)

你也可以使用普通数学操作来操纵向量。

combined = vector1 + vector2;

查看Vector3类文档获取完整操纵和可用属性的列表。

 

成员变量 & 全局变量(Javascript 版本)

定义在任何函数之外的变量是一个成员变量Field。在Unity中这个变量可以通过检视面板来访问,任何保存在成员变量中的值也可以自动随工程保存。

public int memberVariable = 0.0;

上面的变量将在检视面板中显示为名为"Member Variable"的数值属性。

如果你设置变量的类型为一个组件类型(例如Transform, Rigidbody, Collider,任何脚本名称,等等)然后你可以在检视面板中通过拖动一个游戏物体来设置它们。

public Transform enemy;

function Update()
{

if ( Vector3.Distance( enemy.position, transform.position ) < 10 );
print("I sense the enemy is near!");

}
}

你也可以创建私有成员变量。私有成员变量可以用来存储那些在该脚本之外不可见的状态。私有成员变量不会被保存到磁盘并且在检视面板中不能编辑。当它被设置为调试模式时,它们在检视面板中可见。这允许你就像一个实时更新的调试器一样使用私有变量。

private var lastCollider : Collider;

function OnCollisionEnter( collisionInfo : Collision ) {

lastCollider = collisionInfo.other;

}

 

 全局变量

你也可以使用static关键字创建全局变量,这创造了一个全局变量,名为someGlobal

static var someGlobal = 5;// 你可以在脚本内部像普通变量一样访问它

print(someGlobal);// 'TheScriptName.js'中的一个静态变量

someGlobal = 1;

为了从另一个脚本访问它,你需要使用这个脚本的名称加上一个点和全局变量名。

print(TheScriptName.someGlobal);
TheScriptName.someGlobal = 10;


用C#编写脚本

除了语法,使用C#编写脚本还有一些不同。最需要注意的是:

1.从MonoBehaviour继承

所有的行为脚本必须从MonoBehaviour继承(直接或间接)。在Javascript中这自动完成,但是必须在C#脚本中显示申 明。如果你在Unity内部使用Asset -> Create -> C Sharp菜单创建脚本,创建模板已经包含了必需的定义。

public class NewBehaviourScript : MonoBehaviour {...} // C#

2.使用Awake或Start函数来初始化

Javascript中放置在函数之外的代码,在C#中要放置在Awake或Start中。

Awake和Start的不同是Awake在场景被加载时候运行,而Start在第一次调用Update或FixedUpdate函数之前被调用,所有Awake函数在任何Start函数调用之前被调用。

3.类名必须与文件名相同

Javascript中,类名被隐式地设置为脚本的文件名(不包含文件扩展名)。在c#中必须手工做。

4.在C#中Coroutines有不同语法。

Coroutines必有一个IEnumerator返回类型,并且yield使用yield return… 而不是yield…

using System.Collections;

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour {

// C# coroutine

IEnumerator SomeCoroutine ()

{

yield return 0;// 等一帧

yield return new WaitForSeconds (2);//等两秒

}
}

5.不要使用命名空间

目前Unity还不支持将代码放置在一个命名空间中,这个需要将会出在未来的版本中。

6.避免使用构造函数

不要在构造函数中初始化任何变量,使用Awake或Start实现这个目的。即使是在编辑模式中Unity也自动调用构造函数,这通常发生在一个脚 本被编译之后,因为需要调用构造函数来取向一个脚本的默认值。构造函数不仅会在无法预料的时刻被调用,它也会为预设或未激活的游戏物体调用。

单件模式使用构造函数可能会导致严重的后果,带来类似随机null引用异常。

因此如果你想实现,如,一个单件模式,不要使用构造函数,而是使用Awake。其实上,没有理由一定要在继续自MononBehaviour类的构造函数中写任何代码。

 

脚本编译顺序:

1.所有在"Standard Assets", "Pro Standard Assets" 或 "Plugins"的脚本被首先编译。

在这些文件夹之内的脚本不能直接访问这些文件夹之外脚本。不能直接引用或它的 变量,但是可以使用GameObject.SentMessage与它们通信。

2.所有在"Standard Assets/Editor", "Pro Standard Assets/Editor" 或 "Plugins/Editor"的脚本被首先编译。

如果你想使用UnityEditor命名空间你必须放置你的脚本在这些文件夹中,例如添加菜单项或自定义的向导,你都需要放置脚本到这些文件夹。这些脚本可以访问前一组中的脚本。

3.然后所有在"Editor"中的脚本被编译。

如果你想使用UnityEditor命名空间你必须放置你的脚本在这些文件夹中。例如添加菜单单项或自定义的向导,你都需要放置脚本到这些文件夹。 这些脚本可以访问所有前面组中的脚本,然而它们不能访问后面组中的脚本。这可能会是一个问题,当编写编辑器代码编辑那些在后面组中的脚本时。有两个解决方 法:1、移动其他脚本到"Plugins"文件夹 2、利用JavaScript的动态类型,在javascript中你不需要知道类的类型。在使用GetComponent时你可以使用字符串而不是类 型。你也可以使用SendMessage,它使用一个字符串。

4.所有其他的脚本被最后编译

所有那些没有在上面文件夹中的脚本被最后编译。所有在这里编译的脚本可以访问第一个组中的所有脚本("Standard Assets","ProStandard Assets" or "Plugins")。这允许你让不同的脚本语言互操作。例如,如果你想创建一个JavaScript。它使用一个C#脚本;放置C#脚本 到"Standard Assets"文件夹并且JavaScript放置在"Standard Assets"文件夹之外。现在JavaScript可以直接引用c#脚本。放置在第一个组中的脚本,将需要较长的编译时间,因为当他们被编译后,第三组 需要被重新编译。因此如果你想减少编译时间,移动那些不常改变的到第一组。经常改变的到第四组

posted @ 2013-01-02 06:29  若愚Shawn  阅读(173)  评论(0编辑  收藏  举报