算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
unity-editor-tooling【设计与创意】Unity Editor scripting — custom Inspectors, PropertyDrawers, EditorWindow, MenuItems, asset post-processors, Editor Coroutines, automated builds via `-batchmode -executeMethod`. USE WHEN: building tools for designers, custom Inspector UI, gizmos, scene validators, asset import hooks, editor menu commands, headless CI builds. DO NOT USE FOR: runtime…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: unity-editor-tooling
description: |
Unity Editor scripting — custom Inspectors, PropertyDrawers, EditorWindow,
MenuItems, asset post-processors, Editor Coroutines, automated builds via
-batchmode -executeMethod.
USE WHEN: building tools for designers, custom Inspector UI, gizmos, scene validators, asset import hooks, editor menu commands, headless CI builds.
unity-input-ui); test runner (use
unity-testing).
allowed-tools: Read, Grep, Glob, Write, EditAssets/
Scripts/
Runtime.asmdef (no editor refs)
Editor.asmdef (Include Platforms = Editor only)
depends on Runtime + UnityEditor
Editor code never ships in player builds — keep it isolated.
[CustomEditor(typeof(EnemySpawner))]
public class EnemySpawnerEditor : Editor {
public override void OnInspectorGUI() {
DrawDefaultInspector();
var spawner = (EnemySpawner)target;
EditorGUILayout.Space();
if (GUILayout.Button("Spawn Test Wave")) {
if (Application.isPlaying) spawner.SpawnTestWave();
else Debug.LogWarning("Enter Play Mode first.");
}
}
}
Prefer UI Toolkit Inspectors (UXML/USS) for complex tools — better composition than IMGUI.
[CustomPropertyDrawer(typeof(MinMaxRangeAttribute))]
public class MinMaxRangeDrawer : PropertyDrawer {
public override void OnGUI(Rect r, SerializedProperty p, GUIContent l) {
var attr = (MinMaxRangeAttribute)attribute;
var min = p.FindPropertyRelative("min");
var max = p.FindPropertyRelative("max");
EditorGUI.MinMaxSlider(r, l, ref min.floatValue, ref max.floatValue, attr.Min, attr.Max);
}
}
public class LevelToolsWindow : EditorWindow {
[MenuItem("Tools/Level Tools")]
public static void Show() => GetWindow<LevelToolsWindow>("Level Tools");
private void OnGUI() {
if (GUILayout.Button("Bake Lighting")) Lightmapping.BakeAsync();
if (GUILayout.Button("Validate Scene")) ValidateActiveScene();
}
}
Auto-fix import settings for new sprites:
public class SpriteImporter : AssetPostprocessor {
void OnPreprocessTexture() {
if (!assetPath.Contains("/Sprites/")) return;
var ti = (TextureImporter)assetImporter;
ti.textureType = TextureImporterType.Sprite;
ti.spritePixelsPerUnit = 32;
ti.filterMode = FilterMode.Point;
ti.textureCompression = TextureImporterCompression.Uncompressed;
}
}
-batchmode)public static class CIBuild {
[MenuItem("Build/Build Windows")]
public static void BuildWindows() {
var opts = new BuildPlayerOptions {
scenes = new[] { "Assets/Scenes/Boot.unity", "Assets/Scenes/Main.unity" },
locationPathName = "Build/Win64/Game.exe",
target = BuildTarget.StandaloneWindows64,
options = BuildOptions.None,
};
var report = BuildPipeline.BuildPlayer(opts);
if (report.summary.result != BuildResult.Succeeded)
EditorApplication.Exit(1);
}
}
CI invocation:
Unity -batchmode -nographics -quit \
-projectPath . \
-executeMethod CIBuild.BuildWindows \
-logFile -
Combine with Addressables.BuildPlayerContent() before player build to prep content.
| Anti-pattern | Fix |
|---|---|
| Editor code mixed in Runtime asmdef | Split asmdef; gate with #if UNITY_EDITOR for one-offs |
| Heavy logic in OnInspectorGUI | Cache, only recompute on EditorUtility.SetDirty events |
EditorPrefs for project-shared state | Use ProjectSettings or assets in repo |
| Reflection-driven Inspectors with no fallback | Always provide DrawDefaultInspector path |
Tools/ namespace-batchmode -executeMethodAnalytics.RegisterEvent) opt-in only, scrubbed of PII