2018-05-22 11:28:34 luoyikun 阅读数 1260
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ChangeMat : MonoBehaviour {


    [MenuItem("Tools/ChangeNewMat")]
    static void ChangeNewMat()
    {
        GameObject obj = Selection.activeGameObject;
        foreach (Renderer it in obj.transform.GetComponentsInChildren<Renderer>())
        {
            Material mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/ViveJx/Materials/JianXiuBall.mat");
            Material[] bufMat = new Material[it.sharedMaterials.Length];
            for (int i = 0; i < it.sharedMaterials.Length; i++)
            {
                bufMat[i] = mat;
            }
            it.sharedMaterials = bufMat;
        }
    }
}

Note that like all arrays returned by Unity, this returns a copy of materials array. If you want to change some materials in it, get the value, change an entry and set materials back.
要改变材质数组,得重新赋值一个数组

2016-02-29 10:32:01 qinyuanpei 阅读数 6206
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

  最近在学习Shader时感觉Shader语言参数众多、语法诡异,如果每次都从头开始写Shader一定是一件痛苦的事情。如果可以在本地定义好一组标准的Shader模板,这样当我们需要实现某些效果类似的Shader时,就可以在这个Shader模板的基础上进行修改。因为Shader文件是一个文本文件,所以我们可以非常容易地创建这样一个模板,在这个模板中我们可以进一步完善相关的参数注释,这样就不用每次写Shader的时候都需要查文档了,从这个角度出发,就进入了这篇文章的正题:扩展Unity3D编辑器的脚本模板。

按图索骥,模板在哪里?

  Unity3D默认的脚本模版位于/Editor/Data/Resources/ScriptTemplates/目录下,注意该目录相对Unity3D的安装目录而言,在这个目录中我们可以找到Unity3D中脚本模板的某些蛛丝马迹,首先,脚本模板是一个简单的文本文件,这个文本文件中预先填充了内容,我们在编辑器中创建模脚本或者Shader的时候实际上是读取这些文件然后在写入项目中的指定路径的。其次,这些模板文件中#SCRIPTNAME#或者#NAME#这样的标记,当我们在编辑器中创建文件的时候,这个标记会被替换成指定的文件名。比如Unity3D中继承自MonoBehaviour的脚本,有一个非常重要的特性是文件名必须和类名保持一致,这固然是Unity3D引擎的一个设定,可是在这里亦可以找到一个可以称得上理由的理由。我们注意到这些模板的文件名中都有一个独一无二的数字,比如C#脚本的模板中的数字是81、Shader模板中的数字是83,这些数字是什么呢,博主这里将其称为来自星星的黑科技。

来自星星的黑科技

  作为一个经常捣鼓Unity3D编辑器的人,如果说你不知道MenuItem、EditorWindow、ScriptableWizard这些黑科技,那么说明你不是一个喜欢折腾和探索的人。从Unity3D的API文档中,我们知道MenuItem的原型为:

MenuItem(string itemName,bool isValidateFunction,int priority) 

我知道我们通常使用MenuItem常常使用的是它的第一个参数,即定义一个菜单项的名称,我们可以使用”/”这样的分隔符来表示菜单的层级,MenuItem需要配合一个静态方法来使用,可以理解为当我们点击当前定义的菜单后就会去执行静态方法中的代码,因此MenuItem常常可以帮助我们做些编辑器扩展开发的工作。好了,第二个参数作为一个验证的标志,如果该标志为true,意味着我们定义的静态方法是一个验证方法在执行静态方法前会首先对方法进行验证,这个我们暂且不管,因为今天我们这个来自星星的黑科技主要和第三个参数有关,第三个参数表示一个优先级,它表示菜单项在菜单栏中的展示顺序,优先级大的菜单项会展示在优先级小的菜单项下面,由此我们就明白了了模板文件名中的类似81、83这样的数字的真实含义,注意到模板文件的排列顺序和编辑器中的菜单项顺序是一样的,我们做一个尝试,编写下面的代码:

[MenuItem("Assets/Create/Lua Scripts", false, 85)]
static void CreateLuaScripts()
{

}

[MenuItem("Assets/Create/固定功能着色器", false, 86)]
static void CreateFixedFunctionShader()
{

}

[MenuItem("Assets/Create/表面着色器", false, 87)]
static void CreateSurfaceShader()
{

}

[MenuItem("Assets/Create/可编程着色器", false, 88)]
static void CreateVertexAndFragmentShader()
{

}

注意到我们按照已知的优先级继续写了四个方法,现在我们在编辑器中可以发现默认的菜单栏发生了变化:

黑科技让菜单栏发生了变化

我们可以看到我们编写的这四个菜单都生效了,虽然它们暂时什么都做不了,但顺着这个方向去探索,我们是可以实现最初的梦想的。现在我们来思考如何根据模板来创建文件,这个对我们来说简直太简单了,通过StreamReader来读取模板,然后再用StreamWriter来生成文件就可以了。可是这样创建的文件的文件名是固定的,在创建文件的时候我们没法修改,而且即使修改了文件内定义的名字并不会改变啊。所以我们需要一个更好的解决方案。Unity3D提供了一个UnityEditor.ProjectWindowCallback的命名空间,在这个空间中提供了一个称为EndNameEditAction的类,我们只需要继承这个类就可以完成这个任务。这个类需要重写Action的方法,我们知道创建一个文件的完整步骤是创建文件然后使其高亮显示,因此这部分代码实现如下:

