背景バージョンと履歴バージョンについては、このブログ投稿を確認してください。
UnityとBlueLakeのUIワークフロー最適化に関する考え方
最新バージョン:
この記事の目的は、Unityを使用しない他の人がツールを理解し、開発者がUnityでUIプレハブを構築できるようにすることです。これは、開発者の作業圧力を軽減するために、開発者が少し調整した後に使用できます。
UIビューのプレハブを作成する手順は次のとおりです。
1.ブルーレイクのビューに関連するすべての依存関係をダウンロードします
2.ダウンロードしたリソースパッケージを解凍した後、UnityのプロジェクトウィンドウのAssetsディレクトリにある任意のフォルダーにドラッグします
3.すべてのカット画像を選択し、[インスペクター]ウィンドウで[テクスチャタイプ]を[スプライトタイプ]に変更して、右下隅にある[適用]をクリックします。
4.トップメニューバーSKFrameworkでLanHuを見つけて、ウィンドウを開きます
5. [参照]ボタンをクリックして、ビューの切り抜きが配置されているフォルダーを選択します
6. [作成]をクリックしてキャンバスキャンバスを作成するか、シーン内の既存のキャンバスを選択できます
7.追加
[追加]ボタンをクリックして、UIビュー要素を追加します
ブルーレイクのカットマップのスタイル情報の内容をクリックしてコピーします
Unityに戻り、貼り付けボタンをクリックして、BlueLakeからコピーしたコンテンツを対応するパラメーターに貼り付けます
8.削除
「-」ボタンをクリックしてアイテムを削除します
[クリア]ボタンをクリックして、現在のすべての構成情報をクリアします
9.縮小
構成情報が多すぎる場合は、縮小ボタンをクリックして、折りたたまれたすべてのバーを閉じます
10.展開します
展開ボタンをクリックして、折りたたみ可能なすべての列を開きます
11.生成する
[生成]をクリックすると、ツールは、入力された構成情報に従ってカットが配置されているフォルダーに指定されたカットをロードし、指定された場所に設定し、指定されたサイズを設定し、最後に生成されたUIビューをプレハブとして作成します。
プレハブが生成されると、ツールはビューのすべての構成情報もアセットの形式で保存します
12.インポート
UIビューの要素を変更する場合は、インポートボタンをクリックしてビューの構成アセットファイルをインポートし、構成コンテンツを変更した後に再生成します。
13.生成されたUIビューをプレビューします
シーンウィンドウで2Dオプションを開きます
階層ウィンドウのキャンバスでUIビューを見つけ、ダブルクリックしてフォーカスします
ツールの完全なコード:
using System;
namespace SK.Framework
{
/// <summary>
/// 蓝湖界面UI元素
/// </summary>
[Serializable]
public class LanHuViewElement
{
/// <summary>
/// 图层名称
/// </summary>
public string name;
/// <summary>
/// 位置x
/// </summary>
public string x;
/// <summary>
/// 位置y
/// </summary>
public string y;
/// <summary>
/// 宽度
/// </summary>
public string width;
/// <summary>
/// 高度
/// </summary>
public string height;
/// <summary>
/// 不透明度
/// </summary>
public string opacity;
/// <summary>
/// 像素倍数
/// </summary>
public string pixel = "x1";
/// <summary>
/// 构造函数
/// </summary>
public LanHuViewElement(string name, string x, string y, string width, string height, string opacity, string pixel)
{
this.name = name;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.opacity = opacity;
this.pixel = pixel;
}
}
}
using UnityEngine;
using System.Collections.Generic;
namespace SK.Framework
{
public class LanHuView : ScriptableObject
{
/// <summary>
/// 存放切图的文件夹路径
/// </summary>
public string path;
public List<LanHuViewElement> elements = new List<LanHuViewElement>(0);
}
}
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
namespace SK.Framework
{
/// <summary>
/// 蓝湖UI界面搭建工具
/// </summary>
public class LanHu : EditorWindow
{
[MenuItem("SKFramework/LanHu")]
private static void Open()
{
GetWindow<LanHu>("LanHu").Show();
}
private string path;
private List<LanHuViewElement> elements;
private Vector2 scroll;
private const float labelWidth = 70f;
private Dictionary<LanHuViewElement, bool> foldoutDic;
private CanvasScaler canvasScaler;
private void OnEnable()
{
path = "Assets";
elements = new List<LanHuViewElement>();
foldoutDic = new Dictionary<LanHuViewElement, bool>();
}
private void OnGUI()
{
OnTopGUI();
OnElementsGUI();
OnMenuGUI();
}
private void OnTopGUI()
{
GUILayout.BeginHorizontal();
GUILayout.Label("切图文件夹路径:", GUILayout.Width(100f));
EditorGUILayout.TextField(path);
if (GUILayout.Button("浏览", GUILayout.Width(40f)))
{
//Assets相对路径
path = EditorUtility.OpenFolderPanel("选择切图文件夹", "", "").Replace(Application.dataPath, "Assets");
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Canvas Scaler", GUILayout.Width(100f));
canvasScaler = (CanvasScaler)EditorGUILayout.ObjectField(canvasScaler, typeof(CanvasScaler), true);
if (canvasScaler == null)
{
if (GUILayout.Button("创建", GUILayout.Width(40f)))
{
var canvas = new GameObject("Canvas").AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvasScaler = canvas.gameObject.AddComponent<CanvasScaler>();
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
canvasScaler.referenceResolution = new Vector2(1920f, 1080f);
EditorGUIUtility.PingObject(canvas);
}
}
GUILayout.EndHorizontal();
}
private void OnElementsGUI()
{
EditorGUILayout.Space();
GUI.enabled = canvasScaler != null;
scroll = EditorGUILayout.BeginScrollView(scroll);
for (int i = 0; i < elements.Count; i++)
{
var element = elements[i];
if (!foldoutDic.ContainsKey(element))
{
foldoutDic.Add(element, true);
}
foldoutDic[element] = EditorGUILayout.Foldout(foldoutDic[element], element.name, true);
if (!foldoutDic[element]) continue;
GUILayout.BeginVertical("Box");
GUILayout.BeginHorizontal();
GUILayout.Label("图层", GUILayout.Width(labelWidth));
element.name = EditorGUILayout.TextField(element.name);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.name = GUIUtility.systemCopyBuffer;
}
if (GUILayout.Button("-", GUILayout.Width(20f)))
{
foldoutDic.Remove(element);
elements.RemoveAt(i);
Repaint();
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("位置", GUILayout.Width(labelWidth));
element.x = EditorGUILayout.TextField(element.x);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.x = GUIUtility.systemCopyBuffer;
}
element.y = EditorGUILayout.TextField(element.y);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.y = GUIUtility.systemCopyBuffer;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("大小", GUILayout.Width(labelWidth));
element.width = EditorGUILayout.TextField(element.width);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.width = GUIUtility.systemCopyBuffer;
}
element.height = EditorGUILayout.TextField(element.height);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.height = GUIUtility.systemCopyBuffer;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("不透明度", GUILayout.Width(labelWidth));
element.opacity = EditorGUILayout.TextField(element.opacity);
if (GUILayout.Button("粘贴", GUILayout.Width(40f)))
{
element.opacity = GUIUtility.systemCopyBuffer;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("像素倍数", GUILayout.Width(labelWidth));
if (GUILayout.Button(element.pixel))
{
GenericMenu gm = new GenericMenu();
gm.AddItem(new GUIContent("x1"), element.pixel == "x1", () => element.pixel = "x1");
gm.AddItem(new GUIContent("x2"), element.pixel == "x2", () => element.pixel = "x2");
gm.ShowAsContext();
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
EditorGUILayout.EndScrollView();
}
private void OnMenuGUI()
{
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
if (GUILayout.Button("导入", "ButtonLeft"))
{
string presetPath = EditorUtility.OpenFilePanel("选择预设文件", Application.dataPath, "asset");
if (File.Exists(presetPath))
{
var import = AssetDatabase.LoadAssetAtPath<LanHuView>(presetPath.Replace(Application.dataPath, "Assets"));
if (import != null)
{
elements.Clear();
foldoutDic.Clear();
path = import.path;
for (int i = 0; i < import.elements.Count; i++)
{
elements.Add(import.elements[i]);
}
Repaint();
}
}
}
if (GUILayout.Button("添加", "ButtonMid"))
{
elements.Add(new LanHuViewElement("", "0px", "0px", "1920px", "1080px", "100%", "x1"));
}
if (GUILayout.Button("清空", "ButtonMid"))
{
if (EditorUtility.DisplayDialog("提醒", "确定删除当前所有配置信息?", "确定", "取消"))
{
elements.Clear();
foldoutDic.Clear();
}
}
if (GUILayout.Button("展开", "ButtonMid"))
{
for (int i = 0; i < elements.Count; i++)
{
foldoutDic[elements[i]] = true;
}
}
if (GUILayout.Button("收缩", "ButtonMid"))
{
for (int i = 0; i < elements.Count; i++)
{
foldoutDic[elements[i]] = false;
}
}
if (GUILayout.Button("生成", "ButtonRight"))
{
var array = path.Split('/');
var view = new GameObject(array[array.Length - 1]).AddComponent<RectTransform>();
view.transform.SetParent(canvasScaler.transform, false);
SetRectTransform(view, 0, 0, canvasScaler.referenceResolution.x, canvasScaler.referenceResolution.y);
for (int i = 0; i < elements.Count; i++)
{
var element = elements[i];
string spritePath = string.Format("{0}/{1}{2}.png", path, element.name, element.pixel == "x1" ? string.Empty : "@2x");
var obj = AssetDatabase.LoadAssetAtPath<Sprite>(spritePath);
if (obj != null)
{
var image = new GameObject(obj.name).AddComponent<Image>();
image.transform.SetParent(view.transform, false);
image.sprite = obj;
RectTransform rt = image.transform as RectTransform;
float.TryParse(element.x.Replace(element.x.Substring(element.x.Length - 2, 2), string.Empty), out float xValue);
float.TryParse(element.y.Replace(element.y.Substring(element.y.Length - 2, 2), string.Empty), out float yValue);
float.TryParse(element.width.Replace(element.width.Substring(element.width.Length - 2, 2), string.Empty), out float wValue);
float.TryParse(element.height.Replace(element.height.Substring(element.height.Length - 2, 2), string.Empty), out float hValue);
/*
float.TryParse(element.x, out float xValue);
float.TryParse(element.y, out float yValue);
float.TryParse(element.width, out float wValue);
float.TryParse(element.height, out float hValue);
*/
SetRectTransform(rt, xValue, yValue, wValue, hValue);
}
else
{
Debug.Log($"<color=yellow>加载切图失败 {spritePath}</color>");
}
}
//创建预设文件
var preset = CreateInstance<LanHuView>();
for (int i = 0; i < elements.Count; i++)
{
preset.elements.Add(elements[i]);
}
preset.path = path;
AssetDatabase.CreateAsset(preset, string.Format("Assets/{0}.asset", view.name));
AssetDatabase.Refresh();
Selection.activeObject = preset;
//创建Prefab
var prefab = PrefabUtility.SaveAsPrefabAsset(view.gameObject, $"Assets/{view.name}.prefab", out bool result);
if (!result)
{
Debug.Log($"<color=yellow>生成预制体失败 {view.name}</color>");
}
else
{
EditorGUIUtility.PingObject(prefab);
}
}
GUILayout.EndHorizontal();
}
private void SetRectTransform(RectTransform rt, float x, float y, float width, float height)
{
//调整位置及大小
rt.anchorMin = new Vector2(0, 1);
rt.anchorMax = new Vector2(0, 1);
rt.pivot = Vector2.one * .5f;
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
rt.anchoredPosition = new Vector2(x + width / 2f, -(y + height / 2f));
//调整完成后自动设置锚点
RectTransform prt = rt.parent as RectTransform;
Vector2 anchorMin = new Vector2(
rt.anchorMin.x + rt.offsetMin.x / prt.rect.width,
rt.anchorMin.y + rt.offsetMin.y / prt.rect.height);
Vector2 anchorMax = new Vector2(
rt.anchorMax.x + rt.offsetMax.x / prt.rect.width,
rt.anchorMax.y + rt.offsetMax.y / prt.rect.height);
rt.anchorMin = anchorMin;
rt.anchorMax = anchorMax;
rt.offsetMin = rt.offsetMax = Vector2.zero;
}
}
}