标签归档:C#

爱上C#的理由 之 implicit隐式转换

写机器能够读懂的代码简单,写人类能够读懂的代码才是真功夫,而C#则提供了诸多优秀的语言特性来帮助你写出更加整洁、易读的代码。今天介绍的是implicit隐式转换

作为例子,我们定义了一个HsbColor结构(struct),它与Color类似,是对于色彩的一种数学表示,只是其色彩空间为HSB,而非Color采用的RGB色彩空间,因此你可以通过HsbColor.s来设置色彩的饱和度。下面这个函数可以调整当前物体材质颜色的饱和度:

可以看出,在创建hsbColor实例的时候,我们在构造函数中传入一个Color类型参数,最后在调整完hsbColor的饱和度后,又通过ToColor()函数将其转换为Color,并给material.color赋值。这段代码并无甚不妥,只是在implicit隐式转换的帮助下,我们可以让它变得更为简洁:

从上面的代码可以看到,我们可以使用Color直接为HsbColor赋值,同样的,我们还可以直接将HsbColor赋值给Color类型参数——这就是数据类型的隐式转换,在HsbColor中我定义了这样两个静态函数:

它们实现了HsbColor到Color之间的隐式转换。

需要注意的一点是,采用implicit隐式转换的一个首要原则是数据转换过程中没有丢失信息(如精度),HSB和RGB属于同一色彩的不同色彩空间表示,满足这一条件。而如果是float至int这类丢失数据精度的转换,我们则应该采用explicit显示转换:A = (A) B,这样可以在编译过程中就提示程序员转换非完全等价。

implicit和explicit属于C#的一个很小的语言特性,介绍的文章也很多在此不再赘述,附上实例中用到的HsbColor脚本,除了提供通过HSB属性定义颜色的功能外,还提供了HsbColor.Lerp函数,使你可以在HSB色彩空间内进行颜色转换,比起RGB空间的Color.Lerp更加符合人眼色彩变化的观感:

爱上C#的理由 之 Extension Method

在Unity3D提供的几种脚本语言中,有很多理由爱上C#,在我心目中Extension Method无疑是其中一个。

在使用Unity3D提供的类库书写脚本时,是否经常有类似这样的抱怨:“为什么就不能为AAA类写一个XXX方法呢?!明明很简单的一件事,现在却需要绕这么多圈子!”例如下面这3行代码:

明明很简单的三件事,但是代码写出来却不怎么简洁明了:

  • 设置X坐标为3
  • 设置等比缩放为(3,3,3)
  • Log一段话

对于Unity开发者,前两行代码估计都写过,而且很可能是需要常常写。第三行的Log代码我使用了string.Format——我喜欢更接近自然语言的Log输出,因为它会让那些调试信息看起来不那么烦人,但是每次都写一遍string.Format和一堆括号确实是又麻烦又冗长。

假如我们换一种写法:

是不是更加易懂而且代码也更加简洁了呢?我给Transform添加了两个梦寐以求”的方法:SetPositionX(float)以及SetUniformLocalScale(float),并且给所有继承自Object的类添加了一个Log(string, args)方法,可以直接传入string.Format的参数。

要实现这样的扩展无需破解Unity的类库,只需要使用C#的Extension Method即可。顾名思义,Extension Method允许你从外部为已有的类添加“扩展方法”——而且无需该类的任何代码。例如上面三个Extension Method的脚本是这样书写的:

从上面的代码不难看出,Extension Method要求必须使用静态类封装,且需要依据这样的格式为方法命名:

这里面this在函数传参中的使用也算是C#中this的一种特殊用法。

虽然Extension Method善加使用可以减少一定的重复工作量,让脚本更加简洁易读,但它也不是万灵药,在书写过于复杂的Extension Method之前也许你需要慎重考虑是否应该为该类增添一个新的接口,而不是“把代码写在外部”。另外struct是无法定义Extension Method的,例如Unity中的Vector3和Color。

最后附上两个我做的Extension Method脚本,分别针对Transform和Debug做了几个扩展方法,相信在看了这两个脚本后,你一定可以自己动手写出那些“梦寐以求”的扩展方法了。

