Unity es uno de los motores de juegos más populares utilizado tanto por desarrolladores independientes para crear juegos y aplicaciones móviles, como por empresas cuyos productos utilizan tecnologías de realidad virtual y aumentada.
, , , . , .
, , .
, Unity- .
.
, 3 . , , 3D-. .
, , . 3 - .
, 10? 20? 50?
, , . - . . .
?
, ! .
. , , (, , ), , , . .
OnValidate() , . . , OnValidate(), , MonoBehaviour.
.
, . , .
, «Editor»:
, , Unity . , "Editor" , Unity , , .
, , «Editor Window» ( «MonoBehaviour», ):
using UnityEngine;
using UnityEditor;
public class SceneUpdater : EditorWindow
{
[MenuItem("Custom Tools/Scene Updater")]
public static void ShowWindow()
{
GetWindow(typeof(SceneUpdater));
}
private void OnGUI()
{
if (GUILayout.Button("Update scenes"))
Debug.Log("Updating")
}
}
[MenuItem("Custom Tools/Scene Updater")] . :
, :
using UnityEngine;
using UnityEditor;
public class SceneUpdater : EditorWindow
{
[MenuItem("Custom Tools/Scene Updater")]
public static void ShowWindow()
{
GetWindow(typeof(SceneUpdater));
}
private void OnGUI()
{
if (GUILayout.Button("Update scenes"))
Debug.Log("Updating")
}
}
, .
:
/// <summary>
///
/// </summary>
/// <param name="objectName"> </param>
/// <typeparam name="T"> </typeparam>
private void AddComponentToObject<T>(string objectName) where T : Component
{
GameObject.Find(objectName)?.gameObject.AddComponent<T>();
}
:
AddComponentToObject<BoxCollider>("Plane");
AddComponentToObject<SampleClass>("EventSystem");
, .
:
/// <summary>
///
/// </summary>
/// <param name="objectName"> </param>
private void DestroyObjectWithName(string objectName)
{
DestroyImmediate(GameObject.Find(objectName)?.gameObject);
}
:
DestroyObjectWithName("Sphere");
,
Transform RectTransform , , (, ):
/// <summary>
/// , Transform
/// .
/// parent root
/// </summary>
/// <param name="objectToCopyFrom"> , </param>
/// <param name="objectToPasteTo"> , </param>
/// <param name="copyPosition"> , </param>
/// <param name="copeRotation"> , </param>
/// <param name="copyScale"> , </param>
private static void CopyTransformPositionRotationScale(GameObject objectToCopyFrom, GameObject objectToPasteTo,
bool copyPosition = true, bool copeRotation = true, bool copyScale = true)
{
var newTransform = objectToCopyFrom.GetComponent<Transform>();
var currentTransform = objectToPasteTo.GetComponent<Transform>();
if (copyPosition) currentTransform.localPosition = newTransform.localPosition;
if (copeRotation) currentTransform.localRotation = newTransform.localRotation;
if (copyScale) currentTransform.localScale = newTransform.localScale;
}
/// <summary>
/// , RectTransform UI-
/// . ( sizeDelta)
/// parent root
/// </summary>
/// <param name="objectToCopyFrom"> , </param>
/// <param name="objectToPasteTo"> , </param>
/// <param name="copyPosition"> , </param>
/// <param name="copeRotation"> , </param>
/// <param name="copyScale"> , </param>
private static void CopyRectTransformPositionRotationScale(GameObject objectToCopyFrom, GameObject objectToPasteTo,
bool copyPosition = true, bool copeRotation = true, bool copyScale = true)
{
var newTransform = objectToCopyFrom.GetComponent<RectTransform>();
var currentTransform = objectToPasteTo.GetComponent<RectTransform>();
if (copyPosition) currentTransform.localPosition = newTransform.localPosition;
if (copeRotation) currentTransform.localRotation = newTransform.localRotation;
if (copyScale) currentTransform.localScale = newTransform.localScale;
}
, , -, , :
var plane = GameObject.Find("Plane");
var cube = GameObject.Find("Cube");
CopyTransformPositionRotationScale(plane, cube, copyScale:false);
UI-
, Canvas, TextMeshPro RectTransform:
/// <summary>
/// Canvas
/// </summary>
/// <param name="canvasGameObject"> , </param>
/// <param name="renderMode"> </param>
/// <param name="scaleMode"> </param>
private void ChangeCanvasSettings(GameObject canvasGameObject, RenderMode renderMode, CanvasScaler.ScaleMode scaleMode)
{
canvasGameObject.GetComponentInChildren<Canvas>().renderMode = renderMode;
var canvasScaler = canvasGameObject.GetComponentInChildren<CanvasScaler>();
canvasScaler.uiScaleMode = scaleMode;
//
if (scaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize)
{
canvasScaler.referenceResolution = new Vector2(720f, 1280f);
canvasScaler.matchWidthOrHeight = 1f;
}
}
/// <summary>
/// TextMeshPro
/// </summary>
/// <param name="textMeshPro"> </param>
/// <param name="fontSizeMin"> </param>
/// <param name="fontSizeMax"> </param>
/// <param name="textAlignmentOption"> </param>
private void ChangeTMPSettings(TextMeshProUGUI textMeshPro, int fontSizeMin, int fontSizeMax, TextAlignmentOptions textAlignmentOption = TextAlignmentOptions.Center)
{
//
textMeshPro.font = (TMP_FontAsset) AssetDatabase.LoadAssetAtPath("Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset", typeof(TMP_FontAsset));
textMeshPro.enableAutoSizing = true;
textMeshPro.fontSizeMin = fontSizeMin;
textMeshPro.fontSizeMax = fontSizeMax;
textMeshPro.alignment = textAlignmentOption;
}
/// <summary>
/// RectTransform
/// </summary>
/// <param name="rectTransform"> </param>
/// <param name="alignment"> </param>
/// <param name="position"> 3D- </param>
/// <param name="size"> </param>
private void ChangeRectTransformSettings(RectTransform rectTransform, AnchorPresets alignment, Vector3 position, Vector2 size)
{
rectTransform.anchoredPosition3D = position;
rectTransform.sizeDelta = size;
rectTransform.SetAnchor(alignment);
}
, RectTransform , - Unity. Anchor Pivot. Utils:
:
RectTransformExtension.cs
using UnityEngine;
public enum AnchorPresets
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight,
VertStretchLeft,
VertStretchRight,
VertStretchCenter,
HorStretchTop,
HorStretchMiddle,
HorStretchBottom,
StretchAll
}
public enum PivotPresets
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight,
}
/// <summary>
/// RectTransform
/// </summary>
public static class RectTransformExtension
{
/// <summary>
///
/// </summary>
/// <param name="source"> , </param>
/// <param name="align"> </param>
/// <param name="offsetX"> X </param>
/// <param name="offsetY"> Y </param>
public static void SetAnchor(this RectTransform source, AnchorPresets align, int offsetX = 0, int offsetY = 0)
{
source.anchoredPosition = new Vector3(offsetX, offsetY, 0);
switch (align)
{
case (AnchorPresets.TopLeft):
{
source.anchorMin = new Vector2(0, 1);
source.anchorMax = new Vector2(0, 1);
break;
}
case (AnchorPresets.TopCenter):
{
source.anchorMin = new Vector2(0.5f, 1);
source.anchorMax = new Vector2(0.5f, 1);
break;
}
case (AnchorPresets.TopRight):
{
source.anchorMin = new Vector2(1, 1);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.MiddleLeft):
{
source.anchorMin = new Vector2(0, 0.5f);
source.anchorMax = new Vector2(0, 0.5f);
break;
}
case (AnchorPresets.MiddleCenter):
{
source.anchorMin = new Vector2(0.5f, 0.5f);
source.anchorMax = new Vector2(0.5f, 0.5f);
break;
}
case (AnchorPresets.MiddleRight):
{
source.anchorMin = new Vector2(1, 0.5f);
source.anchorMax = new Vector2(1, 0.5f);
break;
}
case (AnchorPresets.BottomLeft):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(0, 0);
break;
}
case (AnchorPresets.BottomCenter):
{
source.anchorMin = new Vector2(0.5f, 0);
source.anchorMax = new Vector2(0.5f, 0);
break;
}
case (AnchorPresets.BottomRight):
{
source.anchorMin = new Vector2(1, 0);
source.anchorMax = new Vector2(1, 0);
break;
}
case (AnchorPresets.HorStretchTop):
{
source.anchorMin = new Vector2(0, 1);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.HorStretchMiddle):
{
source.anchorMin = new Vector2(0, 0.5f);
source.anchorMax = new Vector2(1, 0.5f);
break;
}
case (AnchorPresets.HorStretchBottom):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(1, 0);
break;
}
case (AnchorPresets.VertStretchLeft):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(0, 1);
break;
}
case (AnchorPresets.VertStretchCenter):
{
source.anchorMin = new Vector2(0.5f, 0);
source.anchorMax = new Vector2(0.5f, 1);
break;
}
case (AnchorPresets.VertStretchRight):
{
source.anchorMin = new Vector2(1, 0);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.StretchAll):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(1, 1);
break;
}
}
}
/// <summary>
/// pivot
/// </summary>
/// <param name="source"> , </param>
/// <param name="preset"> </param>
public static void SetPivot(this RectTransform source, PivotPresets preset)
{
switch (preset)
{
case (PivotPresets.TopLeft):
{
source.pivot = new Vector2(0, 1);
break;
}
case (PivotPresets.TopCenter):
{
source.pivot = new Vector2(0.5f, 1);
break;
}
case (PivotPresets.TopRight):
{
source.pivot = new Vector2(1, 1);
break;
}
case (PivotPresets.MiddleLeft):
{
source.pivot = new Vector2(0, 0.5f);
break;
}
case (PivotPresets.MiddleCenter):
{
source.pivot = new Vector2(0.5f, 0.5f);
break;
}
case (PivotPresets.MiddleRight):
{
source.pivot = new Vector2(1, 0.5f);
break;
}
case (PivotPresets.BottomLeft):
{
source.pivot = new Vector2(0, 0);
break;
}
case (PivotPresets.BottomCenter):
{
source.pivot = new Vector2(0.5f, 0);
break;
}
case (PivotPresets.BottomRight):
{
source.pivot = new Vector2(1, 0);
break;
}
}
}
}
:
// Canvas
var canvas = GameObject.Find("Canvas");
ChangeCanvasSettings(canvas, RenderMode.ScreenSpaceOverlay, CanvasScaler.ScaleMode.ScaleWithScreenSize);
//
var tmp = canvas.GetComponentInChildren<TextMeshProUGUI>();
ChangeTMPSettings(tmp, 36, 72, TextAlignmentOptions.BottomRight);
// RectTransform
ChangeRectTransformSettings(tmp.GetComponent<RectTransform>(), AnchorPresets.MiddleCenter, Vector3.zero, new Vector2(100f, 20f));
, Transform ( ):
TransformExtension.cs
using UnityEngine;
/// <summary>
/// Transform
/// </summary>
public static class TransformExtension
{
/// <summary>
///
/// </summary>
/// <param name="parent"> </param>
/// <param name="childName"> </param>
/// <returns> null - ,
/// Transform ,
/// </returns>
public static Transform FindChildWithName(this Transform parent, string childName)
{
foreach (Transform child in parent)
{
if (child.name == childName)
return child;
var result = child.FindChildWithName(childName);
if (result)
return result;
}
return null;
}
}
, OnClick() - :
/// <summary>
/// ( )
/// </summary>
/// <param name="uiButton"> </param>
/// <param name="action"> </param>
private static void AddPersistentListenerToButton(Button uiButton, UnityAction action)
{
try
{
// ,
if (uiButton.onClick.GetPersistentTarget(0) == null)
UnityEventTools.RegisterPersistentListener(uiButton.onClick, 0, action);
}
catch (ArgumentException)
{
UnityEventTools.AddPersistentListener(uiButton.onClick, action);
}
}
, :
//
AddPersistentListenerToButton(canvas.GetComponentInChildren<Button>(), FindObjectOfType<SampleClass>().QuitApp);
:
, , , :
/// <summary>
///
/// </summary>
/// <param name="gameObject"> </param>
/// <param name="layerName"> </param>
private void ChangeObjectLayer(GameObject gameObject, string layerName)
{
gameObject.layer = LayerMask.NameToLayer(layerName);
}
/// <summary>
///
/// </summary>
/// <param name="prefabPath"> </param>
/// <param name="parentGameObject"> </param>
/// <param name="hierarchyIndex"> </param>
private void InstantiateNewGameObject(string prefabPath, GameObject parentGameObject, int hierarchyIndex = 0)
{
if (parentGameObject)
{
var newGameObject = Instantiate((GameObject) AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)), parentGameObject.transform);
//
newGameObject.transform.SetSiblingIndex(hierarchyIndex);
}
else
Instantiate((GameObject) AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)));
}
, :
//
var cube = GameObject.Find("Cube");
cube.tag = "Player";
ChangeObjectLayer(cube, "MainLayer");
//
InstantiateNewGameObject("Assets/Prefabs/Capsule.prefab", cube, 1);
, :
, - , -- , File ->Build Settings:
/// <summary>
/// Build Settings
/// </summary>
/// <param name="onSceneLoaded"> </param>
private void RunSceneUpdateCycle(UnityAction onSceneLoaded)
{
//
var scenes = EditorBuildSettings.scenes.Select(scene => scene.path).ToList();
foreach (var scene in scenes)
{
//
EditorSceneManager.OpenScene(scene);
// ,
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
//
onSceneLoaded?.Invoke();
//
EditorApplication.SaveScene();
Debug.Log($"UPDATED {scene}");
}
}
, :
SceneUpdater.cs
#if UNITY_EDITOR
using System;
using UnityEditor.Events;
using TMPro;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// , BuildSettings ( )
/// </summary>
public class SceneUpdater : EditorWindow
{
[MenuItem("Custom Tools/Scene Updater")]
public static void ShowWindow()
{
GetWindow(typeof(SceneUpdater));
}
private void OnGUI()
{
//
if (GUILayout.Button("Update scenes"))
RunSceneUpdateCycle((() =>
{
//
var cube = GameObject.Find("Cube");
cube.tag = "Player";
ChangeObjectLayer(cube, "MainLayer");
//
AddComponentToObject<BoxCollider>("Plane");
//
DestroyObjectWithName("Sphere");
//
InstantiateNewGameObject("Assets/Prefabs/Capsule.prefab", cube, 1);
// Canvas
var canvas = GameObject.Find("Canvas");
ChangeCanvasSettings(canvas, RenderMode.ScreenSpaceOverlay, CanvasScaler.ScaleMode.ScaleWithScreenSize);
//
var tmp = canvas.GetComponentInChildren<TextMeshProUGUI>();
ChangeTMPSettings(tmp, 36, 72, TextAlignmentOptions.BottomRight);
// RectTransform
ChangeRectTransformSettings(tmp.GetComponent<RectTransform>(), AnchorPresets.MiddleCenter, Vector3.zero, new Vector2(100f, 20f));
//
AddPersistentListenerToButton(canvas.GetComponentInChildren<Button>(), FindObjectOfType<SampleClass>().QuitApp);
//
CopyTransformPositionRotationScale(GameObject.Find("Plane"), cube, copyScale:false);
}));
}
/// <summary>
/// Build Settings
/// </summary>
/// <param name="onSceneLoaded"> </param>
private void RunSceneUpdateCycle(UnityAction onSceneLoaded)
{
//
var scenes = EditorBuildSettings.scenes.Select(scene => scene.path).ToList();
foreach (var scene in scenes)
{
//
EditorSceneManager.OpenScene(scene);
// ,
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
//
onSceneLoaded?.Invoke();
//
EditorApplication.SaveScene();
Debug.Log($"UPDATED {scene}");
}
}
/// <summary>
/// ( )
/// </summary>
/// <param name="uiButton"> </param>
/// <param name="action"> </param>
private static void AddPersistentListenerToButton(Button uiButton, UnityAction action)
{
try
{
// ,
if (uiButton.onClick.GetPersistentTarget(0) == null)
UnityEventTools.RegisterPersistentListener(uiButton.onClick, 0, action);
}
catch (ArgumentException)
{
UnityEventTools.AddPersistentListener(uiButton.onClick, action);
}
}
/// <summary>
/// RectTransform
/// </summary>
/// <param name="rectTransform"> </param>
/// <param name="alignment"> </param>
/// <param name="position"> 3D- </param>
/// <param name="size"> </param>
private void ChangeRectTransformSettings(RectTransform rectTransform, AnchorPresets alignment, Vector3 position, Vector2 size)
{
rectTransform.anchoredPosition3D = position;
rectTransform.sizeDelta = size;
rectTransform.SetAnchor(alignment);
}
/// <summary>
/// TextMeshPro
/// </summary>
/// <param name="textMeshPro"> </param>
/// <param name="fontSizeMin"> </param>
/// <param name="fontSizeMax"> </param>
/// <param name="textAlignmentOption"> </param>
private void ChangeTMPSettings(TextMeshProUGUI textMeshPro, int fontSizeMin, int fontSizeMax, TextAlignmentOptions textAlignmentOption = TextAlignmentOptions.Center)
{
//
textMeshPro.font = (TMP_FontAsset) AssetDatabase.LoadAssetAtPath("Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset", typeof(TMP_FontAsset));
textMeshPro.enableAutoSizing = true;
textMeshPro.fontSizeMin = fontSizeMin;
textMeshPro.fontSizeMax = fontSizeMax;
textMeshPro.alignment = textAlignmentOption;
}
/// <summary>
/// Canvas
/// </summary>
/// <param name="canvasGameObject"> , </param>
/// <param name="renderMode"> </param>
/// <param name="scaleMode"> </param>
private void ChangeCanvasSettings(GameObject canvasGameObject, RenderMode renderMode, CanvasScaler.ScaleMode scaleMode)
{
canvasGameObject.GetComponentInChildren<Canvas>().renderMode = renderMode;
var canvasScaler = canvasGameObject.GetComponentInChildren<CanvasScaler>();
canvasScaler.uiScaleMode = scaleMode;
//
if (scaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize)
{
canvasScaler.referenceResolution = new Vector2(720f, 1280f);
canvasScaler.matchWidthOrHeight = 1f;
}
}
/// <summary>
///
/// </summary>
/// <param name="parentGameObject"> </param>
/// <returns> </returns>
private static List<GameObject> GetAllChildren(GameObject parentGameObject)
{
var children = new List<GameObject>();
for (int i = 0; i< parentGameObject.transform.childCount; i++)
children.Add(parentGameObject.transform.GetChild(i).gameObject);
return children;
}
/// <summary>
/// , Transform
/// .
/// parent root
/// </summary>
/// <param name="objectToCopyFrom"> , </param>
/// <param name="objectToPasteTo"> , </param>
/// <param name="copyPosition"> , </param>
/// <param name="copyRotation"> , </param>
/// <param name="copyScale"> , </param>
private static void CopyTransformPositionRotationScale(GameObject objectToCopyFrom, GameObject objectToPasteTo,
bool copyPosition = true, bool copyRotation = true, bool copyScale = true)
{
var newTransform = objectToCopyFrom.GetComponent<Transform>();
var currentTransform = objectToPasteTo.GetComponent<Transform>();
if (copyPosition) currentTransform.localPosition = newTransform.localPosition;
if (copyRotation) currentTransform.localRotation = newTransform.localRotation;
if (copyScale) currentTransform.localScale = newTransform.localScale;
}
/// <summary>
/// , RectTransform UI-
/// . ( sizeDelta)
/// parent root
/// </summary>
/// <param name="objectToCopyFrom"> , </param>
/// <param name="objectToPasteTo"> , </param>
/// <param name="copyPosition"> , </param>
/// <param name="copyRotation"> , </param>
/// <param name="copyScale"> , </param>
private static void CopyRectTransformPositionRotationScale(GameObject objectToCopyFrom, GameObject objectToPasteTo,
bool copyPosition = true, bool copyRotation = true, bool copyScale = true)
{
var newTransform = objectToCopyFrom.GetComponent<RectTransform>();
var currentTransform = objectToPasteTo.GetComponent<RectTransform>();
if (copyPosition) currentTransform.localPosition = newTransform.localPosition;
if (copyRotation) currentTransform.localRotation = newTransform.localRotation;
if (copyScale) currentTransform.localScale = newTransform.localScale;
}
/// <summary>
///
/// </summary>
/// <param name="objectName"> </param>
private void DestroyObjectWithName(string objectName)
{
DestroyImmediate(GameObject.Find(objectName)?.gameObject);
}
/// <summary>
///
/// </summary>
/// <param name="objectName"> </param>
/// <typeparam name="T"> </typeparam>
private void AddComponentToObject<T>(string objectName) where T : Component
{
GameObject.Find(objectName)?.gameObject.AddComponent<T>();
}
/// <summary>
///
/// </summary>
/// <param name="gameObject"> </param>
/// <param name="layerName"> </param>
private void ChangeObjectLayer(GameObject gameObject, string layerName)
{
gameObject.layer = LayerMask.NameToLayer(layerName);
}
/// <summary>
///
/// </summary>
/// <param name="prefabPath"> </param>
/// <param name="parentGameObject"> </param>
/// <param name="hierarchyIndex"> </param>
private void InstantiateNewGameObject(string prefabPath, GameObject parentGameObject, int hierarchyIndex = 0)
{
if (parentGameObject)
{
var newGameObject = Instantiate((GameObject) AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)), parentGameObject.transform);
//
newGameObject.transform.SetSiblingIndex(hierarchyIndex);
}
else
Instantiate((GameObject) AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)));
}
}
#endif
, , :
, , : , , Fuse/IClone/DAZ , Build Pipeline, - .
, (.. RunSceneUpdateCycle).
, , IT, YouTube- IT DIVA. , GitHub, , , , ..
!