Unity3D脚本语言UnityScript初探

译者注:

Unity3D中支持三种语言:JavaScript、C#、Boo,很多人不知道如何选择,通过这篇译文,我们可以搞清楚这三者语言的来龙去脉,对选择主语言有一定的借鉴意义。

首先,Unity是基于Mono也就是.Net的运行环境的,所以它肯定支持C#;然后,Unity团队自行开发了一种Boo的语言;后面可能考虑到用户的接受程度的问题,又开发了类似JS的一种语言,但那绝对不是JS,勉强可以称之为UnityScript。这三种语言的代码最后都会被编译执行,而且可以互相访问。

一、Unity中的"JavaScript"与你所了解的JavaScript对比

1. 使用 #pragma strict

#pragma strict

进行这样的声明,是一种很好的习惯,并且对于进行iOS开发来说也是必须的。 #pragma strict 意味着强制进行更严格的类型检测、尽早生成更多有用的错误信息、养成更好的编程习惯。

2. 使用枚举 enum

enum WeaponType {
  pistol,
  rifle,
  launcher
}
var type : WeaponType = WeaponType.pistol;
 

这种方式更加简洁,并且是比使用字符串产生更少潜在错误的方法。

3. 其实是大不相同的

尽管Unity中的JavaScript尝试尽量做得至少某种程度上要像ECMAScript标准,但它与同样基于ECMAScript的JavaScript在其他实现方面有很多不同。也许它与微软的JScript更加相似,尤其是它们都是.NET平台上的语言。当然,Unity的JavaScript版本是自己独立开发实现的,并且两者之间也有很多不同之处。

4. 运行速度快

Unity JavaScript 是编译型的,所以性能很高,但浏览器中的JavaScript是动态解释型的。

在Unity中,JavaScript、C#与Boo在运行速度上显然没有差异。它们各有优缺点,但速度上是一致的。

说明:如果你关注过浏览器之争的话,你应该知道现代浏览器中JavaScript已经不是简单的解释执行,而是以JIT方式编译执行。当然,肯定是不支持严格类型定义的。如果ECMAScript标准改成允许显示声明变量类型(像Adobe公司所提倡的,译注:其实个人觉得UnityScript更像是ActionScript3),JavaScript的性能还能以数量级的提升。尽管如此,现实是真正的JavaScript就算是拿Safari浏览器的Squirrelfish Extreme引擎进行测试,比Unity中的UnityScript仍要慢上两个数量级。

5. 必须用var关键字声明变量

JavaScript中,如果你定义变量时不用var关键字,该变量将会作为全局变量处理。

function DoSomeStuff() {
   x = 3;
}

DoSomeStuff();

alert(x); // returns 3 ... in JavaScript (not in Unity‘s UnityScript)
 

为了避免JS老用户在Unity碰到这种模棱两可的情况,就要求在定义变量时加上var关键字,那样就可以自动讲变量的作用域限定在当前范围。

function DoSomeStuff() {
   var x = 3;
}

DoSomeStuff();

print(x); // raises an error because x is not global in any sense.
 

6. UnityScript是基于类式继承,而不是原型式继承

UnityScript中,没有.prototype那样混乱的写法。要定义类,你只要这样简单的定义:

// Foo.js
var foo = "hello, world";

function doEet () {
  // does nothing, intended to be overridden
}
 

编译器最后在编译之前会自动补全一些代码,构造一个完整的类定义结构。最终形式应该类似如下:

// Foo.js
import UnityEngine;
class Foo 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 );
  }
}

虚函数可用于重载函数

在UnityScript中,你可以创建虚函数。

class Foo
{
     virtual function DoSomething ()
     {
         Debug.Log("from base class");
     }
}

//SubFoo.js
class SubFoo extends Foo
{
     virtual function DoSomething()
     {
          Debug.Log("from sub class");
     }
}

//Elsewhere
var foo : Foo = new SubFoo();
foo.DoSomething();//prints from sub class

