收藏 分享(赏)

讲稿(五) unity脚本语法.doc

上传人:11xg27ws 文档编号:7846512 上传时间:2019-05-27 格式:DOC 页数:37 大小:163.50KB
下载 相关 举报
讲稿(五) unity脚本语法.doc_第1页
第1页 / 共37页
讲稿(五) unity脚本语法.doc_第2页
第2页 / 共37页
讲稿(五) unity脚本语法.doc_第3页
第3页 / 共37页
讲稿(五) unity脚本语法.doc_第4页
第4页 / 共37页
讲稿(五) unity脚本语法.doc_第5页
第5页 / 共37页
点击查看更多>>
资源描述

1、(五)游戏开发平台 (1)游戏开发平台的种类(2)各种游戏开发平台的适用范围(3)各种游戏开发平台介绍,如 Torque,Unreal,Unity(4)游戏开发平台 Unity 的基本操作 ,游戏开发平台 Unity 的脚本(5)三维模型在游戏开发平台中的使用(6)游戏开发平台的各种元素:GUI,地形引擎,刚体,碰撞器,粒子系统等(7)人工智能(8)FPS 游戏案例分析Unity 脚本语法#pragma strict,#pragma downcast、#pragma implicit在一些 Unity 脚本的开始经常可以看到 #pragma strict,#pragma downcast、#p

2、ragma implicit 指令,而有的 Unity 脚本则没有这些指令,那这些指令有什么作用呢?#pragma strict,此指令的含义是强制输入,也就是我们在声明变量时,需要精确的声明变量是什么类型,而不是让编译器来自己推测变量的类型,因此,也不能随便的使用一个随机的名称并让编译器来为你实例化此变量。例如,在使用此指令后,我们随意声明一个变量:private var bobby;/是不可以的,而需要这样:private var bobby : GameObject;/这个可以 通过使用#pragma strict,可以强制我们养成良好的编程习惯,但这在 Unity 中也不是必须要这样做

3、。而#pragma downcast 和#pragma implicit 指令,则是可以与 #pragma strict 指令搭配使用,从而做到“严中有松” ,真是有点意思。先看#pragma implicit 指令,它的意思是在使用#pragma strict 指令,搭配此指令又可以含蓄的声明变量,例如:#pragma strictfoo = 5; / 不可以#pragma strictvar foo = 5; /可以#pragma strict#pragma implicitfoo = 5; / 通过使用#pragma implicit,此句是可以的。而#pragma downcast 语

4、句则允许在使用#pragma strict 指令时,使变量可以从 super(父类型)到 sub(子)类型的转换,例如:#pragma strictvar go : GameObject;var clone : GameObject = Instantiate(go); /此语句是不可以的,因为 Instantiate 后返回/的物体类型是 Object,而不是 GameObject#pragma strict#pragma downcastvar go : GameObject;var clone : GameObject = Instantiate(go); /此语句是可以的,使用了 #p

5、ragma downcast下面的语句也是可以的:#pragma strictvar go : GameObject;var clone : GameObject = Instantiate(go) as GameObject; /此语句也是可以的,因为使/用了类型转换 as。UnityScript 程序设计语言UnityScript(即 javascript for Unity)的教程网上千千万,中文的也不少,但是讲 Unity3D 界面操作的多,讲 UnityScript 这个语言的少,同时对于 UnityScript 的描述部分,也是入门的教程多,对语言特性的描述少,能够成系统的我就根本

6、没有找到过。连续的看了不少的 Unity3D 的文章,书籍,但是发现写代码的时候,对 UnityScript 的细节掌握仍然不甚了了,也就是对怎么写 UnityScript 效率更高,更加符合语言设计的目的,风格等事情并还没有清晰的认识。这个对于习惯写脚本的人来说,可能是常态,对于习惯C+我来说,简直难以忍受。看到这样的名字,学过编程的人都知道我是模仿了经典的 C 语言教材,目的也是一样。,本文的目的不是再多写一个教程,而是希望对 UnityScript 这个语言进行一个较为深入细节,并且准确的描述。也就是说,相对于教程,本文会更加像一个语言说明书。同时,更不用说的就是,本文会甚少涉及 Uni

