月份:2012年7月

Unity4 来了!

Unity 4 是Unity的新一代开发平台,包括全新的角色动画技术,更多的平台发布支持,手机游戏即时光影,对DirectX 11的支持和其他更多关键性升级.Unity 4.0是Unity 4系列的第一版,具有强大的全新功能,现在到官网可以预定,跟我们一起探索这个真正大众化的AAA级游戏引擎吧!

Unity4官方视频介绍:http://v.youku.com/v_show/id_XNDI1OTQxMDQ4.html

Mecanim是Unity独有的强大灵活的角色动画系统,能带给您栩栩如生的动画人物形象,画面运动极度流畅自然.

一旦在Unity中建立了操纵模型,先进的重新定位就让您能够使用和再使用各种各样形态的动画.从您喜爱的工具或资源库中选择动画和动作捕捉数据,即使在占用极少的CPU周期的情况下,也能保证人物动作流畅.

用Unity的视觉工具来定义和优化您的动画.可轻松地构建和编辑复杂的交互状态和混合的树形结构,以完全控制人物的移动.要让一大群人动起来?不仅角色设置精确有效,而且Mecanim的稳定性和强大性,结合新的优化,例如蒙皮网格实例化,能确保平稳的运行性能.

Unity动画系统使用视频:http://v.youku.com/v_show/id_XNDI1OTUzMTA4.html

Adobe® Flash® Player是全球主要的游戏平台.
发布到FlashPlayer,就相当于发布到全世界
全球有超过十亿个个人电脑用户安装了Adobe Flash Player,您可以将您的Unity3D内容发布到这个真正的全球平台.创作一个游戏,或将您现有的3D内容——用于iOS,安卓系统,桌面或网页——无缝发布到拥有Unity一样的标致速度和易用性的Adobe Flash Player上.

发布到Linux上是一个针对强大Unity游戏的成熟营销举措
Unity社区中最受期待的功能来了!将个人电脑的桌面单机游戏发布到装有Unit 4的Linux上.即使所处游戏平台服务不健全,Linux游戏也会大受欢迎.帮助你创造新的成功,如Humble Indie Bundle和Ubuntu软件中心,证明Linux用户很乐于为游戏买单.Linux单机发布系统可使Unity桌面用户免于额外费用.把您的游戏发布到Linux上吧,观众渴望高品质的娱乐.

视觉保真度和AAA级渲染可实现您渴望的艺术风格
震惊您的玩家,创作一个细腻,优雅的耀眼形象吧.发布一个可在多个平台平稳运行的超炫游戏.

光照贴图,让场景拥有更多细节
场景有了更多的细节,而不影响性能.Unity 4现在使用的法线贴图使用的是完整的Beast技术.使拥有法线贴图和双重光照贴图的场景看起来更加柔和,消除了远处物体和近处物体的视觉距离.
DirectX® 11渲染为您的个人电脑游戏提供更高的视觉保真度和更快的渲染周期:Unity 4现在支持 Windows DirectX 11图像API.提高计算着色器性能,使GPU可以作为一个并行的CPU来使用.利用装有5.0模型的更复杂的着色器,为您的游戏世界模型和环境添加了更丰富的细节.

光照贴图场景的更多细节和操作
Unity 4的迭代光照图烘焙让您能完全控制您的光照贴图工作流. “bake selected”这一选项让您能够只烘焙那些你需要烘焙的场景.加上新的更新,例如光照贴图时使用法线贴图,以及烘焙过程中占用较低的内存,这使得将细节和细微的差别加入到光照贴图的场景中这一过程变得前所未有的快捷和简单.拥有法线贴图和双重光照贴图的场景看起来更加柔和,消除了远处物体和近处物体的视觉距离.

蒙皮网格实例化
有效创建角色人群渲染系统.Unity 4为您提供一个可使用蒙皮网格渲染器输出的脚本,这样您就能预先计算好动画的动作,或者在相同动作的网格中低耗的渲染出多个对象.

新的文本渲染
Unity 4现在具有手机游戏动态字体的功能.可在任何分辨率下渲染亚洲文字,并用类似于HTML的标记来控制字体大小,重量和字体选择,不需要再导入庞大字体了.

工作流程更新为您高效创造游戏世界,更快速流畅地创作美丽的游戏
您将惊讶于您可以使用Unity如此快速的创作出一个高品质的游戏.通过市场上最全面最有效的资源管道导入资源.利用在一个直观的工作区简单的设立模块和强大的工具来整合您的镜头.同时对您的游戏进行测试和校对.使您保持激情和对成品游戏的注意力.

更流畅的组件工作流.

快速资源搜索和管理
使用新的项目窗口可轻松搜索并预览大型的复杂的项目中的资源