如果你要调用父类的方法,用关键字super。示例如下:

class SubFoo extends Foo
{
     virtual function DoSomething()
     {
          super.DoSomething();
          Debug.Log("from sub class");
     }
}

//Elsewhere
var foo : Foo = new SubFoo();
foo.DoSomething();//prints "from base class" and "from sub class"

考虑用编写Mixins与Helpers的方式替代子类继承

可以很容易编写相互访问与调用的类,但还有一种方式可能比用对指定对象进行子类继承具有更好的维护性。

如:

/* Foo.js */
var bar : Bar;

function Start(){
  bar = gameObject.GetComponent(Bar);
}

function doEet(){
  // do my own thing
  if( bar ){
    bar.doEet();
  }
}

/* Bar.js */
  function doEet(){
    // do something special
  }
 

7. 声明字符串类型是使用String (代表Mono中的String类) 而不是string

var x : String;

你在JavaScript所知道及喜欢的字符串函数都在,不同的是调用时首字母大写。

比如如何分割字符串,写法如下:

var qualifiedName = "System.Integer myInt";

var name = qualifiedName.Split(" "[0]);
 

分割后,name[1] 就包含"myInt"。

要查看可用的字符串函数清单,请访问Mono文档(http://go-mono.com/docs/monodoc.ashx?link=T%3aSystem.String%2f*)

8. 变量在使用前必须进行声明

a = "fred"; // works in JavaScript (a is treated as a global), error in Unity

var a = "fred"; // a is now a string variable containing ‘fred‘
var b: String; // b is now a string variable, with no assigned value
b = "wilma";
var c; // c is now a dynamically typed variable with no assigned value
c = "barney";
c = 17;

a) 你可以(通常也应该这么做)显示声明变量的作用域,如private、public等。不声明的话,默认代表public。

b) 在你声明一个变量时,如果直接赋值给它,Unity就会隐式的给它定义一个数据类型,所以:

var a = "fred"; // a is now of type String
a = 5; // ERROR! -- a is a String
var b : String = "fred"; // redundant
 

但:

var a; // a is dynamically typed;
a = "fred"; // works
a = 5; // works

9. 方法名与类名通常都是首字母大写

方法名与类名一般是首字母大写的,除非当它们不是遵循这一原则的时候。这句话很矛盾。本质上,UnityScript是处在.NET的命名约定的环境 - 方法名采用CamelCase这种骆驼峰式及camelCase这种首字母大写的写法、属性采用骆驼峰式且首字母小写,但它也试着像JavaScript的写法 - 像C一样,严重分化成小写命名及camelCase骆驼峰式。

如 JavaScript 中, typeof("fred") == ‘string‘, 但在Unity中你的写法是 var a: String;

10. 多了很多数据类型、两种数组、无对象语法糖

JavaScript本质上有三种类型:数值、字符串与对象(函数与数组都是对象)。UnityScript则具有更多的数据类型,包括:

1)对象:不能与array、Array进行互相转换;

var a = new Object(); // works
a.fred = "wilma"; // runtime exception!
 

2)原生数组:无法进行动态调整;

var a = [1, 2, 3];
a.Push(4); // ERROR -- won‘t work!
 

如果要定义指定类型的数组,语法如下:

public var friendsOfCarlotta : Transform[];

3)UnityScript Array:可以动态调整

var a = new Array();
a.Push(4); // This works
 

你可以把UnityScript Array转换成原生array,效率更高但灵活性降低,具体是使用方法ToBuiltIn(ArrayType),如:

var a = new Array();
a.Push(1);
a.Push(3.1415926535);
a.Push(17);
var b = a.ToBuiltin(float);
 

4)整型(包括int、uint32、等等):

Unity支持各种整型的大数,你不需要担心。

5)Unity的大量内置类(如Vector3):

你在使用Unity的过程中,你会越来越熟悉这些类,就像Web开发时那些DOM类一样。Unity中的类相比DOM要少。

