unity 中favorate 中的all touchscript unity被删除了怎么办

Script属性是基于IDE的一系列编译器属性JS中用@script&属性方法()访问,c#中用[属性方法()]访问。一共就只有9种属性访问方式:
AddComponentMenu&&&&在Component菜单中添加新的菜单项
ContextMenu&&&&&&在当前脚本的组件中添加右键菜单内容
ExecuteInEditMode&&&&让当前脚本可以在运行模式中实时更新修改
HideInInspector&&&&&&&&是变量在检测时不被显示,但是会被实例化?
NonSerialized&&&&&&&标记一个变量不会被序列化?
RPC&&&&&&&&&&?
RenderBeforeQueues&&附加一个自定义渲染&在整个引擎渲染队列之前
RequireComponent&&&强制添加一个组件,(限定一定要有某个组件)
Serializable&&&&&&序列化一个类
---------------------------------------------------------------------------------------------------------------------------------------------------------------AddComponentMenu用法:@script&AddComponentMenu&("Transform/Follow&Transform")class&FollowTransform&:&MonoBehaviour{}用处:可以自己开发组件类,在菜单里往GameObject里添加组件实例。------------------------------------------------------------------------------------ContextMenu&用法:@ContextMenu&("Update&Waypoints")function&UpdateWaypoints(){}用处:使用当前脚本时候可以用右键菜单触发开发环境中运行的函数----------------------------------------------------------------------------------------ExecuteInEditMode&用法:@script&ExecuteInEditMode()用处:使当前脚本可以在运行中实时更新修改,每帧都会重新导入脚本,可以方便调试使用。----------------------------------------------------------------------------------------HideInInspector&用法:@HideInInspectorvar&p&=&5;用处:是变量在检测时不被显示,但是会被实例化??具体用处不详,猜测为在脚本外部变量设置的时候不会被显示,但是会被作用到-------------------------------------------------------------------------------------------NonSerialized&用处:标记一个变量不会被序列化。具体用处不详,我理解为不会被外部改变但是可以保持public状态-------------------------------------------------------------------------------------------RPC&&&&&&&&&&什么鬼东西-.-&RPC火箭筒?还是标记他用RPC协议传输?反正官网什么都没写。-------------------------------------------------------------------------------------------RenderBeforeQueues&&用法:@RenderBeforeQueues()function&OnRenderObject&(queue&:&int)&{//&do&some&custom&rendering...}用处:在引擎渲染之前添加一个自定义的渲染具体用法不详,里头能用什么东西渲染我也不清楚,还有那个参数我也没搞明白,以后用到再说吧--------------------------------------------------------------------------------------------RequireComponent&用法:js:@Script&RequireComponent(Rigidbody)&c#:[RequireComponent&(typeof&(Rigidbody))]用处:强制添加一个组件到这个object上,如果存在,则该组件不允许被删除。-------------------------------------------------------------------------------------------Serializable&&&&&&用法:js继承Object类默认就是会被序列化class&Test&extends&System.Object{var&p&=&5;var&c&=&Color.}var&test&=&Test&();//&C#&Example[System.Serializable]class&Test{public&int&p&=&5;public&Color&c&=&Color.}
阅读(...) 评论()TA的最新馆藏[转]&[转]&[转]&[转]&[转]&[转]&Unity3D中支持三种语言:JavaScript、C#、Boo,很多人不知道如何选择,通过这篇译文,我们可以搞清楚这三者语言的来龙去脉,对选择主语言有一定的借鉴意义。
首先,Unity是基于Mono也就是.Net的运行环境的,所以它肯定支持C#;然后,Unity团队自行开发了一种Boo的语言;后面可能考虑到用户的接受程度的问题,又开发了类似JS的一种语言,但那绝对不是JS,勉强可以称之为UnityScript。这三种语言的代码最后都会被编译执行,而且可以互相访问。
花了一上午,才译完,文章有点长,估计有耐心看完的都不多,呵呵。
一、Unity中的"JavaScript"与你所了解的JavaScript对比
#pragma strict
进行这样的声明,是一种很好的习惯,并且对于进行iOS开发来说也是必须的。 #pragma strict 意味着强制进行更严格的类型检测、尽早生成更多有用的错误信息、养成更好的编程习惯。
enum WeaponType {
var type : WeaponType = WeaponType.
这种方式更加简洁,并且是比使用字符串产生更少潜在错误的方法。
尽管Unity中的JavaScript尝试尽量做得至少某种程度上要像ECMAScript标准,但它与同样基于ECMAScript的JavaScript在其他实现方面有很多不同。也许它与微软的JScript更加相似,尤其是它们都是.NET平台上的语言。当然,Unity的JavaScript版本是自己独立开发实现的,并且两者之间也有很多不同之处。
Unity JavaScript 是编译型的,所以性能很高,但浏览器中的JavaScript是动态解释型的。
在Unity中,JavaScript、C#与Boo在运行速度上显然没有差异。它们各有优缺点,但速度上是一致的。
说明:如果你关注过浏览器之争的话,你应该知道现代浏览器中JavaScript已经不是简单的解释执行,而是以JIT方式编译执行。当然,肯定是不支持严格类型定义的。如果ECMAScript标准改成允许显示声明变量类型(像Adobe公司所提倡的,译注:其实个人觉得UnityScript更像是ActionScript3),JavaScript的性能还能以数量级的提升。尽管如此,现实是真正的JavaScript就算是拿Safari浏览器的Squirrelfish Extreme引擎进行测试,比Unity中的UnityScript仍要慢上两个数量级。
JavaScript中,如果你定义变量时不用var关键字,该变量将会作为全局变量处理。
function DoSomeStuff() {
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.
UnityScript中,没有.prototype那样混乱的写法。要定义类,你只要这样简单的定义:
var foo = "hello, world";
function doEet () {
// does nothing, intended to be overridden
编译器最后在编译之前会自动补全一些代码,构造一个完整的类定义结构。最终形式应该类似如下:
import UnityE
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中,你可以创建虚函数。
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"
可以很容易编写相互访问与调用的类,但还有一种方式可能比用对指定对象进行子类继承具有更好的维护性。
/* Foo.js */
var bar : B
function Start(){
bar = gameObject.GetComponent(Bar);
function doEet(){
// do my own thing
if( bar ){
bar.doEet();
/* Bar.js */
function doEet(){
// do something special
你在JavaScript所知道及喜欢的字符串函数都在,不同的是调用时首字母大写。
比如如何分割字符串,写法如下:
var qualifiedName = "System.Integer myInt";
var name = qualifiedName.Split(" "[0]);
分割后,name[1] 就包含"myInt"。
要查看可用的字符串函数清单,请访问Mono文档()
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: S // b is now a string variable, with no assigned value
b = "wilma";
var // c is now a dynamically typed variable with no assigned value
c = "barney";
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
a = "fred"; // works
a = 5; // works
方法名与类名一般是首字母大写的,除非当它们不是遵循这一原则的时候。这句话很矛盾。本质上,UnityScript是处在.NET的命名约定的环境 - 方法名采用CamelCase这种骆驼峰式及camelCase这种首字母大写的写法、属性采用骆驼峰式且首字母小写,但它也试着像JavaScript的写法 - 像C一样,严重分化成小写命名及camelCase骆驼峰式。
如 JavaScript 中, typeof("fred") == 'string', 但在Unity中你的写法是 var a: S
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.);
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等来配合实现。内部数组速度是最快的。
一般来说,贴入如下代码:
function y(){}
并保存到Foo.js文件中,等同于在该文件中输入如下代码:
class Foo extends MonoBehaviour {
function y(){}
但是,你可以在同一个文件中声明多个类,尤其是当你需要使用一些辅助工具类时非常有用,一般这种辅助类没有继承自MonoBehaviour。
class ButtonState {
var currentState :
var offset : Vector2;
如果你在一个文件中声明了MonoBehaviour的子类,但类名与文件名不匹配的话,即使是大小写不一致,你也会碰到麻烦。
一定要理解,当你在js文件中编写行为脚本是,你实际上在编写一个类:
a) 文件名就是类名,如果文件名是foo.js,你就可以在其他地方以var x = new foo()的格式进行调用;
b) 有一些特定的方法是实现系统预先定义的一些事件处理器,如Start、FixedUpdate等。任何事件中,声明的一个函数就是这个文件所代表的类的一个方法。
c) 文件中在函数定义之外编写的代码都在该类的范围之内执行,声明的变量也是该类的成员变量。
d) 类中的静态函数、变量本质上是类的方法与属性。
这种方式远比真正的JavaScript中实现的类来的更优雅,但某种程度上来说是限定你以更好的方式进行编码。
例如,创建一个行为脚本,命名为foo,那文件名就应该是foo.js。假设文件的内容如下:
public name : S // when you drag the behavior onto a gameobject, these values will be visible and editable
public age : // 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 : C // private members are NOT visible to other scripts, even if they have a reference to this object
public bestFriend : // 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 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()方法。
JavaScript中分号是可写可不写的,但在Unity中必须要写。
var foo = 3 // OK in JavaScript but an error in Unity
JavaScript的Math库在Unity中对应为Mathf库,并且方法名是首字母大写的,如Math.abs()在Unity中就应该是Mathf.Abs()。
UnityScript运行环境使用Mono - .NET的开源克隆。实际上,UnityScript是用Boo实现的,Boo是运行在Mono虚拟机上的一种语言,并且编译成本机代码。JavasScript很多典型的运行环境如String和Math库由Mono提供。你也就知道了为什么UnityScript中方法名要大写了,因为要与Mono中相同。
要使用Mono库,就需要导入它们,如:
import System.IO;
否则,你带指定完整的命名空间来调用函数,如System.IO.File.Open(),而不是File.Open()。
当Mono函数需要字符char作为输入参数时,你可以简单的使用索引来获取,比如你像将小写的a作为字符char a传递,你可以这样写:
如,当使用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库如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)编写。翻译:/p/3838619.html
阅读(...) 评论()1521人阅读
转载自/articles/179.html,写得实在太好
UnityScript(即javascript for Unity)的教程网上千千万,中文的也不少,但是讲Unity3D界面操作的多,讲UnityScript这个语言的少,同时对于UnityScript的描述部分,也是入门的教程多,对语言特性的描述少,能够成系统的我就根本没有找到过。连续的看了不少的Unity3D的文章,书籍,但是发现写代码的时候,对UnityScript的细节掌握仍然不甚了了,也就是对怎么写UnityScript效率更高,更加符合语言设计的目的,风格等事情并还没有清晰的认识。这个对于习惯写脚本的人来说,可能是常态,对于习惯C++我来说,简直难以忍受。
看到这样的名字,学过编程的人都知道我是模仿了经典的C语言教材,目的也是一样。,本文的目的不是再多写一个教程,而是希望对UnityScript这个语言进行一个较为深入细节,并且准确的描述。也就是说,相对于教程,本文会更加像一个语言说明书。同时,更不用说的就是,本文会甚少涉及Unity3D本身的界面操作,仅仅关注于UnityScript这个语言,不要希望通过本文学会Unity3D,但是,当你对Unity3D有了些基本的了解后,希望写一个大型游戏时,本文会对你该怎么写脚本,怎么写对脚本,怎么样写好脚本,并且避免掉进语言的陷阱中有一些帮助。
更进一步的说,因为UnityScript完全是Unity3D控制的语言,同时仅在Unity3D中可用,所以对于UnityScript来说,甚至于连哪些是属于语言本身的特性,哪些属于库的扩展,这些都分不清楚。这比Objective C还混乱……在Unity里面想要完全的区分开库和语言几乎不可能,但是本文还是会尽量做这方面的尝试,尽量将本文的主要关注点放在语言上,而不是库上。
一般的说法UnityScript是javascript for Unity,事实上,这个脚本语言更加接近JScript,这个MS发挥了其一贯不尊重标准本性做的javascript方言。甚至于,对JScript的风格更加喜欢,而抛弃了javascript本身的一些东西。这些事情,MS因为兼容性问题都没有敢做。当然,考虑到Unity的开发者使用了Mono这个开源的.Net,而不是诸如Java, Lua, Python等其他选择,说明Unity开发者有很强烈的MS向,这点也不让我感到意外。
Hello World
下面是经典Hello World程序的UnityScript代码
#pragma strict
function Start () {
print('Hello World\n');
在Unity的控制台上输出”Hello World”。需要注意的是,在Unity中创建该脚本后,需要绑定到某个GameObject中成为一个Script的组建(compent)后才能运行。
function Start() { code here… } 就是Unity里面用function关键字来定义新函数的方式。这个没有太多好讲的。
#pragma strict可以更加严格的进行静态类型检查,能够引导你更加好的写更加严谨和更好风格的代码,这个在后面还会再次提到,现在记得在开发的时候推荐都写上就行。
比较需要说明的是,一个UnityScript文件默认就是一个类,并且继承自MonoBehavior,类的名字就是文件名。以上的代码(假设保存在名为HelloWorld.js文件中)与下面的代码意义一模一样:
#pragma strict
class HelloWorld extends MonoBehaviour
function Start () {
print('Hello World\n');
其中MonoBehaviour是Unity内置的一个类,目前我们只需要知道其中Start函数和Update即可。Start函数能保证在第一次Update被调用前调用,Update函数就是游戏每帧调用的刷新函数。其中Update函数没有参数,可以通过读取Time.deltaTime变量来获得两次Update之间流逝的时间。
上面的代码同时展示了用class关键字定义新类,用extends关键字继承的方式。这个和C++,Java的语法很像,都是class-based的,这也是UnityScript不同于普通JavaScript,而更像JScript的地方。
这种类定义思维方式,使得从C++,Java过来的人更加能够上手。这可能是MS和Unity开发者都喜欢这种方式的原因。
在UnityScript中使用一个变量,遵循先定义后使用的原则。
如下代码首先定义了一个名为str的字符串,然后输出str的值。
#pragma strict
function Start () {
var hello : String = 'Hello';
var world : String = 'World';
print(hello + ' ' + world + '\n');
需要注意一下的是var hello : String这种语法,表示静态的指定hello这个变量名(上例中还有个变量world也是一样)的类型为String(UnityScript内建的字符串),这种使用方式效率最高,虽然在javascript中原来直接使用var hello = “Hello”;的方式也还可以使用,但是不建议使用。这个问题以后也还会提到。
下面看一个较为完整的例子,打印一个从华氏温度(Fahrenheit)到摄氏温度(Celsius)的转换表(来自于K&R page 19)
#pragma strict
function Start () {
/* defines */
var lower : float = 0;
var upper : float = 300;
var step : float = 20;
var fahr : float = // define and assign
var celsius :
while (fahr &= upper) { // while loop
celsius = (5.0f / 9.0f) * (fahr - 32.0f);
print(fahr + & & + celsius + &\n&);
fahr = fahr +
没有什么太多新内容,展示了新的UnityScript类型float,表示浮点数,还有while循环。还有,UnityScript支持C++所有的两种注释形式,意义和使用方式完全一样,这个就不多说了。
本节是属于为了完整性加的引导,下面开始上干货了~~~
UnityScript中包含的数值数据类型(指int,float等数值)和普通的javascript差异巨大,因为从效率和内存占用的双重考虑(游戏开发必须的),都比网页开发要严格的多,所以UnityScript事实是沿用了.Net的数值类型定义方式,并且这些基本类型(貌似)其实是使用了.Net的System库中的类型,所以实际类型是System.XXX,UnityScript提供的仅仅是一个缩写别名而已。
这种方式对数值的大小和范围进行了严格限定,并提供了丰富的数值数据类型(普通的javascript和很多脚本语言,为了方便理解,都将所有的数字归为统一的Number类型),具体的如下:
类型名(type name)
类型(type)
位数(width)
范围(range)
Unsigned integer
Signed integer
-128 ~ 127
Signed integer
-32,768 ~ 32,767
Unsigned integer
Signed integer
-2,147,483,648 ~ 2,147,483,647
Unsigned integer
Signed integer
-477508 ~ 477507
Unsigned integer
Single-precision floating point type
Double-precision floating point type
-1.32e308 ~ 1.32e308
A single Unicode character
Unicode Symbols
以上数值的定义完全是因为机器的表示实现导致的,所以虽然是.Net中的一套东西,但是和C++的数值体系几乎完全一致,只是把long作为单独的64位整数而已(JAVA早就这么做了)。
特别需要注意的是,UnityScript的char类型默认就是16位的,用于Unicode表示。
知道数值类型是这样的体系后,可以预想的是,其行为和C++里面完全一样,该有的溢出坑一个也不会少,运算时,各种类型转换复杂规则和各种转换带来的坑也少不了。好处当然就是速度及你能选择最合适大小的数值类型,在大规模数据保存的时候,可以省很多内容和磁盘。
需要顺面提到的一点是,所有的数值类型,其实自带一对内置的成员变量,MinValue和MaxValue,用于表示此类型可以表达的最小,最大值。
先看数值溢出的坑:
#pragma strict
function Start () {
var bytenumber : byte = 255;
var result : byte = bytenumber + 1;
print(&result=& + result);
上面的代码会输出0,从C++过来的人就不用惊讶了,也许仅了解Python,lua等脚本语言的人很难接受吧。具体的原因在于数值位表示的局限,当(上例中255的机器码)再加一的时候,已经没法再表达,变成了,即0.更多细节参考.类似的问题在符号类型的时候会更加让人惊讶,比如sbyte的&#再加1会等于-128。
再看类型转换的问题,一般而言,像C++这样的语言,很大程度上靠静态类型(编译期验错)来减少程序的bug,这在用户自定义的类上面,能起到很大的作用。但是对于数值运算来说,要是还是严格遵循类型定义,那么就会相当麻烦,想象一下一个两个整数想加,或者1个整数加1个浮点数时还必须用强制转换才能进行的情况,那样的表达式表达一个长的数学表达式简直就会是噩梦,(何况在UnityScript没有提供强制转换的方式)系统一般会提供一套各个数值类型之间运算时隐式转换(Implicit conversion)的规则,常见的规则是表达更大范围的数值类型进行转换,称为类型提升(type
promotion),int + long,转成long,以减少数值溢出的情况。
见下面的例子:
#pragma strict
function Start () {
var bytenumber : byte = 255;
var result = bytenumber + 1;
print(&result=& + result);
我仅仅把result的类型由Unity自动识别,程序就能正常输出256。也许有些人会奇怪,为什么不是0了?
print(“result type=” + result.GetType());
语句,我们能看到最后result的类型:
result type=System.Int32
result实际是int类型(在.net中的System.Int32),理由呢?就是类型自动提升,因为在bytenumber + 1的表达式中的整数常量1实际上就是int类型的,在byte类型的变量bytenumber与其相加时,bytenumber自动提升到int型,然后再进行运算,所以没有溢出。
到目前为止规则还好理解?看个不好理解的:
#pragma strict
function Start () {
var number : int = int.MaxV
var unsignedNumber : uint = 1;
var result = number + unsignedN
print(&result=& + result);
print(&result type=& + result.GetType());
在无符号和有符号运算时会发生什么?
结果输出:
result type=System.Int64
结果没有溢出,也没有把result改为uint(其实也不会溢出),而是直接换成了long(在.Net中用System.Int64表示)快晕了吗?这就是想要随心所欲的使用自己数值类型的代价。
我总结的转换倾向如下:
1.优先转为浮点类型
2.优先转为可表示数值范围大的类型
还有很多更值得琢磨的东西,浮点和整数一起运算的情况,仿照K&R,我这里给出一个详细规则:(自己研究的,目前不保证完全正确,假如有问题请提出来)
1.在比int更小(sbyte,byte,short,ushort)的整数类型之间进行运算时,都换成int类型进行运算。(此时肯定不会发生溢出)
2.int类型与比int小的整数类型间发生的运算,会将另外一个提升到int进行运算。(此时有可能发生溢出,从C语言继承过来的老规则,原因可能还是因为32位效率最高)
3.有符号和无符号的int类型发生计算提升到long。(此时肯定不会发生溢出)
4.在int和long,ulong之间发生的计算,提升int到long。(此时有可能发生溢出)
5.在long和ulong之间发生的计算,将ulong转为long。(此时有可能发生溢出)
6.在double参与的计算中, 将另一个数转为double。
7.在float参与的计算(另一个数不是double)中,将另一个数转为float。即时另一个数是比float宽度更大的long也是如此。
这里仅列出规则1的例子:
#pragma strict
function Start () {
var num1 : sbyte = 1;
var num2 : byte = 1;
var result = num1 + num2;
print(&result=& + result);
print(&result type=& + result.GetType());
result type = System.Int32
两点说明:
一、即使sbyte,byte相加时,short肯定能表示,但是还是会提升到int(类似越级),原因可能是因为int类型的运算在原来的32位机器上效率是最高的。
二、类型提升更会不会实际发生溢出没有关系,即使是1+1=2这样简单的运算,还是会进行类型提升,因为在运算前,编译器没法判断是否会发生溢出。
另外,除了这些基本的数值类型,还有以下类型:
类型名(type name)
类型(type)
位数(width)
范围(range)
Logical Boolean type
true or false
A sequence of characters
Base type of all other types
其中,boolean是布尔型,只能是是true和false,需要特别注意的是,布尔类型比C++的要严格,不能当作整形来计算。
然后,UnityScript虽然用的是.Net的数值类型,但是直接支持decimal这个精确浮点数类型,但是允许通过System.Decimal的形式使用。
Object类型是所有类型的基类,类似JAVA中的情况,这里不多说了,在类的部分会再次提到。
除此以外,UnityScript还提供了内置的数组及Array类型。这些以后会详细讲到。
字面常量(Literals)
在表达式中出现的整形常量,默认为int。
在表达式中出现的浮点型常量,默认为float。(这个需要特别注意)
但是可以像C++中那样,直接通过后缀指定常量的类型,但是可用的后缀比C++少很多,能用的后缀见下例:(还有其他的可以告诉我)
#pragma strict
function Start () {
// integer
var a = 10; // default is int
var b = 10l; // long
var c = 10e5; // float
print(&a's type=& + a.GetType());
print(&b's type=& + b.GetType());
print(&c's type=& + c.GetType());
var x = 10.0; // default is float
var y = 10.0f; // float
var z = 10.0d; // double
print(&x's type=& + x.GetType());
print(&y's type=& + y.GetType());
print(&z's type=& + z.GetType());
注释就是其实际类型,有些不一样的是浮点数默认为单精度浮点类型,不是C++中的double,好处是,将来可以少些很多f后缀……
赋值时的隐式类型转换
除了数值计算时会发生隐式转换外,赋值时,左右类型不一样的情况,也会发生隐式的类型转换,比如下例中:
#pragma strict
function Start () {
var x : char = 97;
var y : byte = 256;
print('x=' + x);
print('y=' + y);
97,256默认是int型,但是将其赋值给char,byte型时,进行了类型转换。在超出左边类型表达上限的情况时,会对右边的数值进行截断(truncation)操作。比如上例中,y会等于0.
与计算时的隐形转换有尽量提升类型,减少溢出的可能性相比,不管右边的数值是什么类型,是比等号左边的类型大,还是小,只要能进行有意义的转换,都会进行转换,即使是从大到小(此时发生截断)。
转换的规则和C++很类似
1.小数到整数直接去掉小数部分
2.从大的整数到小的整数发生截断,相当于直接忽略大整数中高位(小整数类型无法表示的部分)
讲到这里,顺面说条好的编程实践规则:
一般的计算仅使用有符号类型,仅在进行位运算时才使用无符号类型。
衍生出两条规则:
1.即使当1个变量从逻辑上来讲完全不可能是负,也使用有符号类型
2.即使当你发现有符号类型的上限快到了,希望扩充其上限,也不要使用将有符号类型改为无符号的方式,这种方式仅将上限扩充了一倍而已,要使用直接扩充到上1级类型的方式,即从short=&int,int=&long。
通过上面的类型转换规则可以看到,这样的使用方式可以避免出现同类型有符号和无符号计算的情况,可以避免很多类型的转换和提升,对数值的溢出判断也更加直接一些。
UnityScript中使用了final关键字用于表示常量,同时,我们可以以全大写的惯例来表示常量。有意思的是,我以前从来没在文档中看到过Unity3D开发组对final的描述。
其中总的来说,UnityScript对数据类型的处理和C++很相似,有的地方甚至更加严格,并且完全不支持任何C/C++,C#里面那种类型加括号方式的强制类型转换,所以还算比较好理解。就是表达方法上为了接近javascript(实际上和JScript一样),总是以var开头,导致每个变量的定义都会多敲6次键盘,(为了好看,我一般还需要加一些空格,例子中都是)这个算是挺烦人的事情。
表达式和操作符
Javascript是面向表达式(Statement)的语言,这个就像我们熟悉的绝大部分语言一样,每个表达式用分号(;)结尾,并且这个分号不能忽略。(和javascript不一样)
去掉了undefined和Nah
UnityScript去掉了javascript中的和undefined,NaN,只有null,用于表示空对象。见下例:
#pragma strict
function Start () {
这个例子,在C++中根本就无法编译通过,但是UnityScript可以,同时,不会像javascript一样输出undefined,而是输出null。
UnityScript也没有Nah类型,直接在代码中存在的除0表达式会出现编译错误,运行时出现除0操作,会出现运行错误,不会有Nah值出现的情况。
数值转换
UnityScript拥有parseInt()和parseFloat()这两种javascript的数值转换函数,Number()实际等于double类型,不再做此用途。
而且parseInt函数实际是System.Int32.Parse (System.String s)函数,不像javascript中那样’灵活’的容错,不识别任何格式,需要完全是整数才能识别,意味着类似”1234blue”,”0×10”这种格式会出现运行错误。并且不带第二参数(javascript中用第二参数来表示进制)。
parseFloat也换成了System.Single.Parse (System.String s)函数,也没有javascript中那样的灵活性。不支持任何格式。
#pragma strict
function Start () {
var b = byte.Parse('256');
数值运算操作符
支持+,-,*,/,%,++, –
数值运算操作符,完全和C++及大多数语言里面的意义一模一样,不介绍了。
赋值操作符
除了=外,C++中有的两元赋值操作符(*=等),都存在,不介绍了。
&, |, ~, ^,&&,&&和C++里面一模一样,不介绍了。只要知道不支持javascript里面的无符号位移&&&,&&&就好了。因此,编程实践方面,最好也是和C++一样,进行位移操作的最好是无符号整数。
比较操作符
&,&,&=,&=,==,!=
需要注意的是没有javascript的严格比较===,因为类型本来就是相对确定的,同时在==比较时,不会进行javascript中那么多的类型转换。
比如下例:
#pragma strict
function Start () {
if ( 42 == '42' ) {
print(&42 == '42'&);
print(&42 != '42'&);
输出42 != ‘42’
这样结果会让习惯javascript的人感到意外,同时也会让习惯C++的感到意外,42和’42’竟然能够比较….-_-!我前面说UnityScript的类型有时候比C++要严格,注意,也就是有时候。不过,好在UnityScript中数值和字符串发生比较时,不会将字符串转换为整数后再比较,而是判断类型不一样,导致结果为假。这比javascript已经和好多了。
在不同类型发生比较时,也会发生类型转换。和计算是发生的事情类似,但是因为类似的转换放到逻辑操作中较少会出现意外,这里不详细描述了。
原生类型及引用类型
一般的语言中都会分原生类型和引用类型,比如在JAVA中,你比较两个字符串类型的变量,要是直接使用==操作符,其实比较的是两个变量指向的是否是同一个字符串,而不是判断两个字符串是否相等,需要使用单独的Equal函数,这个问题在C++比较char[]时也存在(因为C++的操作符重载的存在,将std::string的==比较操作符重载了)
UnityScript使用的方式还是类似的,前面提到的那些数值类型,一如既往的是原生类型,只是,特别注意的是,String被认为是原生类型,也就是说,在两个String进行比较时,比较的就是String的内容,而不是引用地址。见下面的代码:
var str1 : String = 'abc';
var str2 : String = 'abc';
if (str1 == str2) {
print('str1 == str2');
上面代码会输出str1==str2
而在比较其它的对象类型的时候,比较就是引用地址了。比如下例中:
var str1 : Array = ['a', 'b', 'c'];
var str2 : Array = ['a', 'b', 'c'];
if (str1 == str2) {
print('str1 == str2');
str1是不等于str2的….比较有意思的是,Array类型还提供了一个Equals函数,其实比较的也是引用地址,这个简直就是天坑。
在查找那么到底两个Array应该怎么比较的时候,发现了,那就是比较两个对象ToString以后的结果。我只能说,想出用这种办法来比较Array的人简直就是神。
#pragma strict
function ToString() {
return i.ToString();
function Start () {
var obj : C = new C();
obj.i = 1;
var str1 : Array = [obj, 'b', 'c'];
var obj2 : C = new C();
obj2.i = 2;
var str2 : Array = [obj2, 'b', 'c'];
print(obj.ToString());
if (str1.ToString() == str2.ToString()) {
print('str1 == str2');
print('str1 != str2');
这种比较在数组元素是简单类型时,一定正确,但是存储对象时,要对对象也有正确的ToString实现,不然结果可能会不正确。
这里还有个有意思的地方,在javascript的习惯里面,对象会有个ToString函数,而在C#的习惯里面,对象会有个toString函数,注意,两个函数的首字母大小写不一样,作为UnityScript,在mono这个开源.Net平台上自创的javascript语言,在使用.Net类的时候(比如上面的Array)两者都有!并且功能完全一样!这个实在是太丑陋了。
这里总结一下,上面提到的所有数值类型都是原生类型,再加上String,它们的比较都是通过比较值的方式,同时,在函数传参的时候,也是传值(意味着有复制的发生),其他的,包括原生数组,其他的对象,都是比较引用地址,在传参数的时候也是传引用地址,也就是说,没有内容复制的发生,同时,对引用地址变量的任何更改都是更改了原对象,见下例,用一个原生数组作为示例:
#pragma strict
function Start () {
var array : int[] = [1, 1, 2];
var array2 : int[] = new int[3];
array2[0] = 0;
array2[1] = 1;
array2[2] = 2;
if (ArrayUtility.ArrayEquals(array, array2)) {
print('array == array2');
print('array != array2');
#pragma strict
function changeStr( str : char[] ) : char[] {
str[0] = 'b'[0];
function Start () {
var str : char[] = [ 'a'[0], 'b'[0], 'c'[0] ];
changeStr(str);
print( Array(str) );
最后输出的是b,b,c,因为在changeStr里面对参数str的更改,实际更改了外部的str,这个C++及其他语言中见得多了,不再过多描述。
逻辑操作符
像C++一样,也有逻辑截断效果,当前面的操作可以确认结果时,后面的操作不再进行。
这里需要注意的是在UnityScript中,什么样的值会是true,什么样的值会是false:
false: 空字符串,0, null
true: 任何对象,非空字符串,非0数字
条件判断操作符
?:三目操作符UnityScript也支持,和C++一样
操作符优先级
操作符计算顺序和C++也完全一样,也没有理由不一样,不介绍了。
语句和控制结构
这是最没有什么好讲的一节。需要理解的是在UnityScript中变量的scope和C++不一样。
比如下面的代码:
#pragma strict
function Start () {
for (var i : i & 10; ++i) {
for(var m : m & 10; ++m) {
// still could read i
你会发现在第二个循环里面还能够读取到第一个循环里面的变量i,这种方式对于习惯了C++的人来说是个大坑,也就是说UnityScript中的局部变量不像C++中习惯的那个样子,UnityScript没有块级作用域(这个奇怪的特性来自于标准的javascript,不明白UnityScript为什么不改了)
其他的诸如if,else等条件控制,while,do-while,for等循环的代码和C/C++一样,不介绍了。
首先介绍一下for-in,for-in就是通常意义的foreach循环,直接遍历整个容器。
#pragma strict
function Start () {
var charArray : char[] = new char[10];
for (var i : i & 10; ++i) {
charArray[i] = 97 +
for(var value in charArray) {
print(value);
直接遍历整个容器算是语法糖,但是从抽象上来说的确比通常的for层次更高,也更难用错。
switch多条件控制
UnityScript的switch本质上和C/C++中的一样,但是有些加强,那就是case不再是仅可使用数值,甚至可以是变量,这个的确很强大,很多复杂情况的if-else都可以被替代了。
#pragma strict
function Start () {
var num : float = 10.0;
var numEqual : int = 10;
switch (num) {
case (num & 10.0):
print('num & 10.0');
case (num & 10.0):
print('num & 10.0');
case numEqual:
print('num == numEqual');
上例中会输出num == numEqual,这么复杂的条件判断,在C/C++中是不允许的。
函数,Lambda和闭包
函数里面值得研究的东西就多了,也是UnityScript中最有意思的部分,没有之一。这也是UnityScript作为从javascript过来的最大特点之一,javascript可是号称函数式编程的语言。
作为最大的特点,函数本身就是一个Function类型的对象,不是什么特殊的种类,也称函数为第一类值。此时函数可以像普通变量一样的操作,甚至从外部看不知道这是函数,并且还能随时调用。
首先看函数的定义,前面讲过一下,下面这个函数定义带参数和返回值:
function sum(num1 : float, num2 : float) : float {
return num1 + num2;
并且,和下面的定义方式没有区别:
var sumFun : Function = function(num1 : float, num2 : float) : float {
return num1 + num2;
也看赋值和传递:
var sumFun2 : Function = sumF
调用sumFun2和调用sum,sumFun是一样的效果。
函数作为参数
函数是第一类值,也就是说可以想变量一样使用,那么,参数也可以是函数,见下面的例子:
#pragma strict
function Start () {
var sum = function(num1 : float, num2 : float) : float {
return num1 + num2;
var call : Function = function( fun : Function, num1 : float, num2 : float, num3 : float ) : float {
return fun(fun(num1, num2), num3);
print(call(sum, 1.0, 2.0, 3.0));
在C++11中,Function,Bind库是最让我高兴的扩展,这在UnityScript中是语言本身的特性。
函数作为返回值
当函数作为第一类值的时候,函数甚至可以作为返回值返回,也就是说,可以实现一个返回值是函数的函数。见下例:
#pragma strict
function Start () {
var multipleFun : Function = function() {
return function(num1 : float, num2 : float) : float {
return num1 * num2;
var call : Function = function( fun : Function, num1 : float, num2 : float, num3 : float ) : float {
return fun(fun(num1, num2), num3);
print(call(multipleFun(), 1.0, 2.0, 3.0));
multipleFun返回一个函数,再作为call函数的参数传进call函数。
另外,虽然这些特点和javascript的函数特点一样,但是在UnityScript中函数不再有默认的内部属性,很大原因是因为UnityScript不再依靠函数来完成对象的设计,所以更改了这部分的设计,让函数更加的纯粹,没有了arguments属性,稍微有些遗憾。
函数的重载
javascript没有函数的重载,这个很好理解,因为函数的参数都是var,没有重载的太大必要,但是UnityScript中可以直接指定参数的类型,那么重载就有一定必要了,事实上,UnityScript实现了函数的重载:
#pragma strict
function sum( num1 : int, num2 : int) : int {
return num1 + num2 + 1;
function sum( num1 : float, num2 : float) : float {
return num1 + num2 + 2;
function Start () {
print(sum(1, 1)); // call sum( num1 : int, num2 : int) : int
print(sum(1.0, 1.0)); // call sum( num1 : float, num2 : float) : float
print(sum(1.0, 1)); // call sum( num1 : float, num2 : float) : float/
如上代码,会输出3,4,4,正确的匹配了合适的函数,并且在出现二义性的时候,进行了类型提升,第三个sum的调用也调用了浮点数的那个。这种类型提升多恰当其实也说不上,在C++中这是会出现二义性编译错误的 ,但是总得来说还是较为符合预期,毕竟和计算时的提升方式类似。稍微提及一点,在UnityScript中,函数的参数个数要求是严格的(编译期检查),不像javascript中那种参数个数不够也能调用。
UnityScript支持匿名函数,即我们常说的Lamda函数,简单的说就是没有名字的函数,说来简单,其实作用挺强大的。
在本节前面的例子中
function sum(num1 : float, num2 : float) : float {
return num1 + num2;
var sumFun : Function = function(num1 : float, num2 : float) : float {
return num1 + num2;
两种定义函数的方式其实是有些区别的,前一种是在当前作用域中定义了一个名为sum的函数,这在程序编译时就确定了,在代码执行之前就已经加载到作用域了,无论你在这个作用域的哪个地方都能直接调用,而后一种定义方式,实际上是先定义了一个匿名的函数,然后将匿名的函数赋给变量sumFun,只在这一行代码在运行时被执行后才有效。
在前面例子里面的call函数,也可以用Lambda函数调用:
function Start () {
var call : Function = function( fun : Function, num1 : float, num2 : float, num3 : float ) : float {
return fun(fun(num1, num2), num3);
print(call(function(num1 : float, num2 : float) { return num1 + num2; }, 1.0, 2.0, 3.0));
对于只使用一次的函数来说,这样做更加便捷,并且还少费一个变量~~也许对于这个例子,这么调用没有太大必要,但是在大规模的使用函数作为参数的情况下,这样的简化就会带来很大的意义,当然,那就看你的编码思维是函数式的还是JAVA,C++那样面向对象的方式了,要是一直习惯使用C++,可能都不会有把函数作为参数的抽象思维,那样,这样的代码你写几W行代码都不会碰到。相对来说,因为UnityScript中去掉了很多与函数编程相关的便捷方法(类似map,filter等),使得用函数编程的方式成本偏高,所以按照C++的思维来写UnityScript,完全是靠谱的。
这里有个UnityScript很大的特点需要注意,那就是不支持函数内的函数定义,但是支持函数定义表达式。也就是说
function fun1() {
//function fun2() {
// not support
var fun2 : Function = function() {
return fun2;
上例中,被注释掉的第一个fun2的定义方式不被UnityScript支持,而第二种方式是支持的,虽然我们现在已经知道了,这两种方式其实没有啥区别,但是,UnityScript就是有这么诡异的情况……
虽然在Python和Lua中都接触过闭包,大概明白什么回事,但是要从概念到细节的描述,我感觉自己还是不太明白,于是查了下网络,发现我最喜欢的两个博客,阮一峰和酷壳上正好有两篇文章,作为入门,概念讲解的清楚,,细节描述的到位准确,关于闭包的概念,我发现我只需要发两个链接就够了。
UnityScript中类的使用方式没有用javascript中较为别扭的prototype方式,(说prototype别扭会有人来喷我吗?-_-!)而是选择了JScript中MS加入的class-base方式,这种方式前面讲过一些,事实上和C++的比较像。下面看稍微复杂些,带继承的情况。
#pragma strict
class Base
public var x :
protected var y :
private var z :
function Base() {
function PrintToOverride() {
Debug.Log('x=' + x + ',y=' + y + ',z=' + z);
final function PrintCantOverride() {
Debug.Log('x=' + x + ',y=' + y + ',z=' + z);
class Derived extends Base
//public var x :
//protected var y :
private var z :
function Derived() {
function PrintToOverride() {
super.PrintToOverride();
Debug.Log('x=' + this.x + ',y=' + this.y + ',z=' + this.z);
function Start () {
var base : Base = new Derived();
base.PrintToOverride();
base.PrintCantOverride();
能想到的情况上面的例子中都展示了,包括和C++一样的构造函数,丰富的访问控制(public,protected,private),和Java一样的默认全虚函数,final定义不可override的非虚函数,用super关键字调用父类的对象。其中PrintToOverride函数就是在Derived类中重载了Base类中的同名函数,并且调用了基类的同名函数。
有个小细节需要注意,z这个变量在Base中是private的变量,因为在Derived中完全不可见,在Derived类中还可以重复定义,但是public的x和protected的y是不能在Derived中重新定义的,这个比C++要严格,在C++中是可以通过this指针来进行区别的,当然,就算真的可以,比如z,也完全不推荐大家去定义重名变量。可以看看上例中输出的结果有没有超过你的预期,要是超过了的话,更加应该把不定义重名变量作为规则来遵守。
这部分UnityScript的设计基本来自于JScript的class-base object创建方式。类似面向对象的一般思维。在第一节就讲过一些基本的东西了,这里不做重复的叙述。
数组和字符串
Unity中有两种数组,一种是原生数组(Buildin array),类似C/C++中原生数组的使用方式。
function Start () {
var str : char[] = new char[10];
for (var index = 0; index & str. ++index) {
str[index] = 97 +
for (var printIndex = 0; printIndex & str. ++printIndex) {
print(str[printIndex]);
会依次输出a,b,c….
需要注意的是,即使是内置数值,其实也还带名为length的成员变量,表示数组的长度。(这是C/C++ coder多年的梦想)
因为原生数组是类型安全的,并且效率很高,内存占用很少,在需要不是频繁增删的容器时,优先考虑的应该是UnityScript的原生数组,比如游戏的配置读取后的结构。
这个是一个奇怪的特性,用逗号来分割维度,没有使用C/C++中[ ][ ][ ]的方式。
function Start () {
var multidim : double[,,] = new double[5,4,3]; // three dimension
multidim[0, 0, 0] = 1;
在UnityScript可以直接使用.Net中的所有容器,还有Array这个javascript的数组。
Array算是UnityScript中最乱的类了,一方面为了照顾javascript的习惯,函数需要以小写开头,一方面还要照顾自己的习惯,函数又要用大写开头,于是乎,UnityScript两者都保留了,因为我对javascript没有什么感情,推荐碰到类似的情况一律使用大写开头的函数。
因为Array来自于javascript,不是一个类型安全的容器,不推荐使用。推荐使用.Net的ArrayList等容器替代。当你确定需要一个类型不确定的容器时,才使用Array。Unity的Script Reference对Array有足够的描述,这里就不多介绍了。
在UnityScript中,用char(见上表)来表示字符,并且默认支持Unicode。
在C/C++中,常用char[]来表示字符串。并且字面常量无论是用双引号”,还是用单引号’,表示的都是字符串,而不像C++中用”表示字符串,用’表示字符。实在在需要字符的时候,这里有个hack,那就是使用’a’[0]的形式…….这么扭曲的方法,来自,见下面的代码:
var str : char[] = [ 'a'[0], ‘b’[0], ‘c’[0] ];
上面讲到做,char默认保存的就是Unicode的值,可以完美支持中文。见下例:
#pragma strict
function Start () {
var str : char[] = [ '中'[0], '国'[0] ];
var value0 : int = str[0];
var value1 : int = str[1];
print( Array(str) );
print( str[0] + & & + str[1] );
print( value0 + & & + value1 );
倒是monoDevelop对中文支持的不是很好,不能输入中文,上面的代码在其他地方编辑后,在Unity中运行正常。
5.The C Programming Language
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:60691次
排名:千里之外
原创:25篇
转载:22篇
评论:10条
(2)(5)(3)(3)(1)(4)(1)(2)(1)(1)(2)(2)(2)(5)(5)(4)(4)

我要回帖

更多关于 unity3d scriptobject 的文章

 

随机推荐