点击下载示例脚本

Unity3D使用C#实现Coroutines & Yield

Coroutines & Yield是Unity3D编程中重要的概念,它可以实现将一段程序延迟执行或者将其各个部分分布在一个时间段内连续执行,但是在Javascript与C#中实现Coroutines & Yield,在语法上却有一些区别:

yield不可单独使用,需要与return配合使用,例如:

所有使用yield的函数必须将返回值类型设置为IEnumerator类型,例如:

最后,也是在”Using C#”这个章节中没有讲到的关键一点是,所有IEnumerator类型函数必须使用”StartCoroutine”这个函数触发,不能单独使用,例如:

Unity3D中如何调用其他GameObject的脚本函数

调用其他实例的脚本是一种很常用的需求,在Unity3D中实现起来也有多种方法,假设在ScriptB有一个DoSomething函数,如下所示:

在ScriptA中如果要访问某个GameObject的ScriptB脚本中的DoSomething函数:

注意ScriptA有一个ScriptB类型的公共变量,这是一个绝妙的小技巧,如此一来你便可以通过编辑器拖拽任何含有ScriptB这一脚本的GameObject至该变量上(因为是public的,所以暴露于编辑器界面中),Unity会自动识别你需要赋值的不是那个GameObject,而是它所包含的ScriptB脚本。

除此之外,如果你不喜欢这种在编辑器中直接赋值的办法,你可以通过GameObject.Find(“somename”) 来获取GameObject:

不过需要注意的是GameObject.Find()的执行效率非常低,所以如果可能的话还是尽可能使用“直接赋值法”吧。

学习使用C#进行Unity3D编程

本文针对Unity3D,从AactionScript 3开发者的角度来介绍C#的特性以及与AS3的不同,如果熟悉AS3的话C#学起来并不困难。

很遗憾本文作者所推荐的C# Pocket Reference在国内还没有出版,O’Reilly几本关于C#的大部头儿著作倒是都在国内上架了,想必是因为这本书过于基础,出版社觉得无利可图吧。

版权声明:本文系原文翻译,中文版转载请保留版权信息
原文出处:Getting started with C# for Unity3D
原文作者:EveryDayFlash
中文翻译:交典创艺

Unity3D 提供了三种可供选择的脚本编程语言:JavaScript, C# 以及 Boo。尽管它们各有各的优势与不足,但对我来讲C#显然会脱颖而出成为我的首选——首选,它完整支持面向对象,而且语法与Java以及ActionScript 3很类似,而这两者都是我所熟悉的。不过在接触Unity3D之前,我一行C#的代码都没写过,所以我必须从头学起。

C#由Microsoft提出并广泛使用于.NET framework以及Silverlight开发中。不过我们首先需要明白的是,学习用于Unity3D的C#并不等同于学习.NET平台,事实上你并不需要了解所有关于.NET的事情就可以使用C#为Unity3D编写脚本程序。

尽管我平时使用各种在线文档,但是一本实体书通常才是最好的助手,于是我决定买一本C#好书O’Reilly C# Pocket Guide看起来正是我所需要的,购买一本500页的C#圣经显然是没有必要的,因为那些书中大部分内容都是与.NET相关的,根本无法与Unity3D兼容。

当然,仅仅依靠这一本书是不够的,你还需要经常查阅 Unity3D scripting reference文档中所有的例子都是用Javascript书写的,但是不必担心,一旦你熟悉C#后将它们翻译为C#语言将轻而易举。文档中所有的例子默认都是用JavaScript写的,不过你可以在代码区域的右上角选择切换为C#或者Boo。

C#是一种非常典雅而强大的编程语言,它的dot-syntax命名法则基于Java,所以如果你具有Java编程背景将感到非常舒服。不过区别也还是有一些的,最明显的应该是在C#中属性以及方法的名称约定俗称都是以大写字母开头的。 我估计这是继承自Visual Basic的习惯,我并不是这种习惯的簇拥,但是与其反抗到底还不如接受它以保证代码的一致性。