使得用Unity非常有趣的一件事是,它的类采用了非常自由的mixin策略。通常你可以非常快速简单的查到你所需要的类。最通用的一个例子是Transform类,对于你正在处理的一个对象,所有被附加到该对象的相关联的类,你都可以简单快速的获取。(这段话没有翻译好)

比如,典型的动作就是你会访问名叫"transform"的变量,它代表与该对象关联的Transform类的实例。如果你需要相关的位置坐标,就访问transform.position(一个 Vector3对象);如果你需要它的GameObject,就访问transform.gameObject;如果你需要它的渲染器,就访问transform.renderer。等等。一般如果你一个对象的主要属性,你就可以快速获取所有其他的属性。

a) Unity的String类缺少JavaScript中字符串的好的特性;

b) Unity的内部数组远不如JavaScript中数组和对象的灵活。当然,可以用各种集合类如List、Queue、Dictionary等来配合实现。内部数组速度是最快的。

11. 每个.js文件默认代表一个类

一般来说,贴入如下代码:

var x : int;
function y(){}
 

并保存到Foo.js文件中,等同于在该文件中输入如下代码:

class Foo extends MonoBehaviour {
  var x : int;
  function y(){}
}
 

但是,你可以在同一个文件中声明多个类,尤其是当你需要使用一些辅助工具类时非常有用,一般这种辅助类没有继承自MonoBehaviour。

class ButtonState {
  var currentState : int;
  var offset : Vector2;
}
 

如果你在一个文件中声明了MonoBehaviour的子类,但类名与文件名不匹配的话,即使是大小写不一致,你也会碰到麻烦。

一定要理解,当你在js文件中编写行为脚本是,你实际上在编写一个类:

a) 文件名就是类名,如果文件名是foo.js,你就可以在其他地方以var x = new foo()的格式进行调用;

b) 有一些特定的方法是实现系统预先定义的一些事件处理器,如Start、FixedUpdate等。任何事件中,声明的一个函数就是这个文件所代表的类的一个方法。

c) 文件中在函数定义之外编写的代码都在该类的范围之内执行,声明的变量也是该类的成员变量。

d) 类中的静态函数、变量本质上是类的方法与属性。

这种方式远比真正的JavaScript中实现的类来的更优雅,但某种程度上来说是限定你以更好的方式进行编码。

例如,创建一个行为脚本,命名为foo,那文件名就应该是foo.js。假设文件的内容如下:

public name : String; // when you drag the behavior onto a gameobject, these values will be visible and editable
public age : int; // other scripts which have a reference to this object (e.g. if they‘re attached to the same object) can see public functions
private favoriteColor : Color; // private members are NOT visible to other scripts, even if they have a reference to this object
public bestFriend : foo; // you can assign a value to bestFriend by dragging a gameObject with an attached copy of the foo behavior to this property. This will give you access to bestFriend‘s public methods and members

function Update(){
  // this function will be called every frame by Unity, so it‘s actually an event handler
  var t = transform; // transform is a property inherited from the gameObject the behavior is attached to
}

function Bar(){
  // this is just a function, if you don‘t call it yourself, it will never do anything
}
 

调用父类方法

super()代表父类的构造函数,supper则相当于父类中的原本应该以this访问的成员函数,如super.foo()代表代用父类的foo()方法。

12. 分号不可缺少

JavaScript中分号是可写可不写的,但在Unity中必须要写。

var foo = 3 // OK in JavaScript but an error in Unity
foo += 17
 

13. Math is Mathf; Math.abs is Mathf.Abs

JavaScript的Math库在Unity中对应为Mathf库,并且方法名是首字母大写的,如Math.abs()在Unity中就应该是Mathf.Abs()。

二、Mono运行环境 (.NET)

