需求

  • Editor模式下,在运行或者非运行状态下,能够按照指定的变化率来自动改变material中属性数值。

需求分析

  • 如何在Editor模式下获得一个游戏对象及其组件,尤其是在非运行状态下?我们知道在Unity IDE运行起来后是很容易获得一个对象和组件的,在GameObject上挂一个脚本即可。但是在非运行状态下呢,transform.GetComponent 这样的方法怎么执行?好在unity已经为我们考虑到了这个问题,提供了[ExecuteInEditMode]Attribute,通过指定这个attribute使得组件类中的方法可以在edit模式下执行,并且是在非运行状态下的。

  • 如何在非运行状态下匀速改变数值呢?update方法中配合Time.deltaTime是一个完美的方案,但是即使设置了[ExecuteInEditMode],update的表现在非运行和运行时也是完全不同的,查资料看到is only called when something in the scene changed.这句话时也有种吐槽的冲动。好在unity又为大家考虑到了这个问题(话说unity editor确实功能强大,AssetAtore里面那些插件真是厉害),Edit模式下提供了EditorApplication.update,这是一个事件,我们注册一个自己的方法就可以在非运行状态下实现update的功能。我个人比较推荐使用EditorCoroutine,一个基于EditorApplication.update的协程实现。

功能实现

  • 使用一个自定义组件来实现material中数值的修改,这个类在UI上要体现出能够设置变化速率和初始值。并且在UI上通过点击按钮的形式来触发改变。
  • 使用Custom Inspector来实现组件UI的自定义。
  • 在运行状态下通过使用默认的update来实现匀速变化,在非运行状态下通过使用EditorCoroutine来实现。

代码实现

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4. public class UVAnimation : MonoBehaviour
  5. {
  6. public Vector2 TilingSpeed = new Vector2(1, 1);
  7. public Vector2 OffsetSpeed = new Vector2(0.1f, 0.1f);
  8. public Vector2 Tiling = new Vector2(1, 1);
  9. public Vector2 Offset = new Vector2(0, 0);
  10. float rate = 0.02f;
  11. EditorCoroutine coroutineOffset;
  12. EditorCoroutine coroutineTiling;
  13. bool isOffset = false;
  14. bool isTiling = false;
  15. // Use this for initialization
  16. void Start()
  17. {
  18. }
  19. // Update is called once per frame
  20. void Update()
  21. {
  22. }
  23. void FixedUpdate()
  24. {
  25. if (isOffset)
  26. {
  27. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset += OffsetSpeed * Time.deltaTime;
  28. }
  29. if (isTiling)
  30. {
  31. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale += TilingSpeed * Time.deltaTime;
  32. }
  33. }
  34. public void ChangeOffset()
  35. {
  36. if (EditorApplication.isPlaying)
  37. {
  38. isOffset = true;
  39. }
  40. else
  41. {
  42. if (coroutineOffset != null)
  43. {
  44. coroutineOffset.stop();
  45. }
  46. coroutineOffset = EditorCoroutine.start(ChangeOffsetCoroutine());
  47. }
  48. }
  49. IEnumerator ChangeOffsetCoroutine()
  50. {
  51. while (true)
  52. {
  53. yield return new WaitForSeconds(rate);
  54. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset += OffsetSpeed * rate;
  55. }
  56. }
  57. public void ChangeTiling()
  58. {
  59. if (EditorApplication.isPlaying)
  60. {
  61. isTiling = true;
  62. }
  63. else
  64. {
  65. if (coroutineTiling != null)
  66. {
  67. coroutineTiling.stop();
  68. }
  69. coroutineTiling = EditorCoroutine.start(ChangeTilingCoroutine());
  70. }
  71. }
  72. IEnumerator ChangeTilingCoroutine()
  73. {
  74. while (true)
  75. {
  76. yield return new WaitForSeconds(rate);
  77. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale += TilingSpeed * rate;
  78. }
  79. }
  80. public void SetOffset()
  81. {
  82. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset = Offset;
  83. }
  84. public void SetTiling()
  85. {
  86. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale = Tiling;
  87. }
  88. public void Reset()
  89. {
  90. isOffset = false;
  91. isTiling = false;
  92. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale = new Vector2(1, 1);
  93. transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset = new Vector2(0, 0);
  94. if (coroutineOffset != null)
  95. {
  96. coroutineOffset.stop();
  97. }
  98. if (coroutineTiling != null)
  99. {
  100. coroutineTiling.stop();
  101. }
  102. }
  103. }
  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4. [CustomEditor(typeof(UVAnimation))]
  5. public class UVAnimationBuilderEditor : Editor {
  6. public override void OnInspectorGUI ()
  7. {
  8. base.OnInspectorGUI ();
  9. //DrawDefaultInspector ();
  10. UVAnimation uva = (UVAnimation)target;
  11. if (GUI.changed) {
  12. uva.SetTiling ();
  13. uva.SetOffset ();
  14. }
  15. if (GUILayout.Button("Change Tiling")) {
  16. uva.ChangeTiling ();
  17. EditorUtility.SetDirty (target);
  18. }
  19. if (GUILayout.Button("Change Offset")) {
  20. uva.ChangeOffset ();
  21. }
  22. if (GUILayout.Button("Reset")) {
  23. uva.Reset ();
  24. }
  25. }
  26. }