7、ty3D 本身的界面操作,仅仅关注于 UnityScript 这个语言,不要希望通过本文学会 Unity3D,但是,当你对 Unity3D 有了些基本的了解后,希望写一个大型游戏时,本文会对你该怎么写脚本,怎么写对脚本,怎么样写好脚本,并且避免掉进语言的陷阱中有一些帮助。更进一步的说,因为 UnityScript 完全是 Unity3D 控制的语言,同时仅在 Unity3D 中可用,所以对于 UnityScript 来说,甚至于连哪些是属于语言本身的特性,哪些属于库的扩展,这些都分不清楚。这比 Objective C 还混乱在 Unity 里面想要完全的区分开库和语言几乎不可能,但是本文还是会

8、尽量做这方面的尝试,尽量将本文的主要关注点放在语言上,而不是库上。概述一般的说法 UnityScript 是 javascript for Unity,事实上,这个脚本语言更加接近JScript,这个 MS 发挥了其一贯不尊重标准本性做的 javascript 方言。甚至于,对JScript 的风格更加喜欢,而抛弃了 javascript 本身的一些东西。这些事情,MS 因为兼容性问题都没有敢做。当然,考虑到 Unity 的开发者使用了 Mono 这个开源的.Net,而不是诸如 Java, Lua, Python 等其他选择,说明 Unity 开发者有很强烈的 MS 向,这点也不让我感到意外。

9、Hello World下面是经典 Hello World 程序的 UnityScript 代码#pragma strictfunction Start () print(Hello Worldn);在 Unity 的控制台上输出”Hello World”。需要注意的是,在 Unity 中创建该脚本后,需要绑定到某个 GameObject 中成为一个 Script 的组建(compent)后才能运行。function Start() code here 就是 Unity 里面用 function 关键字来定义新函数的方式。这个没有太多好讲的。#pragma strict 可以更加严格的进行静态类

10、型检查,能够引导你更加好的写更加严谨和更好风格的代码,这个在后面还会再次提到,现在记得在开发的时候推荐都写上就行。类比较需要说明的是,一个 UnityScript 文件默认就是一个类,并且继承自 MonoBehavior,类的名字就是文件名。以上的代码(假设保存在名为 HelloWorld.js 文件中)与下面的代码意义一模一样:#pragma strictclass HelloWorld extends MonoBehaviourfunction Start () print(Hello Worldn);其中 MonoBehaviour 是 Unity 内置的一个类,目前我们只需要知道其中

11、Start 函数和Update 即可。Start 函数能保证在第一次 Update 被调用前调用,Update 函数就是游戏每帧调用的刷新函数。其中 Update 函数没有参数,可以通过读取 Time.deltaTime 变量来获得两次 Update 之间流逝的时间。上面的代码同时展示了用 class 关键字定义新类,用 extends 关键字继承的方式。这个和C+,Java 的语法很像,都是 class-based 的,这也是 UnityScript 不同于普通JavaScript,而更像 JScript 的地方。这种类定义思维方式,使得从 C+,Java 过来的人更加能够上手。这可能是 M

12、S 和 Unity 开发者都喜欢这种方式的原因。变量在 UnityScript 中使用一个变量,遵循先定义后使用的原则。如下代码首先定义了一个名为 str 的字符串,然后输出 str 的值。#pragma strictfunction Start () var hello : String = Hello;var world : String = World;print(hello + + world + n);需要注意一下的是 var hello : String 这种语法,表示静态的指定 hello 这个变量名(上例中还有个变量 world 也是一样)的类型为 String(UnitySc