/// <summary>
/// 定义一个创建资源的Action类并实现其Action方法
/// </summary>
class CreateAssetAction : EndNameEditAction
{

    public override void Action(int instanceId, string pathName, string resourceFile)
    {
        //创建资源
        Object obj = CreateAssetFormTemplate(pathName, resourceFile);
        //高亮显示该资源
        ProjectWindowUtil.ShowCreatedAsset(obj);
    }

    internal static Object CreateAssetFormTemplate(string pathName, string resourceFile)
    {

        //获取要创建资源的绝对路径
        string fullName = Path.GetFullPath(pathName);
        //读取本地模版文件
        StreamReader reader = new StreamReader(resourceFile);
        string content = reader.ReadToEnd();
        reader.Close();

        //获取资源的文件名
        string fileName = Path.GetFileNameWithoutExtension(pathName);
        //替换默认的文件名
        content = content.Replace("#NAME", fileName);

        //写入新文件
        StreamWriter writer = new StreamWriter(fullName, false, System.Text.Encoding.UTF8);
        writer.Write(content);
        writer.Close();

        //刷新本地资源
        AssetDatabase.ImportAsset(pathName);
        AssetDatabase.Refresh();

        return AssetDatabase.LoadAssetAtPath(pathName, typeof(Object));
    }
}

这部分代码相对来说比较简单,就是读取本地模板文件然后生成新文件,在生成新文件的时候会将#NAME替换成实际的文件名,这样我们就完成了文件资源的创建。现在的问题是如何在创建文件的时候获取实际的路径,这部分代码实现如下:

private static string GetSelectedPath()
{
    //默认路径为Assets
    string selectedPath = "Assets";

    //获取选中的资源
    Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.Assets);

    //遍历选中的资源以返回路径
    foreach (Object obj in selection)
    {
        selectedPath = AssetDatabase.GetAssetPath(obj);
        if (!string.IsNullOrEmpty(selectedPath) && File.Exists(selectedPath))
        {
            selectedPath = Path.GetDirectoryName(selectedPath);
            break;
        }
    }

    return selectedPath;
}

现在解决了创建资源的问题,我们接下来只要调用ProjectWindowUtil的StartNameEditingIfProjectWindowExists方法即可,该方法需要传入一个继承自EndNameEditAction的类的实例、目标文件路径和模板文件的路径。例如要创建一个Lua脚本可以这样实现:

[MenuItem("Assets/Create/Lua Scripts", false, 85)]
static void CreateLuaScripts()
{
    ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
        ScriptableObject.CreateInstance<CreateAssetAction>(),
        GetSelectedPath() + "/NewLuaScript.lua", null,
        "Assets/Editor/Template/85-Lua-NewLuaScript.lua.txt");
}

小结

  现在有了这个黑科技以后,我们可以创建更多的模板来扩展编辑器的功能,比如对Shader而言,我们可以创建些基础性的Shader模板,然后每次需要写Shader的时候直接从模板库中选择一个功能类似的Shader然后在此基础上进行修改,这样比从头开始写一个新的Shader应该会轻松不少,这段时间学习Shader,感觉进程缓慢离图形学高手遥遥无期,行了,这篇博客就是这样了。

效果演示

2018-10-23 16:52:11 realzuile 阅读数 6375
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

1.没有将vs设置为默认脚本编辑器

2.通过步骤1后设置使用VS2012做脚本编辑,但每次还是启动Monodevelop,可能原因一:没有将unity与vs关联起来

https://marketplace.visualstudio.com/items?itemName=SebastienLebreton.VisualStudio2015ToolsforUnity
你下载对应的vs版本的Tool for Unity,安装后,打开后就可以正常使用vs打开脚本了,亲测(我自己的是用vs2015的,所以这里放2015的Tool for Unity)

要是不是2015版本的vs,那么

在搜索到结果中,找到自己版本的Tool for Unity,点击打开,在弹出的窗口中点击“Download”按钮,就可以下载对于版本的Tool for Unity了,接着安装就可以了

原因2:vs出问题了,无法与unity关联

将vs修复下;既然怒控制面板->程序->程序和功能->vs->更改->修复

 

 

2018-05-31 23:06:56 u012632851 阅读数 3142
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

Unity3D Editor 编辑器扩展3 Editor脚本

环境:Unity2017.2 语言:C#

 

总起:

在编辑Unity项目的时候,总不可能避免的接触到Unity自身自带的Inspector参数调整无法很好的完成某些特定功能的情况。

 

比方说想要一个按钮直接能跳到游戏的主界面进行调试,然而普通的情况下甚至连添加一个按钮都做不到。

 

这边推荐一下本人花了20几刀购买的插件——Odin Inspector & Serializer: http://sirenix.net/odininspector。该插件能够摒弃我今天要讲的Editor脚本,非常轻松的就能完成一些炫酷的EditorUI。

 