搜索,定位并查看您的资源
利用Unity 4您可以快速找到大型项目中您所关注的资源.保存常用的资源搜索结果,标记所有重要的文件夹和提前整理资源目录,都将使您的工作效率达到一个前所未有的高度.利用项目视图中的图标可快速确定任何您想要的资源.您也可直接通过项目窗口预览资源库中的免费和付费内容.

Unity内建Package简要说明

Unity内建了一些Package,方便我们使用,在创建项目时或者创建后都可以根据实际需要添加Package.

Custom Package : 导入第三方资源包,包括自己打出的Package都可以从这里导入,有很多初学者会遇到导入失败提示解压失败之类的错误,多数情况因为中文路径导致,最常见是将Package放在了系统桌面上进行导入.解决办法是放在纯英文路径下.

Character Controller : 角色控制相关代码,包括第一人称的预设,第三人称的预设.绘制完场景拖这里的预设到场景就可以简单的浏览查看.

Glass Refraction : 玻璃折射效果包,一般用来做真实的玻璃或水晶效果,仅在专业版Unity下支持.

Image Effects : 一些图像特效,如动态模糊效果,黑白效果,HDR效果,景深效果,辉光效果,是针对相机图像进行处理的.具体包含内容可以导入这个包,挨个测试一下就知道了.

Light Cookies : 灯光投影的一些图片资源,用于Projector,可以模拟日光灯,手电筒的光斑投影.可一同导入Projectors包.

Light Flares : 光晕的一些资源,比如模拟镜头光晕,夜晚灯光的发光效果等等.

Particles : 一些粒子预设,比如烟雾的效果,水花效果等等.

Physic Materials : 物理材质,设置好参数的物理材质预设,如木头,石头,金属等等.用于模拟物理交互用.

Projectors : 投影预设,如在高低起伏的地面上投射角色的简单影子,不需要实时灯光支持.

Scripts : 一些常用的脚本,如相机的跟随脚本,鼠标旋转,网格整合脚本等等.

Skyboxes : 天空盒素材,夜晚的,白天的,阴天的等等.

Standard Assets : 为移动平台准备的标准资源包,适合移动平台的材质资源,以及适合触屏的控制预设,比如摇杆之类.

Terrain Assets : 地形引擎的一些资源,草地贴图等等.

Toon Shading : 卡通效果相关着色器,描边效果可以试试这个包里面的材质.

Tree Creator : Unity的造树工具,可以简单的创建各种各样的树木,用于地形系统上植被绘制.

Water :这里有两个水资源包,一个用于基础版,一个用于专业版,可以快速创建漂亮的水面效果,两个包的显著区别是专业版的水Package含有真实的折射反射等高级效果.

威阿原创文章,转载请注明来自1Vr.Cn,否则MJJ.

Unity3.5.3更新修正列表