代码解析

  • [CustomEditor(typeof(UVAnimation))]为UVAnimation创建的Editor类,在这个类里面可以修改UVAnimation类的UI,可以调用UVAnimation类中的方法。

  • OnInspectorGUI方法,顾名思义在里面可以对UI进行编程,注意一下这个方法会自己生产一句代码base.OnInspectorGUI ();,我所注释掉的DrawDefaultInspector ();这句代码都是用来绘制默认UI的,二者只可留其一。

  • transform.GetComponent<Renderer>().sharedMaterials在edit模式下获取材质球的对象需要用sharedMaterials

  • mainTextureScale对应的就是UI上的Tiling。命名这让人吐槽。

一个美术需求引发的Custom Inspector的更多相关文章

  1. 由一个项目需求引发的 - textarea中的换行和空格

    当我们使用 textarea 在前台编辑文字,并用 js 提交到后台的时候,空格和换行是我们最需要考虑的问题.在textarea 里面,空格和换行会被保存为/s和/n,如果我们前台输入和前台显示的文字 ...

  2. Spring之LoadTimeWeaver——一个需求引发的思考---转

    原文地址:http://www.myexception.cn/software-architecture-design/602651.html Spring之LoadTimeWeaver——一个需求引 ...

  3. Unity编辑器扩展 Chapter3--Create Custom Inspector

    一.Create Custom Inspector 重绘inspector面板一方面是我们的挂在脚本的窗口变得友好,另一方面可以让其变得更强大,比如添加一些有效性验证. 二.重要说明 1.Editor ...

  4. 一个purge参数引发的惨案——从线上hbase数据被删事故说起

    在写这篇blog前,我的心情久久不能平静,虽然明白运维工作如履薄冰,但没有料到这么一个细小的疏漏会带来如此严重的灾难.这是一起其他公司误用puppet参数引发的事故,而且这个参数我也曾被“坑过”.   ...

  5. 【深入浅出.Net IL】1.一个For循环引发的IL

    .Net底层剖析目录章节 1.[深入浅出.Net IL]1.一个For循环引发的IL 2.[.Net底层剖析]2.stfld指令-给对象的字段赋值 3.[.Net底层剖析]3.用IL来理解属性 1.准 ...

  6. Mysql中where条件一个单引号引发的性能损耗

    日常写SQL中可能会有一些小细节忽略了导致整个sql的性能下降了好几倍甚至几十倍,几百倍.以下这个示例就是mysql语句中的一个单引号('')引发的性能耗损,我相信很多朋友都遇到过,甚至还在这样写. ...

  7. Spring 循环引用(一)一个循环依赖引发的 BUG

    Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...

  8. Linux Framebuffer驱动剖析之中的一个—软件需求

    嵌入式企鹅圈将以本文作为2015年的终结篇,以回应第一篇<Linux字符设备驱动剖析>.嵌入式企鹅圈一直专注于嵌入式Linux和物联网IOT双方面的原创技术分享,稍后会公布嵌入式企鹅圈的2 ...

  9. 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器

    1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...

随机推荐

  1. iOS 传值方式

    1.代理传值 2.AppDelegate传值 3.block传值 4.通知传值 5.NSUserDefault传值

  2. Maven 配置远程仓库

    最近要用到一个包:spark-1.6.0-cdh5.8.2,在https://mvnrepository.com网站上搜到该包的pom.xml语句.但是看到下面有这样一句话: 该包在图中所述repos ...

  3. TDD测试驱动开发

    TDD测试驱动开发 一.概念 TDD故名思意就是用测试的方法驱动开发,简单说就是先写测试代码,再写开发代码.传统的方式是先写代码,再测试,它的开发方式与之正好相反. TDD是极限编程的一个最重要的设计 ...

  4. C语言中函数声明实现的位置

    在学习C语言的时候我遇到了这么个事情,因为之前先学习的C#,在C#编译器中,函数的声明位置不会影响编译的结果,但是在C语言中却发生了错误 先看一段代码: #include <stdio.h> ...

  5. appium过程中的问题

    1.在eclipse中点击Genymotion Virtual Device Manager ,选择虚拟设备,点击start后,无反应.    解决方法:Help/Install New Softwa ...

  6. 《一个操作系统的实现》学习笔记(一) bochs源码安装及配置

    前言:本机环境ubuntu 14.04 bochs 2.4.5 一.下载 官网 http://bochs.sourceforge.net/ 二.安装 1.将下载好的压缩包解压并进入该目录 .tar.g ...

  7. 用.net在画出镂空图片

    最近的一个项目需要用到这个东西,冥思苦想了好几天.还是在同事的帮助下,完成此项难题,希望能够帮助以后的博友们 ! 废话不多说,先看看效果图吧. 首先写一下讲一下思路,首先画一张图,当你的背景,然后在图 ...

  8. python中的参数问题

    python中的有默认参数和可变参数之分 默认参数arg 可变参数args, kargs 默认参数arg就是调用指定参数 可变参数*arg调用时传入的的参数会被python自动包装为列表 可变参数ka ...

  9. 利用sqlmap进行mysql提权的小方法(win与liunx通用)

    文章作者:pt007@vip.sina.com文章来源:https://www.t00ls.net/thread-36196-1-1.html1.连接mysql数据打开一个交互shell:sqlmap ...

  10. jq随手写图片放大

    html: <img id="img1" src="<?php echo $info->business_licence_img; ?>" ...