UnityScript运行环境使用Mono - .NET的开源克隆。实际上,UnityScript是用Boo实现的,Boo是运行在Mono虚拟机上的一种语言,并且编译成本机代码。JavasScript很多典型的运行环境如String和Math库由Mono提供。你也就知道了为什么UnityScript中方法名要大写了,因为要与Mono中相同。

要使用Mono库,就需要导入它们,如:

import System;
import System.IO;
 

否则,你带指定完整的命名空间来调用函数,如System.IO.File.Open(),而不是File.Open()。

Mono中的数据类型

当Mono函数需要字符char作为输入参数时,你可以简单的使用索引来获取,比如你像将小写的a作为字符char a传递,你可以这样写:

"a"[0]

如,当使用String.Replace()函数时,写法如下:

var s : String = "Whatever_it_may_be";
s = s.Replace("_"[0], " "[0]); // replace all the underscores with spaces

当处理Array对象时,可以把它转换成更快的内置array类型数据:

fastArray : SomeType[] = monoArray.ToBuiltin(SomeType);

UnityScript可以使用泛型,所以当用到动态大小的数组时,最好用List来替代Array。基本上就没有什么理由要用到Array了,List更快并且功能更多。如果你需要混合类型的数组,你可以用Object List。UnityScript中泛型的语法与C#中接近,除了要加一个额外的“.”符号在“<>”之前。如C#中的"var myList = new List<int>();"在UnityScript中对应的写法为:"var myList = new List.<int>();"。

使用第三方.NET库

第三方.NET库如XML-RPC可以以新建资源Asset的方式引入。

三、调试

脚本错误 会在Unity窗口状态栏中以红色x图标显示。点击该图标,会打开console视图,显示错误列表,并且可以快速跳转到脚本中出错的那一行。

Unity也会生成有用的警告,这些警告以黄色的!图标显示,比如会告诉你声明的一个变量没有用到过。努力让编写的代码不会生成警告信息是一个非常好的习惯。

print()函数将会生成消息,并输出到状态栏及控制台中,但仅限MonoBehavioour类范围内。更好的办法是使用Debug.Log("insert message here");,该方法到处都可使用。还可用Debug.LogWarning 和 Debug.LogError生成警告和错误消息。

Debug.Break(); 可以将游戏暂停在一个精确的点。当一种特定的情条件发生时,如果你想检查对象的状态的时候,这个特性非常有用。

开发环境运行项目时,编辑界面也是完全实时更新的,你可以查看对象实例的内部状态。

本文由Tonio Loewald (a.k.a. podperson)编写。翻译:http://x3d.cnblogs.com/p/3838619.html

Unity3D脚本语言UnityScript初探

时间: 2024-10-05 23:22:13

Unity3D脚本语言UnityScript初探的相关文章

unity3d脚本语言中的引用类型

在之前的文文里有说到,值类型和引用类型,那么这会就单独说下引用类型: Unity3D中的C#语言提供了专门的类型来为开发者提供使用C#开发游戏的便利条件: 在该引擎中,使用UnityEngine命名空间来盛放自己定义的类型.其中,UnityEngine.Object类该游戏引擎的C#脚本语言中最基本的类,也就是所有对象的基类.所有派生自该类的公开变量都会显示在监视器(Inspector)视图中. 该类提供的类成员: 字段 hideFlags 标识该对象是否被隐藏[我用的2017版本的,都返回的是

现代的新语言--Swift初探

新的语言 WWDC简短的介绍,新的语言Swift就问世了,虽然新语言的名字导致贴吧下歌手粉丝和开发者们争抢地盘- -,不过雨燕就是这么来了. WWDC keynote里给Swift打上了很多标签: Closures,Generics,Namespaces,Type inference,Multiple return types 闭包,泛型支持,支持命名空间,去除隐式类型转换,多返回值等这些优秀的特性让这门语言显得现代和便捷,再加上学习了很多其他语言类似Go,JavaScript等等的优秀语法,它

小试牛刀C#作为脚本语言执行解密