本版Unity最初包含对Unity 3.5的修改.关于最新性能的具体消息请见Unity 3.5发行备注(http://unity3d.com/unity/whats-new/unity-3.5).

改进
音频:修复使用无间隙MP3解码时的音频畸变.
缓存服务器:修复连接问题.
开发播放器将再次显示文件名和堆栈踪迹中的行数.
图像:在播放器设置中新加入优化网格数据选项.打开播放器,会自动移除无用的网格组件(例如:在所有着色器都不使用正常映射的情况下,可移除所有的切线向量).这样可以控制游戏大小和运行时表现.
图像:加入摄像机透明度分类模式,控制透明对象的分类.如果您在2D游戏中使用透视摄影机,您将可以拥有正确的对象分类!
图像:清除网格(Mesh.Clear)可以保留现有的顶点分布,提高您在运行时重组网络的效率.如果您想要完全清除网格,包括清除顶点形式分布,使用Mesh.Clear(伪).
iOS:自动包含的自带插件同样符合“符号链接Unity库”旗帜.建立档案时请关闭此面旗帜.
本地客户端:64-bit NaCl中脚本代码崩溃修复(64位Windows或Linux).
剖面测量仪:观测大型框架时(深度剖面)减少剖面测量仪的内存占用.
网络播放器:让浏览器对用户在Windows上的输入更敏感.
已知问题
安卓:32位显示缓冲器中,Kindle上不运行自动循环.请加强播放器设置的定位.
修复
本地客户端的Unity更新至NaCl SDK新版本,修复了一些问题.输送NaCl SDK游戏需要利用Unity3.5.3重新建立,因为该类游戏在将来的谷歌Chrome浏览器的版本中将不再适用!

安卓:JDK 7安装工具现在在窗口中自动检测.
安卓:现在使用错误的值类型读取播放器偏好会返回默认值.
安卓:退出应用程序时修复少见的紊乱情况.
安卓:在应用程序中加入对gdb服务器的支持.
安卓:在密钥库别名/密码中可以使用空格.
安卓:输入密码错误时提示信息更完善.
安卓:为应用程序签名时强制使用SHA1摘要算法,确保其被谷歌在线商店 (Google Play Store) 接受.
安卓:根据谷歌建议,创建密钥时强制使用RSA密钥算法.
安卓:修复当Kindle合成器使用显示缓冲器的alpha值的方法不正确时产生的漏洞
安卓:当编译引起sgs2升级到ics过程中的错误时,对着色器加入警告信息.
安卓:修复Éclair设备暂停时的返回故障.
安卓:修复PowerVR GPUs上批量/动力几何的perf复原.
缓存服务器:当在磁盘中更新,并且缓存服务器活跃时,本地资源(预制品、材料等)不能在编辑器里更新的时候产生的问题得到修复.
编辑器:运转不再产生多余的动画曲线
编辑器:修复从Unity3.4转换而来的项目中显示的弃用编辑延展实施(“Deprecated EditorExtensionImpl” )资源
编辑器:修正选择多项不同类别的可编辑脚本资源时产生的崩溃情况.
编辑器:修正系列化属性错误,该错误在某一阵列为最后提取的元素时,会引发空引用.
编辑器:修复标签,使之可储存在元数据中,并在检测器中正确显示.
编辑器:正确清除拖放缓存器,让旧数据不会滞留而产生问题.
编辑器:通过极度精确的四边形数据修复Windows错误线框渲染(如10000阴影四边形线框)
编辑器:修正当同一个文件夹中存在“Tree A”和“TreeA”之类名称的资源时,在Windows系统中的崩溃问题(改写MS-DOS系统中的简称!)
图像:修复不需要UV通道时资源网格的静态分批.
图像:修复错误输出顶点计算中联合网格中的漏洞.这就修复了一些显卡中联合网格的漏洞.
图像:在根据脚本设置网格顶点时正确验证阵列大小.
输入:重新与Windows连接之后正确检测控制器.
输入:忽略直接输入中的注册设定.
iOS:修复Xcode项目中的自动.a插件.
iOS:修复所有和喷溅定位有关的问题.
iOS:在所有非动画运行中,从Unity视角修复所有和本地UI有关的问题.
iOS:修复所有和xcode4.5开发版相关的问题.
移动电话:启动分析器时额外加入登陆程序(通过Wi-Fi或USB),当用编辑器无法看到设备时协助进行调试.
移动电话:修复固定功能中着色器生成,以便应对一个以上的TexGen CubeReflect样本.
NavMesh:优化navemesh bake的内存应用.在内存不够时不会导致崩溃,而是返回错误信息.
NavMesh:设置代理目标不会影响停止距离行为.
NavMesh:设置更新循环后,代理方面明确设置转换循环
网络:通过GUID修复服务器保护密码时遇到的问题.
着色器:修复表层着色器印花:在使用正常映射或透镜时的混合模式.
着色器:对移动区着色器转译的各种修复(HLSL -> GLSL编译器)
着色器:修复Windows上着色器模型3.0着色器的错误设置.
升级指南
在Unity3.4中,实时灯光没有影响静态物体.在Unity3.5中,实时灯光会影响静态和动态的物体.

结果就是,如果您之前开启灯光修复此漏洞,表现性能将不如此前,因为这时您会接收到两次照明.由于您的灯光两次被开启,因此表面看起来也会有所不同.

正确使用灯光的方式是使用单自动方向灯,移除实时灯光.

如果您希望拥有不同的实时灯光,而不是静态灯光,那么您应该使用灯罩,只照动态物体.

升级指南:http://forum.unity3d.com/threads/116479-Disappointed-with-performance?p=833498&viewfull=1#post833498

原文地址:http://china.unity3d.com/unity/whats-new/unity-3.5.3

Unity3.5.2更新修正列表

这次发行的Unity 3.5.2主要是对Unity 3.5的更新.想要了解更多新特性 ,请查阅Unity 3.5发行说明(http://unity3d.com/unity/whats-new/unity-3.5).

改进
iOS:在AppController.mm中加入UnityGetGLView功能,返回到unity所使用的视图.
iOS:现在如果在“retina”设备上运行,闪屏会使用“retina”影像.
Flash:引入System.Attribute 基类型,从而可以更方便地编译定制属性.
Flash:现在可以启动构造器,构造器给出byref参数.
Flash:Stage3D路径速度有所提高,同时11.1和11.2设置的路径执行变得更快.
Flash:点过滤现在可以使用.
Flash:系统.Bit转换(System.Bitconverter)现在可以使用
Flash:词典.包含价值( Dictionary.ContainsValue)现在可以使用
Flash:在一些情况下占用较小的内存量
Flash:SWFPostProcessing加速
Flash:生成字节码方面的性能优化
Flash:字节[]现在可以使用Flash本地bytearray作为后备存储器(.元素)
Flash:System.Text.Encoding浅执行,用于ascii和utf
Flash:安装启用System.Random, System.IO.MemoryStream, DateTime.
Flash:System.Exception.StackTrace属性
Flash:更多的转换错误,现在还包括相关的源定位.
改变
增加Resources.UnloadAsset(目标资源)功能.如果你知道某些较大的个体资源已不再使用,且不想调用Resources.UnloadUnusedAssets(),你可以使用这一增加功能很方便地卸载该资源.
编辑器:引入[Callbacks.PostProcessBuild]脚本属性.在建立播放器后执行属性方法.
编辑器:引入[Callbacks.PostProcessScene]脚本属性.处理当前场景时,执行属性方法.
Flash:为不同的FlashPlayer版本11.0、11.1和11.2建立了目标.现在还无从知晓Flash 播放器插件版本的具体的执行,但11.2设置意味着使用更快的代码路径;更好的性能.
Flash:现在可以使用www.GetAudioClip(),仅用于非串流mp3’s
Flash:WWW支持
Flash:WWWForm 支持
修复
Android:对Galaxy Nexus ICS上OpenGL ES驱动程序随意死机进行修复
Android:与一些装置上ICS升级有关的触屏问题得到修复.
Android:Caching.CleanCache()总是返回到false(不清除缓存).
Android:修复ICS装置上的Webcam结构初始化问题.
编辑器:当检测Visual Studio安装时,捕捉更多的角落事例(corner cases).
编辑器:修复游戏模式中当显示AudioClip检视图时的内存不足死机
编辑器:将PvrTexTool更新到2.10.87.498版本.
编辑器:修复使用SendMessage时的死机,非空变元传递到无参数接收器.
编辑器:修复已用纹理统计,在统计视图中显示
修复附加分析器后的内存泄漏.
修复下载资源包时的WebPlayer死机.
修复鼠标Δ处理故障,主要是非HID启用型鼠标.
修复音频试听上的内存不足.
修复当为缓存服务器散列资源时的竞态条件.
修复Resources.Load死机,如果装置的资源引用的是不存在的资源.
对因使用大量场景间参照资源创建播放器导致内存不足进而导致的死机进行修复.
标记为Occluders的SkinnedMeshRenderers将导致闭塞,修复这种故障.在PVS计算中,现在SkinnedMeshes只可以标记Occludees,并且使用蒙皮网络合订卷.
启动Unity后重新装载脚本带有编程错误,修复由此引起的死机.
Flash:修复整数除法符号.
Flash:修复本地方法回归结构中的内存泄露.
Flash:构造器将字段作为byref变元进行传递,修复由此引起的死机.
Flash:修复启动但没有应用的RuntimeServices_ToBool_Object.
Flash:修复字节上的字节序错误[].
Flash:修复资源包上monobehaviour反序列化方面的死机.
Flash:修复不能再进行编写脚本的粒子系统.
Flash:修复随意字符串www.错误,即使没有eror.
Flash:修复由协同程序中错误引起的致命错误故障.
Flash:修复www.纹理使用上的致命错误.
Flash:修复黑色背景上的flash预紧器条.
Flash:如果目的尺寸大于源尺寸,array.CopyTo()失败,修复此处的故障.
Flash:修复示例()上类型表字段故障.
Flash:修复列表序列化.
Flash:SwfPostprocessor引起swf不能确认的问题,或引起栈之下-或溢值,对此类问题进行修复.
Flash:修复许多小动作脚本转换.
Flash:GuiTexture再次正确渲染.
Flash:.Particles再次正确渲染.
Flash:带较大纹理的Texture2D setPixels不在死机.
Flash:UnityContent .setSize(宽,高)正确运行.
Flash:useGuiLayout可以使用.
Flash:gui.window不再出现死机.
Flash:不再有物理/角色控制冲突方面的死机.
Flash:物理,修复物体空间内摄影或困难的问题.
Flash:结构序列不再(不正确地)序列化.
Flash:ParticleSystem脚本现在可以使用.
Flash:现在可以使用非公开monobehaviour序列化.
Flash:协同程序问题,引起FlashPlayer核对和栈尺寸问题,对这种问题修复.
Flash:EncodeToPNG现在可以使用.
Flash:.c#阵列数据压缩支持.
Flash:矫正中缀表达式数值投射处理(不包括(int)(f * g)).
Flash:修复序列化表.
Flash:修复SwfPostprocessor;在这些情况下,player插件出现致命错误,显示文件夹不可用/常量出现检验错误.
Flash:修复SwfPostprocessor;修复最大栈尺寸计算.
Flash:修复StartCoroutine死机中的WWW.GetAudioClip()使用.
图形:修复在CombineMeshes中互换的顶点颜色.
图形:修复零点近平面聚光灯错误.
iOS:修复3.5/3.5.1中的动态几何性能回归.
iOS:闪屏旋转使其倾斜,对此修复.
iOS:Application.targetFrameRate <= 0设置将产生60 fps(如同在其他平台上).
iOS:InvalidateState引起INVALID_FRAMEBUFFER_OPERATION_EXT.GL,对此进行修复.
iOS:修复,并在iPhone上的封面屏幕中进行排列.
iOS:闪屏旋转使其倾斜,对此修复.
旧系统粒子:如果Time.timeScale是0,ParticleRenderer和TrailRenderer不会泄漏内存.
移动:修复SkinnedMeshRenderer死机.
导航网格:当Time.timeScale是0时,NavMeshAgent速率不会变成无效.
导航网格:当目的站和位置设为同一矢量时,NavMeshAgent修复偶然的无效位置/速率.
OS X:通过微软鼠标修复不稳定鼠标行为.
Windows Player:当进出全屏模式时,修复多线程渲染中偶然的暂停.
升级指南
在Unity 3.4中,实时灯光不影响静态物体.在Unity 3.5中,实时灯光往往影响静态和动态物体.产生的结果是:如果你之前设定了灯光围绕这个程序错误运行,因为接收了两次灯光,当前的性能将会很差.同时,它看起来也将不同,因为你的场景中增加了两次灯光.使用这些灯光的正确方法是使用单自动平行灯光,去除实时灯光.如果你希望拥有静态灯光以外的不同实时灯光,你需要使用灯光剔除掩码来影响动态的物体.

原文:http://china.unity3d.com/unity/whats-new/unity-3.5.2

在Unity编辑器上增加你自己的工具

本篇教程将教你扩展Unity编辑器,来更好的配合你开发项目.你将学习如何绘制Gizmo,在节点中创建删除对象,创建一个编辑器窗口,和使用组件,并且允许用户撤消任何在你工具上的操作.

首先我们看看最终我们要达成的工具样子:

正如图中所示,我们将创建一个编辑器窗口,还有颜色选择器来设置我们画出的栅格颜色,另外也可以创建和删除对象,对齐到这个栅格,以及对操作的撤消等等.
1:Gizmos
首先我们学习如何使用Gizmos,下面这个是几个常见的内建的Gizmos.

选择任何一个对象时都会显示这个Gizmo.

这是另外一个Gizmo,这使我们能看到所选的对象的boxCollider的大小.

2:创建一个栅格脚本
用C#脚本绘制Gizmo给一个对象,我们将在编辑器中画一个栅格作为示例.

using UnityEngine;
using System.Collections;

public class Grid : MonoBehaviour
{

    void Start ()
    {
    }

    void Update ()
    {
    }
}

这个栅格,我们需要添加长和宽的两个变量.

public class Grid : MonoBehaviour
{
    public float width = 32.0f;
    public float height = 32.0f;

    void Start ()
    {
    }

    void Update ()
    {
    }
}

要绘制栅格,我们需要用OnDrawGizmos,让我们创建它.

public class Grid : MonoBehaviour
{
    public float width = 32.0f;
    public float height = 32.0f;

    void Start ()
    {
    }

    void Update ()
    {
    }

    void OnDrawGizmos()
    {
    }
}

3:绘制栅格
要绘制栅格,我们需要在编辑器的相机位置绘制一些横线竖线.首先我们用一个变量来储存相机的位置.

void OnDrawGizmos()
{
    Vector3 pos = Camera.current.transform.position;
}

我们可以使用Camera.current来获取编辑器的相机.

现在我们需要用两个循环来绘制横线和竖线.

void OnDrawGizmos()
{
    Vector3 pos = Camera.current.transform.position;

    for (float y = pos.y - 800.0f; y < pos.y + 800.0f; y+= height)
    {
        Gizmos.DrawLine(new Vector3(-1000000.0f, Mathf.Floor(y/height) * height, 0.0f),
                        new Vector3(1000000.0f, Mathf.Floor(y/height) * height, 0.0f));
    }

    for (float x = pos.x - 1200.0f; x < pos.x + 1200.0f; x+= width)
    {
        Gizmos.DrawLine(new Vector3(Mathf.Floor(x/width) * width, -1000000.0f, 0.0f),
                        new Vector3(Mathf.Floor(x/width) * width, 1000000.0f, 0.0f));
    }
}

我们用Gizmos.DrawLine()来画线.Gizmos类里面有很多其他绘制方法,所以它可以绘制立方体,球体,甚至线框图.也可以绘制图像.

栅格应该是无限长,但是没有无穷远的浮点数给我们用,所以我们可以简单的用任意大的数字代替.行数取决于循环的次数.

要看到栅格,旧创建一个空对象并将我们这个脚本赋予它.

4:自定义检视面板

接下来我们自定义检视面板,我们需要创建在创建一个C#脚本文件并命名为GridEditor.放在脚本编辑器Editor文件夹里.如果没有这个文件夹,就创建一个.

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor (typeof(Grid))]
public class GridEditor : Editor
{
}

我们需要用UnityEditor的函数来覆盖栅格默认的检视面板,使用 [CustomEditor (typeof(Grid))] 让Unity知道我们将定制栅格的检视面板.

public class GridEditor : Editor
{
    public override void OnInspectorGUI()
    {
    }
}

如果现在你看编辑器的检视面板,你将看到一个空的窗口.这是因为我们自定义了一个面板用OnInspectorGui()的方法覆盖掉了默认的检视面板.

5:使用GuiLayout填充自定义检视面板.
上面我们创建了一个空的面板,首先我们要给这个面板指定一个目标对象.实际上,已经有个target给这个检视面板.但是方便起见,我们将创建一个引用栅格组件的对象.我们先来声明它.

public class GridEditor : Editor
{
    Grid grid;

在检视面板激活的时候可以用OnEnable()方法来执行一些事件.

public class GridEditor : Editor
{
    Grid grid;

    public void OnEnable()
    {
        grid = (Grid)target;
    }

我们用GUILayout和EditorGUILayout类来创建一些表单.

public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();
}

第一行中的GUILayout.BeginHorizontal()表示下面的元素都将水平排列,同样的,在最后有GUILayout.EndHorizontal()来说明结束上面的排列方式.第一个是一个标签.用来显示网格宽度.然后旁边创建了一个EditorGUILayout.FloatField字段来分配grid.width,并设置默认值为50像素.

下面是在检视面板中实际的效果:

6:填充检视面板和重绘场景.
让我们添加grid.height的字段到检视面板中.

public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();

    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Height ");
    grid.height = EditorGUILayout.FloatField(grid.height, GUILayout.Width(50));
    GUILayout.EndHorizontal();
}

这就是控制栅格对象的所有字段,如果想了解其他类型的字段项,可以看脚本参考的EditorGUILayout和GUILayout,这个时候只有在我们选择场景视图窗口的时候,检视面板中做的新变化才是可见的,为了保持实时变化,一旦我们做了修改,我们就可以用SceneView.RepaintAll()来重绘场景视图.

public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();

    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Height ");
    grid.height = EditorGUILayout.FloatField(grid.height, GUILayout.Width(50));
    GUILayout.EndHorizontal();

    SceneView.RepaintAll();
}