C#的特性列表实在太长,这使得ActionScript实在是看起来有些相形见绌。 C#与Actionscript从本质上是极为相似的,我估计下一次ActionScript的升级中至少会实现C#的一些特性,因此有必要在此预先有所了解。下面是我所钟爱的一些特性。

运算符重载

这是目前为止最酷的!它允许程序员为+-*/这样的运算符定义特殊的行为。它的优势在向量加法运算中就可以明显体现出来,在ActionScript中,要计算向量之和,你需要书写类似下面的代码:

这样并不是很好,在多于两个向量相加时代码的易读性会变得很差。如果在C#中重载+运算符,代码将会变成下面的形式:

这样是不是可读性更好而且更为优雅呢?不用想我们就可以猜到,在Unity3D中所有向量的运算符都进行了重载。如果你希望自己实现,运算符重载也非常简单,对于上面的例子,代码大致是下面这个样子的:

这其中有一些简单的规则:运算符函数永远都是静态的(static),并且需要返回它所定义的对象类型。不过它的参数可以是任何类型的,因此完全可以重载加法或乘法运算符使其支持向量与浮点数或者与矩阵的运算——而这一切都要得益于C#对运算符重载功能的支持。

方法重载

方法重载可以允许我们定义多个同名但参数不同的方法。它不但对一般方法起作用而且也可以应用于构造函数——如果有多种途径来初始化一个对象,那么你可以为每一种途径定义一个专有的构造函数。而且方法重载同样可以应用于运算符方法,这一点上面已经提到了。

在Unity3D API中一个关于运算符重载最好的例子就是’Transform.Rotate()’这个方法,它被重载了三次以满足不同的旋转参数:

你可以指定欧拉角,也可以指定旋转轴以及旋转角度。

ActionScript可以使用默认参数来模拟方法重载,但是这样做并不方便也不便于理解。

Getter/Setter语法

C#声明参数的方法非常简明扼要,在ActionScript中需要两个方法——一个’get’一个’set’,而在C#中的代码则是这样的:

在这种情况下,你不需要额外做任何工作编译器就会自动创建一个私有属性,当然,这样的定义没什么用处,下面列举一个稍微复杂点的,包括一个public的get以及private的set:

想必你应该已经注意到了,尽管C#源自Java,在C#中却并不使用’function’和’var‘关键词——这样做之所以好是因为这两个关键词完全是冗余的病情不会为代码增加任何有价值的信息。

对于其他特性,我推荐看看indexers,generic types,structures以及enumerators,在上面提到的C# Pocket Book中都有详细介绍,许多C#教程中也有涉及。

编辑C#

很多编辑器都支持C#,微软提供的Visual C# Express Edition免费而且非常好用,支持代码自动补完功能,但是只对应Windows平台(显然的),3.0版以后Unity已集成MonoDevelop,跨平台Windows和Mac均可使用,稳定性经过不断更新已日臻完美,实在是Unity C#编程的不二之选。当然,不论如何我们最后至少还可以求助于TextMate

最后需要提到的是Unitron——Unity3D自带的默认编辑器。在开发者中间它并不怎么流行,而且我看到有人抱怨他过于基本了,我并不认同这种观点。虽然它不如FDT之于ActionScript那样强大,但是它非常稳定而且具备基本的代码自动补完功能——有趣的是,自动补完功能在默认设置下是关闭的(为啥?),要开启该功能需要打开’Preferences’,你会在’General’面板的底端找到这个选项,如此一来我相信Unitron还是值得一用的。

我们中很多人都是在浏览器环境下认识Javascript的,而Javascript也是很多人平生第一次使用的编程语言。如果是这种情况的话,你很可能会立刻开始使用Javascript进行Unity3D的编程而不必操心要学习什么新东西,毕竟,如Unity3D所说,任何使用C#可以完成的事同样可以使用Javascript完成

但是从长远考虑的话,C#可以提供更好的代码管理,完整的OOP支持,strong typing以及掌握一门优秀编程语言所带来的成就感。因此,额外付出的努力是值得的,更何况,对于一个经验丰富的AS3开发者,掌握C#只是几个礼拜的事儿,现在就动手尝试一下吧!