Unity中的JS,也称UnityScript,和基于浏览器的JS有比较大的区别,因为UnityScript是基于Mono的.net 的IL语言规范,CLR运行环境(Mono虚拟机)上设计的语言。 0.基本概念: Unity3d中的脚本可以与游戏对象链接,变量数值的修改以及实时预览脚本修改后的游戏效果,节省了很多脚本调整和调试的时间,提高了开发效率。 简单的项目和Unity中的大量例子和脚本资源包都是用JS。商业项目基本都用C#,因为C#和C/C++交互方便,丰富的数据结构和面向对象的架构利于大型程序的编写,很多强大的第三方插件是用C#开发的,方便工作流程。 编译过程: UnityScript运行环境使用Mono 的.NET Framework。实际上,UnityScript是用Boo实现的,Boo是运行在Mono虚拟机上的一种语言,并且编译成本机代码。JavasScript很多典型的运行环境如String和Math库由Mono提供。你也就知道了为什么UnityScript中方法名要大写了,因为要与Mono中相同。 Unity中的脚本和传统的解释型(JIT解释)语言不同,都是需要经过编译的,因此速度都一样快。 这三种语言的代码最后都会被编译执行,而且脚本可以互相访问。 库的调用: Unity的脚本基于Mono的.net平台上运行,脚本都可以使用.net库,为xml,数据库,正则表达式提供了良好的解决方案。 Unity中js想调用mono的.net库,直接import即可。 import System; import System.IO; 否则,你带指定完整的命名空间来调用函数,如System.IO.File.Open(),而不是File.Open()。 1.基本类型和语句: 1)数据类型: 数值类型:char,byte,sbyte;short, ushort, int, uint, long, ulong; float,double; decimal. 布尔值:boolean 字符串:String,[index]符号 字符串[0]是字符串取下标为0的字符。 var s: String = "Whatever_it_may_be"; s =s.Replace("_"[0], " "[0]); // replace all the underscoreswith spaces 2)变量声明: 变量必须先声明[必须](编译缘故,且声明类型有利于减少太多常量,避免内存泄露发生),可以定义类型[可选]: var playerName:String; 函数的参数也要声明类型: function Test( playerName:String, baseInfo:Object ) { } 如果声明时候定义或赋值了类型,那么不能再改变类型,除非声明时候不定义类型。 var a= "test"; a =5;// 报错 var a; a ="test"; a =5;//正确 变量前面可以加public,protected, private来修饰;不写默认是public的,public的变量可以在Inspector视图中查看和编辑。 3)数组: 内建自定义数组(快功能简单): var values : int[] = {1,2,3}; 转换到Array数组(需要对数组处理),var arr = new Array(values); Array对象数组(慢动态增长排序合并功能): var arr = new Array(); arr.Push("good"); 转换到内建数组(需要比较高的性能时候),var bArray : int[] = arr.ToBuiltin(int); 4)链表和泛型: UnityScript可以使用泛型,所以当用到动态大小的数组时,最好用List来替代Array。基本上就没有什么理由要用到Array了,List更快并且功能更多。如果你需要混合类型的数组,你可以用Object List。UnityScript中泛型的语法与C#中接近,除了要加一个额外的“.”符号在“<>”之前。如C#中的"varmyList = new List<int>();"在UnityScript中对应的写法为:"var myList = new List.<int>();"。 5)运算符和表达式: 和C一样。 6)语句: 每行必须写分号; 比C多了for in 用于遍历对象元素,for(var i:int = 0; i < 10; i++)。 switch可以使用String变量。 2.函数 声明规则: function函数名(参数1:参数类型, 参数2:参数类型...):返回值类型 { } unityScript中的函数可以视为Function类型对象,可以像变量一样进行赋值比较等操作。 不能写匿名函数。 Math需要用Mathf。 3.类(DOM js中没有类): 在Unity里,一个js文件就是一个类,unity引擎会为js文件自动生成一个类。 对于UnityScript脚本,Unity编译该文件时会自动的为脚本添加一个与脚本文件名相同的类,并自动地继承于MonoBehaviour。但对于C#或Boo,则需要在脚本中显式的写出类名和继承关系。要创建不继承自MonoBehaviour的类,用C#语言,或者从外部添加js脚本资源(就可以自己直接new对象出来了)。 //SayHello.js #pragma strict // 严格类型检测,尽早生成错误,禁用动态类型,强制用静态类型(强类型) function sayHello() { } 等价于C#中: #pragma strict public class SayHello extends MonoBehaviour { function sayHello() { } } 但是,你可以在同一个文件中声明多个类,尤其是当你需要使用一些辅助工具类时非常有用,一般这种辅助类没有继承自MonoBehaviour。 如 class ButtonState { var currentState : int; var offset : Vector2; } 如果你在一个文件中声明了MonoBehaviour的子类,但类名与文件名不匹配的话,即使是大小写不一致,你也会碰到麻烦。 一定要理解,当你在js文件中编写行为脚本是,你实际上在编写一个类: a) 类及其对象:文件名就是类名,如果文件名是foo.js,你就可以在其他地方以var x = new foo()的格式进行调用; b)类的方法和预定义方法:有一些特定的方法是实现系统预先定义的一些事件处理器,如Start、FixedUpdate等。任何事件中,声明的一个函数就是这个文件所代表的类的一个方法。 c) 类的属性:文件中在函数定义之外编写的代码都在该类的范围之内执行,声明的变量也是该类的成员变量。类中的静态函数、变量本质上是类的方法与属性。 实例: /*whenyou drag the behavior onto a gameobject, these values will be visible andeditable */ public name : String; /*otherscripts which have a reference to this object (e.g. if they're attached to thesame object) can see public functions */ publicage : int; /*privatemembers are NOT visible to other scripts, even if they have a reference to thisobject */ private favoriteColor : Color; /*youcan assign a value to bestFriend by dragging a gameObject with an attached copyof the foo behavior to this property. This will give you access to bestFriend'spublic methods and members */ public bestFriend : foo; /*this function will be called every frame by Unity, so it's actually an eventhandler */ function Update(){ /*transform is a property inherited from thegameObject the behavior is attached to*/ var t = transform; } function Bar(){ // this is just a function, if you don't callit yourself, it will never do anything } 4.继承 Unity里需要extends关键字: class MyHello extends Hello { } DOM js中用prototype里的bind()方法。 Unityjs里面还提供了虚拟函数。 类的继承也是不同的。在JavaScript和C#中,方法是隐型并且不可重载,除非方法声明中添加虚拟关键字。不同的是C#只重载那些包含重载关键字override的方法。而JavaScript不需要关键词,只要重载类方法就可以覆盖,其它的都可继承得到。 //Foo.js var foo = "hello, world"; function doEet () { // does nothing, intended to be overridden } 将会生成: //Foo.js import UnityEngine; classFoo extends MonoBehaviour { public var foo = "hello, world"; public function doEet () { // does nothing, intended to be overridden } } 子类写法: //PrintingFoo.js class PrintingFoo extends Foo { function doEet() { print( foo ); } } 创建虚函数: classFoo { virtual function DoSomething () { Debug.Log("from baseclass"); } } //SubFoo.js class SubFoo extends Foo { virtual function DoSomething() { Debug.Log("from subclass"); } } //Elsewhere varfoo : Foo = new SubFoo(); foo.DoSomething();//printsfrom sub class 如果你要调用父类的方法,用关键字super。示例如下: class SubFoo extends Foo { virtual function DoSomething() { super.DoSomething();// 不是虚函数,应该不需要super修饰就可以直接调用。 Debug.Log("from sub class"); } } //Elsewhere varfoo : Foo = new SubFoo(); foo.DoSomething();//prints"from base class" and "from sub class" 类间通信:Use-a方式(关联关系)比继承耦合度底得多,易于修改维护 /*Foo.js */ varbar : Bar; function Start(){ bar = gameObject.GetComponent(Bar); } function doEet(){ // do my own thing if( bar ){ bar.doEet(); } } /*Bar.js */ function doEet(){ // do something special } 5.对象 Unity中不一定可以用new 创建对象(普通类可以,特殊类不行,各种脚本都一样)。特殊类:用编辑器工程视图右键或者组件Create js 或者C#的类都是继承自MonoBehaviour类,对这种类型的类不能new出来一个对象,原因是Unity会为这种类自动创建对象,并调用被重载的方法。 使得用Unity非常有趣的一件事是,它的类采用了非常自由的mixin策略。通常你可以非常快速简单的查到你所需要的类。最通用的一个例子是Transform类,对于你正在处理的一个对象,所有被附加到该对象的相关联的类,都可以简单快速的获取它的属性和方法。 比如,典型的动作就是你会访问名叫"transform"的变量,它代表与该对象关联的Transform类的实例。如果你需要相关的位置坐标,就访问transform.position(一个 Vector3对象);如果你需要它的GameObject,就访问transform.gameObject;如果你需要它的渲染器,就访问transform.renderer。等等。一般如果你一个对象的主要属性,你就可以快速获取该对象所有其他的属性。 6.js和C#单向通信,不能双向通信,因为编译问题 js访问C#脚本组件: //createa variable to access the C# script private var csScript : CSharp1; function Awake() { //Get the CSharp Script csScript =this.GetComponent("CSharp1");//Don't forget to place the 'CSharp1'file inside the 'Standard Assets' folder } //rendertext and other GUI elements to the screen function OnGUI() { //render the CSharp1 'message' variable GUI.Label(new Rect(10,30,500,20),csScript.message); } C#访问js脚本组件: using UnityEngine; using System.Collections; public class CSharp2 : MonoBehaviour { //create a variable to access the JavaScriptscript private JS1 jsScript; void Awake() { //Get the JavaScript component jsScript = this.GetComponent<JS1>();//Don'tforget to place the 'JS1' file inside the 'Standard Assets' folder } //render text and other GUI elements to thescreen void OnGUI() { //render the JS1 'message' variable GUI.Label(newRect(10,10,300,20),jsScript.message); } } 7.使用第三方库: 第三方.NET库如XML-RPC可以以新建资源Asset的方式引入。 8.调试 可以用print函数,Log()函数或者Debug.Log(),想设置断点,用Debug.Break()函数。 print() 函数将会生成消息,并输出到状态栏及控制台中,但仅限MonoBehavioour类范围内。 更好的办法是使用Debug.Log("insert messagehere");,该方法到处都可使用。还可用Debug.LogWarning 和 Debug.LogError生成警告和错误消息。 Debug.Break(); 可以将游戏暂停在一个精确的点。当一种特定的情条件发生时,如果你想检查对象的状态的时候,这个特性非常有用。 开发环境运行项目时,编辑界面也是完全实时更新的,你可以查看对象实例的内部状态。