13、ript 内建的字符串),这种使用方式效率最高,虽然在 javascript 中原来直接使用 var hello = “Hello”;的方式也还可以使用,但是不建议使用。这个问题以后也还会提到。下面看一个较为完整的例子,打印一个从华氏温度(Fahrenheit)到摄氏温度(Celsius)的转换表(来自于 Kvar upper : float = 300;var step : float = 20;var fahr : float = lower; / define and assignvar celsius : float;while (fahr int,int=long。通过上面的类型转换

14、规则可以看到,这样的使用方式可以避免出现同类型有符号和无符号计算的情况,可以避免很多类型的转换和提升,对数值的溢出判断也更加直接一些。常数变量UnityScript 中使用了 final 关键字用于表示常量,同时,我们可以以全大写的惯例来表示常量。有意思的是,我以前从来没在文档中看到过 Unity3D 开发组对 final 的描述。其中总的来说,UnityScript 对数据类型的处理和 C+很相似,有的地方甚至更加严格,并且完全不支持任何 C/C+,C#里面那种类型加括号方式的强制类型转换,所以还算比较好理解。就是表达方法上为了接近 javascript(实际上和 JScript 一样),总

15、是以 var 开头,导致每个变量的定义都会多敲 6 次键盘,(为了好看,我一般还需要加一些空格,例子中都是)这个算是挺烦人的事情。表达式和操作符Javascript 是面向表达式(Statement)的语言,这个就像我们熟悉的绝大部分语言一样,每个表达式用分号(;)结尾,并且这个分号不能忽略。(和 javascript 不一样)去掉了 undefined 和 NahUnityScript 去掉了 javascript 中的和 undefined,NaN,只有 null,用于表示空对象。见下例:#pragma strictfunction Start () var x;print(x);这个例子

16、,在 C+中根本就无法编译通过,但是 UnityScript 可以,同时,不会像javascript 一样输出 undefined,而是输出 null。UnityScript 也没有 Nah 类型,直接在代码中存在的除 0 表达式会出现编译错误,运行时出现除 0 操作,会出现运行错误,不会有 Nah 值出现的情况。数值转换UnityScript 拥有 parseInt()和 parseFloat()这两种 javascript 的数值转换函数,Number()实际等于 double 类型,不再做此用途。而且 parseInt 函数实际是 System.Int32.Parse (System.S

17、tring s)函数,不像javascript 中那样灵活的容错,不识别任何格式,需要完全是整数才能识别,意味着类似”1234blue”,”010”这种格式会出现运行错误。并且不带第二参数(javascript中用第二参数来表示进制)。parseFloat 也换成了 System.Single.Parse (System.String s)函数,也没有 javascript中那样的灵活性。不支持任何格式。#pragma strictfunction Start () var b = byte.Parse(256);print(b);数值运算操作符支持+,-,*,/,%,+, 数值运算操作符,完

18、全和 C+及大多数语言里面的意义一模一样,不介绍了。赋值操作符除了=外,C+中有的两元赋值操作符(=等),都存在,不介绍了。位操作符break;case numEqual:print(num = numEqual);break;default:break;上例中会输出 num = numEqual,这么复杂的条件判断,在 C/C+中是不允许的。函数,Lambda 和闭包函数里面值得研究的东西就多了,也是 UnityScript 中最有意思的部分,没有之一。这也是 UnityScript 作为从 javascript 过来的最大特点之一,javascript 可是号称函数式编程的语言。作为最大的

19、特点,函数本身就是一个 Function 类型的对象,不是什么特殊的种类,也称函数为第一类值。此时函数可以像普通变量一样的操作,甚至从外部看不知道这是函数,并且还能随时调用。首先看函数的定义,前面讲过一下,下面这个函数定义带参数和返回值:function sum(num1 : float, num2 : float) : float return num1 + num2;并且,和下面的定义方式没有区别:var sumFun : Function = function(num1 : float, num2 : float) : float return num1 + num2;也看赋值和传递:v

20、ar sumFun2 : Function = sumFun;调用 sumFun2 和调用 sum,sumFun 是一样的效果。函数作为参数函数是第一类值,也就是说可以想变量一样使用,那么,参数也可以是函数,见下面的例子:#pragma strictfunction Start () var sum = function(num1 : float, num2 : float) : float return num1 + num2;var call : Function = function( fun : Function, num1 : float, num2 : float, num3 :

21、float ) : float return fun(fun(num1, num2), num3);print(call(sum, 1.0, 2.0, 3.0);在 C+11 中,Function,Bind 库是最让我高兴的扩展,这在 UnityScript 中是语言本身的特性。函数作为返回值当函数作为第一类值的时候,函数甚至可以作为返回值返回,也就是说,可以实现一个返回值是函数的函数。见下例:#pragma strictfunction Start () var multipleFun : Function = function() return function(num1 : float,

22、 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 的函数特点一样,但是在 UnityS

23、cript 中函数不再有默认的内部属性,很大原因是因为 UnityScript 不再依靠函数来完成对象的设计,所以更改了这部分的设计,让函数更加的纯粹,没有了 arguments 属性,稍微有些遗憾。函数的重载javascript 没有函数的重载,这个很好理解,因为函数的参数都是 var,没有重载的太大必要,但是 UnityScript 中可以直接指定参数的类型,那么重载就有一定必要了,事实上,UnityScript 实现了函数的重载:#pragma strictfunction sum( num1 : int, num2 : int) : int return num1 + num2 + 1

24、;function sum( num1 : float, num2 : float) : float return num1 + num2 + 2;function Start () print(sum(1, 1); / call sum( num1 : int, num2 : int) : intprint(sum(1.0, 1.0); / call sum( num1 : float, num2 : float) : floatprint(sum(1.0, 1); / call sum( num1 : float, num2 : float) : float/如上代码,会输出 3,4,4,

25、正确的匹配了合适的函数,并且在出现二义性的时候,进行了类型提升,第三个 sum 的调用也调用了浮点数的那个。这种类型提升多恰当其实也说不上,在 C+中这是会出现二义性编译错误的 ,但是总得来说还是较为符合预期,毕竟和计算时的提升方式类似。稍微提及一点,在 UnityScript 中,函数的参数个数要求是严格的(编译期检查),不像 javascript 中那种参数个数不够也能调用。LamdaUnityScript 支持匿名函数,即我们常说的 Lamda 函数,简单的说就是没有名字的函数,说来简单,其实作用挺强大的。在本节前面的例子中function sum(num1 : float, num2

26、: float) : float return num1 + num2;var sumFun : Function = function(num1 : float, num2 : float) : float return num1 + num2;两种定义函数的方式其实是有些区别的,前一种是在当前作用域中定义了一个名为 sum 的函数,这在程序编译时就确定了,在代码执行之前就已经加载到作用域了,无论你在这个作用域的哪个地方都能直接调用,而后一种定义方式,实际上是先定义了一个匿名的函数,然后将匿名的函数赋给变量 sumFun,只在这一行代码在运行时被执行后才有效。在前面例子里面的 call 函数

27、,也可以用 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);对于只使用一次的函数来说,这样做更加便捷,并且还少费一个变量也许对于这个例子,这么调用没有太

28、大必要,但是在大规模的使用函数作为参数的情况下,这样的简化就会带来很大的意义,当然,那就看你的编码思维是函数式的还是 JAVA,C+那样面向对象的方式了,要是一直习惯使用 C+,可能都不会有把函数作为参数的抽象思维,那样,这样的代码你写几 W 行代码都不会碰到。相对来说,因为 UnityScript 中去掉了很多与函数编程相关的便捷方法(类似 map,filter 等),使得用函数编程的方式成本偏高,所以按照C+的思维来写 UnityScript,完全是靠谱的。这里有个 UnityScript 很大的特点需要注意,那就是不支持函数内的函数定义,但是支持函数定义表达式。也就是说function fun1() /function fun2() / / not supportvar fun2 : Function = function() ; / OKreturn fun2;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报