现在我们就不需要在点击检视面板以外的区域查看改变了.

7:处理编辑器的输入
现在我们来尝试处理编辑器的输入,就像我们做的游戏获得键盘或鼠标的状态.我们用onSceneGUIDelegate来实现场景视图上的交互,让我们来调用GridUpdate().

public void OnEnable()
{
    grid = (Grid)target;
    SceneView.onSceneGUIDelegate = GridUpdate;
}

void GridUpdate(SceneView sceneview)
{
}

现在我们只需要获得输入事件.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;
}

8:创建预设
为了进一步学习编辑器脚本,我们需要一个游戏对象,让我们创建一个立方体预设.

可以缩放立方体或者其他方式让它与网格对齐.

你可以在层次面板中看到立方体的名字是蓝色的,这意味着它与一个预设有关联.在项目视图中也可以看到这个预设.

9:从编辑器脚本创建对象
现在我们要做到从编辑器脚本创建对象,打开GirdeEditor.cs脚本来改进GridUpdate()函数.
当按下按键时创建对象.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;

    if (e.isKey && e.character == 'a')
    {
        GameObject obj;
    }
}

脚本会监听是否按下a键,同样创建了一个用来引用的新对象.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;

    if (e.isKey && e.character == 'a')
    {
        GameObject obj;
        if (Selection.activeObject)
        {
            obj = (GameObject)Instantiate(Selection.activeObject);
            obj.transform.position = new Vector3(0.0f, 0.0f, 0.0f);
        }
    }
}

