¿Cómo personalizo el script generado automáticamente?

11

Cuando crea una secuencia de comandos a través del editor de Unity, genera una secuencia de comandos con un código preformateado.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericClass : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

Cuando creo un script, generalmente tengo garantizado el uso de código adicional, como un espacio de nombres o un editor personalizado. Además, casi siempre elimino contenido del script generado automáticamente. ¿Hay alguna manera de cambiar el código automático generado por Unity?

Gnemlock
fuente
1
Nunca pensé en hacer esto. ¡Gracias por preguntar! Ahora para combinar las dos respuestas para tener una plantilla y luego analizarla para insertar información adicional, como el espacio de nombres ...
Draco18s ya no confía en SE

Respuestas:

4

Además también puedes

  1. Agregue un script de editor en la carpeta Assets / Editor que se suscribe a OnWillCreateAssetdonde puede analizar el resultado y modificarlo. Por ejemplo, el script que insertaría automáticamente el espacio de nombres podría verse así:

    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    
    using UnityEditor;
    
    public class InsertNS : UnityEditor.AssetModificationProcessor
    {
        public static void OnWillCreateAsset(string path)
        {
            string assetPath = Regex.Replace(path, @".meta$", string.Empty);
            if (!assetPath.EndsWith(".cs")) return;
    
            var code = File.ReadAllLines(assetPath).ToList();
            if (code.Any(line => line.Contains("namespace"))) return;//already added by IDE
    
            //insert namespace
            int idx = code.FindIndex(line => line
                .Contains("class " + Path.GetFileNameWithoutExtension(assetPath)));
            code.Insert(idx, Regex.Replace(
            assetPath.Replace('/','.'), @"^([\w+.]+)\.\w+\.cs$", "namespace $1 {\n"));
            code.Add("}");
    
            //correct indentation
            for (int i = idx + 1; i < code.Count - 1; i++) code[i] = '\t' + code[i];
    
            var finalCode = string.Join("\n", code.ToArray());
            File.WriteAllText(assetPath, finalCode);
            AssetDatabase.Refresh();
        }
    }
  2. Inserte secuencias de control propias en las plantillas para reemplazarlas fácilmente OnWillCreateAsset, por ej.

    finalCode = finalCode.Replace(@"#date#", DateTime.Now);
  3. Agregue más plantillas a la carpeta de plantillas, por ejemplo, una para el patrón Singleton: Unity no se limita a la plantilla de script único.

  4. Los fragmentos de código de Visual Studio son una forma de personalizar la creación de nuevos scripts (... y aún más, nuevas partes de scripts). Por ejemplo, un fragmento de código para privado SerializeFieldpodría ser útil. Después de importar privateField.snippet:

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <Title>
            Serialized private field
          </Title>
          <Author>Myself</Author>
          <Description>Adds private serializable field visible to Unity editor</Description>
          <Shortcut>pf</Shortcut>
        </Header>
        <Snippet>
          <Imports>
            <Import>
              <Namespace>UnityEngine</Namespace>
            </Import>
          </Imports>
          <Declarations>
            <Literal>
              <ID>FieldName</ID>
              <ToolTip>Replace with field name.</ToolTip>
              <Default>myField</Default>
            </Literal>
          </Declarations>
          <Code Language="CSharp">
            <![CDATA[[SerializeField] float _$FieldName$;]]>
          </Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>

    a Herramientas / Administrador de fragmentos de código / Mis fragmentos de código , simplemente puede escribir "pf" doble pestaña y escribir el nombre del campo. P.ej:

    //"pf" tab tab "speed" produces
    [SerializeField] float _speed;

    Aún más conveniente serían fragmentos para secuencias más largas que se repiten a menudo, por ejemplo, propiedad de solo lectura respaldada por SerializeFieldcampo.

  5. Visual Studio también ofrece una herramienta de generación de código muy poderosa, las Plantillas de texto T4 (EF está usando T4), aunque personalmente encuentro dudoso el uso práctico para proyectos de Unity: son excesivos, bastante complicados y la compilación del proyecto probablemente dependerá de Visual Estudio.