Odin,我其实研究的不是太深入,因为在实际的项目中并没有用到,所以该插件的介绍,我想过段时间深入研究后再说。

 

今天的主角是Editor脚本。

 

Editor脚本:

♦ 简单介绍

首先Editor脚本必须放在Editor文件夹或其子文件夹下,然后我们来看一个Edior脚本的例子:

//PlayerEditor.cs
[CustomEditor(typeof(Player))]
public class PlayerEditor : Editor
{
    private SerializedProperty hpProperty;

    void Awake()
    {
        Debug.Log("Awake");
    }

    void OnEnable()
    {
        Debug.Log("OnEnable");
        hpProperty = serializedObject.FindProperty("hp");
    }

    public override void OnInspectorGUI()
    {
        // 更新serializedObject,在OnInspectorGUI一开始就要调用该函数
        serializedObject.Update();

        // 创建一个Int的滑动条
        EditorGUILayout.IntSlider(hpProperty, 0, 100, new GUIContent("HP"));

        // 使用自定义的滑动条
        ProgressBar(hpProperty.intValue / 100f, "HP");

        // 保存所有对脚本修改的值
        serializedObject.ApplyModifiedProperties();
    }

    // 自定义一个滑动条
    void ProgressBar(float value, string label)
    {
        Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField");
        EditorGUI.ProgressBar(rect, value, label);
        EditorGUILayout.Space();
    }

    void OnDisable()
    {
        Debug.Log("OnDisable");
    }

    void OnDestroy()
    {
        Debug.Log("OnDestroy");
    }
}

// Player.cs
public class Player : MonoBehaviour
{
    public int hp;
}


效果如下:


可以注意到,PlayerEditor是继承于Editor的,除了Awake、OnEnable这类熟悉的生命周期方法外,脚本中很多操作使用到了UnityEditor.dll里的内容,而该dll是不会被打包的,所以非Editor文件夹底下的脚本千万不要引用到UnityEditor这个命名空间了。

 

Editor父类中的serializedObject代表的正是当前操作的这个脚本,使用以下操作可能更加明了:

Player player = (Player)serializedObject.targetObject;

Debug.Log(player.hp);

 

使用其成员变量targetObject可以直接获取到对应脚本进行操作。

 

具体OnInspectorGUI中的内容,我不想详细介绍了,主要是使用EditorGUILayout、GUILayout、GUILayoutUtility这三个类。

 

说到Editor,其实第一篇文章提到的MenuItem最好就是写在这样的脚本中。

 

♦ Editor脚本的结构

相比于介绍Editor的使用,我更想深入了解一下Editor这个类(使用方面,还有Odin完全可以代替Editor脚本呢)。

 

Editor的继承结构:Editor -> ScriptableObject -> UnityEngine.Object -> object。

 

Editor除了继承于ScriptableObject外,还实现了IPreviewable、IToolModeOwner接口。

 

我们刚刚使用的serializedObject是根据我们写的Component生成的SerializedObject(注意不是Editor的父类ScriptableObject)对象。

 

Editor的父类ScriptableObject可能很多人都用过,他可以很方便的保存一些配置信息,Prefab、资源引用什么的。

 

SerializedObject是UnityEditor命名空间的,用于以通用的方式操作对象的属性,可以自动处理撤销操作,和产生一些预制的样式UI。

 

看到这里,我越来越好奇Unity的对象序列化了,但是这边反编译的C#脚本引用的都是C++内容。

 

感觉有些遗憾,手头也没有C++代码,如果有大神指导如何获取该源码,希望能指条明路,谢谢!

 

个人:

看源码的时候,多数都会追到C++的代码,看得唯一感觉比较友好的就是UGUI的,因为他基本上都是基于C#来编写的,虽然内容比较繁杂,但是总也能理清思路。

 

我手头上有份Unity4 C++,但感觉不是很全,Transform几个类倒是有,像SerializedObject便找不到了,可能是我姿势不对。


2017-04-14 19:26:49 yongh701 阅读数 23851
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

在《【Unity3D】Helloworld》(点击打开链接)第一次遇见Unity3D在安装的时候,我曾经说,暂时不知道MonoDevelop是什么来的,先装上,虽然装上也没坏,但我现在已经知道这东西是什么,是一个不好用的脚本编辑器。习惯了Visual Studio用Ctrl+K Ctrl+F格式化代码的我,Ctrl+J自动补全代码的我,面对如此的编辑器感到极其不适应,更何况本身C#的发源地就是Visual Studio,所以要设置Unity3D默认编辑器了。你使用JavaScript另当别论,或许MonoDevelop是你更好的选择,但C#不用Visual Studio去写,我感觉天理不容啊!!!

可以这样更改,如图:


打开unity3d项目,点击菜单“Edit”。在菜单中选择“Preferences...“,就会进入属性设置界面。选择左边的”External Tools“。在右边的“External Script Editor”选择“Visual Studio”。

这就可以愉快用Visual Studio编辑Unity3D的脚本了。

没有更多推荐了,返回首页