Selection.activeObject 是目前在编辑器选择的对象.只要有对象被选择,我们就会复制它并改变复制出来的对象的坐标到空间原点.

现在我们来测试一下,你要注意当资源重导入或者刷新时GridUpdate()将停止运行,如果要重新运行,你要选择一个对象(例如从层次视图中),我们这例子要选择网格对象.还需要记得场景视图获得焦点时才能捕获输入事件.

10:从编辑器脚本实例化预设
虽然我们现在可以克隆对象,但克隆的对象是不会有预设关联的.

你可以看到Cube(Clone)是纯黑色的字体,代表它没有连接到原来立方体的预设.而我们如果在编辑器中手动复制原始立方体,克隆出来的立方体将拥有原立方体一样的预设.如果想在脚本里面克隆出来的立方体也有原立方体的预设关联,我们需要使用EditorUtility类里面的InstantiatePrefab() 函数.

使用这个函数前,我们需要得到所选对象的预设,我们需要用到EditorUtility类里面的GetPrefabParent()函数.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;

    if (e.isKey&& e.character == 'a')
    {
        GameObject obj;
        Object prefab = EditorUtility.GetPrefabParent(Selection.activeObject);

        if (prefab)
        {

我们也可以停止判断 Selection.activeObject了,因为如果它不存在,预设会为空,因此我们可以只检查预设引用是否存在就可以了.
现在让我们来实例化预设并设置它的位置.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;

    if (e.isKey && e.character == 'a')
    {
        GameObject obj;
        Object prefab = EditorUtility.GetPrefabParent(Selection.activeObject);

        if (prefab)
        {
            obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
            obj.transform.position = new Vector3(0.0f, 0.0f, 0.0f);
        }
    }
}

看,现在克隆出来的有预设关联了.

11:转换屏幕上鼠标坐标到世界坐标系
Event类没有让我们获得鼠标在世界空间的位置,它只提供了屏幕空间坐标系的鼠标位置.下面我们将转换它们,让我们得到鼠标在世界空间里的位置.

void GridUpdate(SceneView sceneview)
{
    Event e = Event.current;

    Ray r = Camera.current.ScreenPointToRay(new Vector3(e.mousePosition.x, -e.mousePosition.y + Camera.current.pixelHeight));
    Vector3 mousePos = r.origin;

首先,我们使用编辑器相机的ScreenPointToRay从屏幕坐标系上获取射线,不过在这之前我们需要转换屏幕坐标供ScreenPointToRay()使用.

e.mousePosition的原点是从屏幕左上角(等于Camera.current.pixelWidth, -Camera.current.pixelHeight).我们需要转换为原点在屏幕左下角的坐标(Camera.current.pixelWidth, Camera.current.pixelHeight).
接下来我们要保存鼠标位置的向量.
现在我们可以指定克隆出来的对象到鼠标的位置.

if (prefab)
{
    obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
    obj.transform.position = new Vector3(mousePos.x, mousePos.y, 0.0f);
}

12:对齐立方体到栅格
让我们将创建的立方体对齐到鼠标位置的网格.

if (prefab)
{
    obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
    Vector3 aligned = new Vector3(Mathf.Floor(mousePos.x/grid.width)*grid.width + grid.width/2.0f,
                                  Mathf.Floor(mousePos.y/grid.height)*grid.height + grid.height/2.0f, 0.0f);
    obj.transform.position = aligned;
}

结果下图这样.

13:销毁从编辑器脚本创建的对象.

可以使用DestroyImmediate()来删除对象,本例中我们将通过按下”d”键来删除所有被选中的对象.

if (e.isKey && e.character == 'a')
{
    GameObject obj;
    Object prefab = EditorUtility.GetPrefabParent(Selection.activeObject);

    if (prefab)
    {
        obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
        Vector3 aligned = new Vector3(Mathf.Floor(mousePos.x/grid.width)*grid.width + grid.width/2.0f,
                                      Mathf.Floor(mousePos.y/grid.height)*grid.height + grid.height/2.0f, 0.0f);
        obj.transform.position = aligned;
    }
}
else if (e.isKey && e.character == 'd')
{
    foreach (GameObject obj in Selection.gameObjects)
        DestroyImmediate(obj);
}

当”D”键按下时,我们遍历所有被选中的对象,并逐一删除.当然Delete键依旧可用的.

14:撤消对象实例化

这一节我们将利用Undo类来实现撤消编辑器脚本的撤消.为了实现撤消,我们需要调用在编辑器中创建Undo.RegisterCreatedObjectUndo().它有两个参数,第一个是已经创建的对象,第二个是撤消的动作名称.会在”Edit-Undo name”中显示.

if (prefab)
{
    obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
    Vector3 aligned = new Vector3(Mathf.Floor(mousePos.x/grid.width)*grid.width + grid.width/2.0f,
                                  Mathf.Floor(mousePos.y/grid.height)*grid.height + grid.height/2.0f, 0.0f);
    obj.transform.position = aligned;
    Undo.RegisterCreatedObjectUndo(obj, "Create " + obj.name);
}

如果你按下按键,创建了多个立方体,然后尝试撤消,你会发现,刚才所有创建的立方体都被删除了.这事因为所有被创建的立方体放在了一个单一撤消事件中.

15:撤消单对象实例

如果我们需要对每个创建的对象都要有自身的撤消事件,我们需要使用Undo.IncrementCurrentEventIndex().

if (prefab)
{
    Undo.IncrementCurrentEventIndex();
    obj = (GameObject)EditorUtility.InstantiatePrefab(prefab);
    Vector3 aligned = new Vector3(Mathf.Floor(mousePos.x/grid.width)*grid.width + grid.width/2.0f,
                                  Mathf.Floor(mousePos.y/grid.height)*grid.height + grid.height/2.0f, 0.0f);
    obj.transform.position = aligned;
    Undo.RegisterCreatedObjectUndo(obj, "Create " + obj.name);
}

现在测试脚本你会看到会一个个的撤消被创建的立方体.

16:撤消对像删除

要撤消被删除的对象可以使用 Undo.RegisterSceneUndo(),它很慢,基本上是保存场景的状态,以便我们重做被撤消的动作,不过目前没有其他直接的办法来重做撤消.

else if (e.isKey && e.character == 'd')
{
    Undo.IncrementCurrentEventIndex();
    Undo.RegisterSceneUndo("Delete Selected Objects");
    foreach (GameObject obj in Selection.gameObjects)
        DestroyImmediate(obj);
}

Undo.RegisterSceneUndo() 只有一个参数,那就是撤消的名称.当用D键删除后.你可以用这个命令撤消删除.

17:创建编辑器窗口脚本

用一个新脚本创建一个新编辑器窗口,脚本名为GridWindow.cs.

using UnityEngine;
using UnityEditor;
using System.Collections;

public class GridWindow : EditorWindow
{
    public void Init()
    {
    }
}

通过栅格对象来访问这个窗口.

public class GridWindow : EditorWindow
{
    Grid grid;

    public void Init()
    {
        grid = (Grid)FindObjectOfType(typeof(Grid));
    }
}

18:创建GridWindow

我们在OnInspectorGUI()中为GridWindow添加一个打开窗口按钮.

public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();

    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Height ");
    grid.height = EditorGUILayout.FloatField(grid.height, GUILayout.Width(50));
    GUILayout.EndHorizontal();

    if (GUILayout.Button("Open Grid Window", GUILayout.Width(255)))
    {
       GridWindow window = (GridWindow) EditorWindow.GetWindow(typeof(GridWindow));
       window.Init();
    }

    SceneView.RepaintAll();
}

用GUILayout来创建按钮,并且设置按钮的名称和宽度.打开GridWindow窗口点下这个按钮,将返回真.

回到检视面板点击打开Grid Window按钮.

你会看到GridWindos弹出了.

19:在GridWindos中创建颜色字段.

可以在这个窗口中添加任何东西,现在让我们为栅格类添加一个颜色字段,以便后面我们来编辑它.

public class Grid : MonoBehaviour
{
    public float width = 32.0f;
    public float height = 32.0f;

    public Color color = Color.white;

在OnDrawGizmos()中赋给Gizmos.color.

void OnDrawGizmos()
{
    Vector3 pos = Camera.current.transform.position;
    Gizmos.color = color;

在GridWindos脚本里的OnGUI()添加一个颜色拾取器字段用来我们拾取颜色.

public class GridWindow : EditorWindow
{
    Grid grid;

    public void Init()
    {
        grid = (Grid)FindObjectOfType(typeof(Grid));
    }

    void OnGUI()
    {
        grid.color = EditorGUILayout.ColorField(grid.color, GUILayout.Width(200));
    }
}

点击测试一下改变栅格的颜色.

20:添加Delegate

我们设置了一个Delegate,用=号得到场景视图的输入事件,这样做不太好,因为它涵盖了所有其他回调.我们可以用+=符号代替=号.下面修改GridEditor.cs脚本.

public void OnEnable()
{
    grid = (Grid)target;
    SceneView.onSceneGUIDelegate += GridUpdate;
}

我们还需要创建一个OnDisable()的回调来替换掉GridUpdate(),否则会被执行很多次.

public void OnEnable()
{
    grid = (Grid)target;
    SceneView.onSceneGUIDelegate += GridUpdate;
}

public void OnDisable()
{
    SceneView.onSceneGUIDelegate -= GridUpdate;
}

结论:
这篇是编辑器编程的基础教程,如果你想扩展这方面的知识,可以查看脚本参考(http://unity3d.com/support/documentation/ScriptReference/index.html)中的Resources,和AssetDatabase和FileUtil类.

原文:http://active.tutsplus.com/tutorials/workflow/how-to-add-your-own-tools-to-unitys-editor/
由威阿翻译,转载请注明来自1Vr.Cn,否则MJJ.