wondra
fuente
¡Esto ha funcionado a las mil maravillas! He agregado espacios de nombres relevantes para futuros usuarios. También tuve un problema más, aunque creo que podría ser uno único para mí; No puedo usar Path.GetFileWithoutExtension. Me dice que está intentando acceder a a MonoBehaviour, lo que parece extraño. Incluyo el espacio de nombres using Path = System.IO.Path.GetFileWithoutExtension, y pierdo Pathtodos juntos. Al final, tuve que renunciar completamente a la línea, en sí misma ( .Contains("class " + System.IO.Path.GetFileNameWithoutExtension(assetPath)));).
Gnemlock
¿Cuál es la forma más sencilla de garantizar que los archivos se creen con LF y UTF-8 en lugar de CRLF y UTF-8 con BOM?
Aaron Franke
@AaronFranke bueno ... esa es una solicitud bastante específica. Intentaría preguntar en stackoverflow.com cómo hacer string/ File.Writegenerar solo LF con BOM. Por lo que sé, '\ n' debería ser solo LF, también puede intentarlo, Environment.Newlinepero debería ser CRLF. También podría existir una opción para usar git hooks si todo lo demás falla. BOM debería ser fácil con esta pregunta de stackoverflow .
wondra
15

Puede encontrar las plantillas de script para generar código automáticamente en su carpeta de instalación de Unity. Encuentro las plantillas en "Unidad / Editor / Datos / Recursos / ScriptTemplates" , mientras que otras fuentes lo han encontrado en "Unidad / Editor / Datos / Recursos" .

Las plantillas genéricas UnityScript y C # se identifican como los archivos "82-Javascript-NewBehaviourScript.js.txt" y "81-C # Script-NewBehaviourScript.cs.txt" , respectivamente. Puede editar directamente estos archivos para cambiar la forma en que Unity genera automáticamente el script.

También puede incluir plantillas adicionales, que aparecerán cuando seleccione "Crear" en la ventana "Proyecto" . No parece que las plantillas requieran una numeración única, y use la cadena inicial para determinar la jerarquía del menú, donde "__" denota un submenú. Por ejemplo, tener un archivo llamado "81-C # Script__Editor Script-NewBehaviourScript.cs.txt" le dará un menú adicional " C # Script" , con la subopción para crear un "Editor Script" usando esta plantilla.

No , no cambiar el nombre de las plantillas originales; estos son utilizados más directamente por el motor. Por ejemplo, cambiar el nombre de "81-C # Script-NewBehaviourScript.cs.txt" evitará que agregue nuevos scripts C # como componentes, directamente a través del inspector.


A continuación se muestra mi propio ejemplo, aunque demuestra prácticas particulares a las que estoy más acostumbrado. Por ejemplo, prefiero tener mi script de editor personalizado en el mismo archivo que la clase de destino, así que lo encapsulo en #if UNITY_EDITOR .. #endiflugar de colocarlo en una carpeta de editor genérico "no compilar en la compilación".

No estoy seguro de si es posible proporcionar el contexto de un espacio de nombres personalizado; Simplemente uso "NAMESPACE", ya que esto me permite proporcionar el espacio de nombres correcto después de la creación, usando la función "encontrar ... reemplazar todo" comúnmente incorporada.


La plantilla:

/* Created by Gnemlock */

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace NAMESPACE
{
    public class #SCRIPTNAME# : MonoBehaviour 
    {
        /// <summary>This method will be called at the start of each frame where this 
        /// instance of <see cref="NAMESPACE.#SCRIPTNAME#"/> is enabled.</summary>
        void Update ()
        {
            #NOTRIM#
        }
    }
}

namespace NAMESPACE.UTILITY
{
    #if UNITY_EDITOR
    [CustomEditor(typeof(#SCRIPTNAME#))] public class #SCRIPTNAME#Editor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            #SCRIPTNAME# s#SCRIPTNAME# = target as #SCRIPTNAME#;
        }
    }
    #endif
}

La salida:

/* Created by Gnemlock */

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace MyNamespace
{

    public class UpdatedClass : MonoBehaviour 
    {
        /// <summary>This method will be called at the start of each frame where this 
        /// instance of <see cref="MyNamespace.UpdatedClass"/> is enabled.</summary>
        void Update ()
        {

        }
    }
}

namespace MyNamespace.UTILITY
{
    #if UNITY_EDITOR
    [CustomEditor(typeof(UpdatedClass))] public class UpdatedClassEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            UpdatedClass sUpdatedClass = target as UpdatedClass;
        }
    }
    #endif
}
Gnemlock
fuente