背景 我们知道Unity3d是通过C#脚本语言的形式来实现游戏的逻辑代码编写,同样SCOTT服务器也设置了通过C#脚本来实现游戏逻辑,但是本文并不是想真正分析解密他们的运行机制,只是想通过自己的一个需求,来探讨总结下其中的原理. 下面来说下我自己的需求,比较简单,由于经常在非开发环境部署一些小工具,做系统维护,但每次又懒得带笔记本和编译环境到现场,但系统数据又总是那么奇葩,时常有bug出现,突发奇想是否是能把工具做成脚本,这样现场就很容易进行调整(简单修改脚本),现场搞定不用来回折腾,岂不是很H

unity3d开发语言有哪些?用什么更好?

Unity3D是由Unity Technologies开发的一个全面整合的专业游戏引擎,软件集成了专业的渲染引擎和"所见即所得"的开发编辑界面,可快速创建具有强大视听效果的交互式3D内容.unity3d开发语言有哪些?unity3d开发语言用什么更好? 有以下三种可供选择的脚本编程语言:Java,C#以及Boo. 使用度更高的是前两种,需要说明的javascipt不是网页的那个javascipt,是Unity自己变化过后的一种语言. 尽管它们各有各的优势与不足,但通常来讲C#显然会脱颖

unity3d开发语言用哪个更好

Unity3D是由Unity Technologies开发的一个全面整合的专业游戏引擎,软件集成了专业的渲染引擎和"所见即所得"的开发编辑界面,可快速创建具有强大视听效果的交互式3D内容.unity3d开发语言用什么更好? 有以下三种可供选择的脚本编程语言:Java,C#以及Boo. 使用度更高的是前两种,需要说明的javascipt不是网页的那个javascipt,是Unity自己变化过后的一种语言. 尽管它们各有各的优势与不足,但通常来讲C#显然会脱颖而出成为大家的首选,首先它完整

java脚本语言学习心得

第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 好了,进入正题: 一 什么是脚本语言? 程序的运行方式有两种:编译运行和解释运行 1.1 前者的典型代表是java, 从文件角度看分为三步: write[编写]: a.java文件(拿个记事本就能写,扩展名是.java), compile[编译]: 编译(cmd命令是java a.java,ide集成了编译器运行之前自动编译)之后产生了a.class文件(是一堆二进制码,人看不懂,是给虚拟机看的) 运行[r

关于JS脚本语言的基础语法

JS脚本语言的基础语法:输出语法  alert("警告!");  confirm("确定吗?");   prompt("请输入密码");为弱类型语言: 开始时要嵌入JS代码:<script type="text/javascript"></script>: 关于写程序是需注意的基本语法:1.所有的字符全都是英文半角的:2.大部分情况下每条语句结束后要加分号:3.每一块代码结束后加换行:4.程序前呼后应:

shell、cmd、dos和脚本语言区别和联系

问题一:DOS与windows中cmd区别   在windows系统中,"开始-运行-cmd"可以打开"cmd.exe",进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部分,其中,Shell是操作系统与外部的主要接口,位于操作系统的外层,为用户提供与操作系统核心沟通的途径.在windows系统中见到的桌面即explorer.exe(资源管理器)是图形shell,而cmd就是命令行shell.这算是cmd与dos的最大区别,一个只是接口.

自动化运维脚本语言之expect实践学习(1)

一.expect简介 expect是一种简单的基于Tcl的脚本语言工具,一个可实现自动交互功能的软件套件,其功能就是进行自动化的人机交互:也能够按照脚本内容里面设定的方式与交互式程序进行"会话"的程序,根据脚本内容expect可以知道程序会提示或反馈什么内容以及什么是正确的应答:它是一种可以提供"分支和嵌套结构"来引导程序流程的解释型脚本语言. shell功能虽然强大,但是不能实现有交互功能的多机器之间的操作例如ssh和ftp,而expect可以帮助我们来实现. 主