galgame,编辑器内蓝图
This commit is contained in:
@@ -0,0 +1,470 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.GraphView;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class IngameGalgameGraphWindow : EditorWindow
|
||||
{
|
||||
private ingame_galgame_so currentSo;
|
||||
private IngameGalgameGraphView graphView;
|
||||
private ObjectField soField;
|
||||
|
||||
public static void Open(ingame_galgame_so so)
|
||||
{
|
||||
var window = GetWindow<IngameGalgameGraphWindow>("Galgame 蓝图");
|
||||
window.Show();
|
||||
window.SetSo(so);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
CreateGraphView();
|
||||
CreateToolbar();
|
||||
if (currentSo == null)
|
||||
{
|
||||
currentSo = Selection.activeObject as ingame_galgame_so;
|
||||
}
|
||||
SetSo(currentSo);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
rootVisualElement.Clear();
|
||||
graphView = null;
|
||||
}
|
||||
|
||||
private void CreateGraphView()
|
||||
{
|
||||
graphView = new IngameGalgameGraphView();
|
||||
graphView.StretchToParentSize();
|
||||
rootVisualElement.Add(graphView);
|
||||
}
|
||||
|
||||
private void CreateToolbar()
|
||||
{
|
||||
var toolbar = new Toolbar();
|
||||
var addBtn = new ToolbarButton(() => graphView?.CreateNodeAt(graphView.GetDefaultNodePosition())) { text = "+" };
|
||||
var delBtn = new ToolbarButton(() => graphView?.DeleteSelected()) { text = "-" };
|
||||
toolbar.Add(addBtn);
|
||||
toolbar.Add(delBtn);
|
||||
soField = new ObjectField("数据") { objectType = typeof(ingame_galgame_so), allowSceneObjects = false };
|
||||
soField.RegisterValueChangedCallback(evt => SetSo(evt.newValue as ingame_galgame_so));
|
||||
toolbar.Add(soField);
|
||||
var refreshBtn = new ToolbarButton(RefreshGraph) { text = "刷新" };
|
||||
toolbar.Add(refreshBtn);
|
||||
rootVisualElement.Add(toolbar);
|
||||
}
|
||||
|
||||
private void SetSo(ingame_galgame_so so)
|
||||
{
|
||||
currentSo = so;
|
||||
if (soField != null && soField.value != so)
|
||||
{
|
||||
soField.SetValueWithoutNotify(so);
|
||||
}
|
||||
RefreshGraph();
|
||||
}
|
||||
|
||||
private void RefreshGraph()
|
||||
{
|
||||
if (graphView == null) return;
|
||||
graphView.Build(currentSo);
|
||||
}
|
||||
}
|
||||
|
||||
class IngameGalgameGraphView : GraphView
|
||||
{
|
||||
private ingame_galgame_so currentSo;
|
||||
|
||||
public IngameGalgameGraphView()
|
||||
{
|
||||
this.AddManipulator(new ContentZoomer());
|
||||
this.AddManipulator(new ContentDragger());
|
||||
this.AddManipulator(new SelectionDragger());
|
||||
this.AddManipulator(new RectangleSelector());
|
||||
var grid = new GridBackground();
|
||||
Insert(0, grid);
|
||||
grid.StretchToParentSize();
|
||||
SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale);
|
||||
RegisterCallback<KeyDownEvent>(OnKeyDown);
|
||||
}
|
||||
|
||||
public void Build(ingame_galgame_so so)
|
||||
{
|
||||
ClearGraph();
|
||||
currentSo = so;
|
||||
if (so == null) return;
|
||||
var serialized = new SerializedObject(so);
|
||||
var dialogueList = serialized.FindProperty("dialogueList");
|
||||
if (dialogueList == null || !dialogueList.isArray) return;
|
||||
var speakerNames = BuildSpeakerNames(serialized);
|
||||
DialogueTextNode prev = null;
|
||||
for (int i = 0; i < dialogueList.arraySize; i++)
|
||||
{
|
||||
var elemProp = dialogueList.GetArrayElementAtIndex(i);
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp == null || !textListProp.isArray) continue;
|
||||
for (int j = 0; j < textListProp.arraySize; j++)
|
||||
{
|
||||
var textProp = textListProp.GetArrayElementAtIndex(j);
|
||||
var node = CreateTextNode(serialized, positionTagProp, textProp, speakerNames, i, j);
|
||||
node.SetPosition(new Rect(80 + i * 420, 80 + j * 260, 360, 220));
|
||||
AddElement(node);
|
||||
if (prev != null)
|
||||
{
|
||||
var edge = prev.output.ConnectTo(node.input);
|
||||
AddElement(edge);
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearGraph()
|
||||
{
|
||||
var toRemove = new List<GraphElement>();
|
||||
foreach (var element in graphElements)
|
||||
{
|
||||
toRemove.Add(element);
|
||||
}
|
||||
DeleteElements(toRemove);
|
||||
}
|
||||
|
||||
private DialogueTextNode CreateTextNode(SerializedObject so, SerializedProperty positionTagProp, SerializedProperty textProp, string[] speakerNames, int elemIndex, int textIndex)
|
||||
{
|
||||
var node = new DialogueTextNode();
|
||||
node.title = $"段落 {elemIndex + 1} / 文本 {textIndex + 1}";
|
||||
node.elementIndex = elemIndex;
|
||||
node.textIndex = textIndex;
|
||||
node.input = node.InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, typeof(float));
|
||||
node.input.portName = "输入";
|
||||
node.output = node.InstantiatePort(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, typeof(float));
|
||||
node.output.portName = "输出";
|
||||
node.inputContainer.Add(node.input);
|
||||
node.outputContainer.Add(node.output);
|
||||
|
||||
if (positionTagProp != null)
|
||||
{
|
||||
var field = new PropertyField(positionTagProp, "位置标签");
|
||||
field.Bind(so);
|
||||
node.extensionContainer.Add(field);
|
||||
}
|
||||
|
||||
AddTextField(node, so, textProp.FindPropertyRelative("content"), "内容");
|
||||
AddIntPopup(node, so, textProp.FindPropertyRelative("senderIndex"), speakerNames);
|
||||
AddField(node, so, textProp.FindPropertyRelative("imagePos"), "图片位置");
|
||||
AddField(node, so, textProp.FindPropertyRelative("flipX"), "水平翻转");
|
||||
AddField(node, so, textProp.FindPropertyRelative("appearTime"), "出现时间");
|
||||
AddField(node, so, textProp.FindPropertyRelative("duration"), "持续时间");
|
||||
AddField(node, so, textProp.FindPropertyRelative("stepMethod"), "步进方式");
|
||||
AddField(node, so, textProp.FindPropertyRelative("timeAction"), "时间动作");
|
||||
AddField(node, so, textProp.FindPropertyRelative("slowMotionScale"), "慢动作倍率");
|
||||
AddField(node, so, textProp.FindPropertyRelative("endAction"), "结束动作");
|
||||
|
||||
node.RefreshExpandedState();
|
||||
node.RefreshPorts();
|
||||
return node;
|
||||
}
|
||||
|
||||
private void AddTextField(Node node, SerializedObject so, SerializedProperty prop, string label)
|
||||
{
|
||||
if (prop == null) return;
|
||||
var field = new PropertyField(prop, label);
|
||||
field.Bind(so);
|
||||
node.extensionContainer.Add(field);
|
||||
}
|
||||
|
||||
private void AddField(Node node, SerializedObject so, SerializedProperty prop, string label)
|
||||
{
|
||||
if (prop == null) return;
|
||||
var field = new PropertyField(prop, label);
|
||||
field.Bind(so);
|
||||
node.extensionContainer.Add(field);
|
||||
}
|
||||
|
||||
private void AddIntPopup(Node node, SerializedObject so, SerializedProperty senderIndexProp, string[] speakerNames)
|
||||
{
|
||||
if (senderIndexProp == null) return;
|
||||
if (speakerNames == null || speakerNames.Length == 0)
|
||||
{
|
||||
AddField(node, so, senderIndexProp, "发言者索引");
|
||||
return;
|
||||
}
|
||||
var imgui = new IMGUIContainer(() =>
|
||||
{
|
||||
so.Update();
|
||||
int current = Mathf.Clamp(senderIndexProp.intValue + 1, 0, speakerNames.Length - 1);
|
||||
int chosen = EditorGUILayout.Popup("发言者", current, speakerNames);
|
||||
senderIndexProp.intValue = Mathf.Max(-1, chosen - 1);
|
||||
so.ApplyModifiedProperties();
|
||||
});
|
||||
node.extensionContainer.Add(imgui);
|
||||
}
|
||||
|
||||
private string[] BuildSpeakerNames(SerializedObject so)
|
||||
{
|
||||
var speakersDataSOProp = so.FindProperty("speakersDataSO");
|
||||
if (speakersDataSOProp == null || speakersDataSOProp.objectReferenceValue == null) return null;
|
||||
var speakersSO = new SerializedObject(speakersDataSOProp.objectReferenceValue);
|
||||
var speakersList = speakersSO.FindProperty("speakers");
|
||||
if (speakersList == null || !speakersList.isArray) return null;
|
||||
int c = speakersList.arraySize;
|
||||
var names = new string[c + 1];
|
||||
names[0] = "(无)";
|
||||
for (int i = 0; i < c; i++)
|
||||
{
|
||||
var e = speakersList.GetArrayElementAtIndex(i);
|
||||
var nameProp = e.FindPropertyRelative("spkrName");
|
||||
names[i + 1] = nameProp != null ? nameProp.stringValue : $"Speaker {i}";
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public Vector2 GetDefaultNodePosition()
|
||||
{
|
||||
var worldCenter = new Vector2(layout.xMin + layout.width * 0.5f, layout.yMin + layout.height * 0.5f);
|
||||
return contentViewContainer.WorldToLocal(worldCenter);
|
||||
}
|
||||
|
||||
public void CreateNodeAt(Vector2 position)
|
||||
{
|
||||
if (currentSo == null) return;
|
||||
Undo.RecordObject(currentSo, "Create Dialogue Node");
|
||||
var so = new SerializedObject(currentSo);
|
||||
var dialogueList = so.FindProperty("dialogueList");
|
||||
if (dialogueList == null) return;
|
||||
int elemIndex = dialogueList.arraySize;
|
||||
dialogueList.arraySize++;
|
||||
var elemProp = dialogueList.GetArrayElementAtIndex(elemIndex);
|
||||
if (elemProp != null)
|
||||
{
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
if (positionTagProp != null) positionTagProp.enumValueIndex = 0;
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp != null)
|
||||
{
|
||||
textListProp.arraySize = 1;
|
||||
var textProp = textListProp.GetArrayElementAtIndex(0);
|
||||
ApplyTextDefaults(textProp);
|
||||
}
|
||||
}
|
||||
so.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(currentSo);
|
||||
Build(currentSo);
|
||||
}
|
||||
|
||||
public void DeleteSelected()
|
||||
{
|
||||
if (currentSo == null) return;
|
||||
var selectedNodes = new List<DialogueTextNode>();
|
||||
foreach (var e in selection)
|
||||
{
|
||||
if (e is DialogueTextNode n) selectedNodes.Add(n);
|
||||
}
|
||||
if (selectedNodes.Count == 0) return;
|
||||
selectedNodes.Sort((a, b) =>
|
||||
{
|
||||
int c = b.elementIndex.CompareTo(a.elementIndex);
|
||||
return c != 0 ? c : b.textIndex.CompareTo(a.textIndex);
|
||||
});
|
||||
Undo.RecordObject(currentSo, "Delete Dialogue Node");
|
||||
var so = new SerializedObject(currentSo);
|
||||
var dialogueList = so.FindProperty("dialogueList");
|
||||
if (dialogueList == null) return;
|
||||
foreach (var node in selectedNodes)
|
||||
{
|
||||
if (node.elementIndex < 0 || node.elementIndex >= dialogueList.arraySize) continue;
|
||||
var elemProp = dialogueList.GetArrayElementAtIndex(node.elementIndex);
|
||||
if (elemProp == null) continue;
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp == null) continue;
|
||||
if (node.textIndex >= 0 && node.textIndex < textListProp.arraySize)
|
||||
{
|
||||
textListProp.DeleteArrayElementAtIndex(node.textIndex);
|
||||
}
|
||||
if (textListProp.arraySize <= 0)
|
||||
{
|
||||
dialogueList.DeleteArrayElementAtIndex(node.elementIndex);
|
||||
}
|
||||
}
|
||||
so.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(currentSo);
|
||||
Build(currentSo);
|
||||
}
|
||||
|
||||
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
|
||||
{
|
||||
evt.menu.AppendAction("新建节点", _ => CreateNodeAt(evt.localMousePosition));
|
||||
bool hasSelection = false;
|
||||
foreach (var e in selection)
|
||||
{
|
||||
if (e is DialogueTextNode) { hasSelection = true; break; }
|
||||
}
|
||||
evt.menu.AppendAction("删除所选", _ => DeleteSelected(), hasSelection ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled);
|
||||
}
|
||||
|
||||
private void OnKeyDown(KeyDownEvent evt)
|
||||
{
|
||||
if (evt.ctrlKey && evt.keyCode == KeyCode.C)
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = SerializeSelection();
|
||||
evt.StopPropagation();
|
||||
}
|
||||
else if (evt.ctrlKey && evt.keyCode == KeyCode.V)
|
||||
{
|
||||
PasteFromClipboard();
|
||||
evt.StopPropagation();
|
||||
}
|
||||
else if (evt.keyCode == KeyCode.Delete || evt.keyCode == KeyCode.Backspace)
|
||||
{
|
||||
DeleteSelected();
|
||||
evt.StopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private string SerializeSelection()
|
||||
{
|
||||
if (currentSo == null) return string.Empty;
|
||||
var payload = new DialogueCopyPayload();
|
||||
var so = new SerializedObject(currentSo);
|
||||
var dialogueList = so.FindProperty("dialogueList");
|
||||
foreach (var e in selection)
|
||||
{
|
||||
if (e is not DialogueTextNode node) continue;
|
||||
if (dialogueList == null) continue;
|
||||
if (node.elementIndex < 0 || node.elementIndex >= dialogueList.arraySize) continue;
|
||||
var elemProp = dialogueList.GetArrayElementAtIndex(node.elementIndex);
|
||||
if (elemProp == null) continue;
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp == null) continue;
|
||||
if (node.textIndex < 0 || node.textIndex >= textListProp.arraySize) continue;
|
||||
var textProp = textListProp.GetArrayElementAtIndex(node.textIndex);
|
||||
if (textProp == null) continue;
|
||||
var data = new DialogueTextCopyData();
|
||||
data.positionTag = positionTagProp != null ? positionTagProp.enumValueIndex : 0;
|
||||
data.content = textProp.FindPropertyRelative("content")?.stringValue;
|
||||
data.textNumber = textProp.FindPropertyRelative("textNumber")?.intValue ?? 0;
|
||||
data.senderIndex = textProp.FindPropertyRelative("senderIndex")?.intValue ?? -1;
|
||||
data.imagePos = textProp.FindPropertyRelative("imagePos")?.enumValueIndex ?? 0;
|
||||
data.flipX = textProp.FindPropertyRelative("flipX")?.boolValue ?? false;
|
||||
data.appearTime = textProp.FindPropertyRelative("appearTime")?.floatValue ?? 0f;
|
||||
data.duration = textProp.FindPropertyRelative("duration")?.floatValue ?? 0f;
|
||||
data.stepMethod = textProp.FindPropertyRelative("stepMethod")?.enumValueIndex ?? 0;
|
||||
data.timeAction = textProp.FindPropertyRelative("timeAction")?.enumValueIndex ?? 0;
|
||||
data.slowMotionScale = textProp.FindPropertyRelative("slowMotionScale")?.floatValue ?? 0f;
|
||||
data.endAction = textProp.FindPropertyRelative("endAction")?.enumValueIndex ?? 0;
|
||||
payload.items.Add(data);
|
||||
}
|
||||
return payload.items.Count == 0 ? string.Empty : JsonUtility.ToJson(payload);
|
||||
}
|
||||
|
||||
private bool CanPasteDataInternal(string serializedData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(serializedData)) return false;
|
||||
var payload = JsonUtility.FromJson<DialogueCopyPayload>(serializedData);
|
||||
return payload != null && payload.items != null && payload.items.Count > 0;
|
||||
}
|
||||
|
||||
private void PasteFromClipboard()
|
||||
{
|
||||
if (currentSo == null) return;
|
||||
var serializedData = EditorGUIUtility.systemCopyBuffer;
|
||||
if (!CanPasteDataInternal(serializedData)) return;
|
||||
var payload = JsonUtility.FromJson<DialogueCopyPayload>(serializedData);
|
||||
if (payload == null || payload.items == null || payload.items.Count == 0) return;
|
||||
Undo.RecordObject(currentSo, "Paste Dialogue Node");
|
||||
var so = new SerializedObject(currentSo);
|
||||
var dialogueList = so.FindProperty("dialogueList");
|
||||
if (dialogueList == null) return;
|
||||
foreach (var item in payload.items)
|
||||
{
|
||||
int elemIndex = dialogueList.arraySize;
|
||||
dialogueList.arraySize++;
|
||||
var elemProp = dialogueList.GetArrayElementAtIndex(elemIndex);
|
||||
if (elemProp == null) continue;
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
if (positionTagProp != null) positionTagProp.enumValueIndex = item.positionTag;
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp != null)
|
||||
{
|
||||
textListProp.arraySize = 1;
|
||||
var textProp = textListProp.GetArrayElementAtIndex(0);
|
||||
ApplyTextData(textProp, item);
|
||||
}
|
||||
}
|
||||
so.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(currentSo);
|
||||
Build(currentSo);
|
||||
}
|
||||
|
||||
private void ApplyTextDefaults(SerializedProperty textProp)
|
||||
{
|
||||
if (textProp == null) return;
|
||||
textProp.FindPropertyRelative("content").stringValue = string.Empty;
|
||||
textProp.FindPropertyRelative("textNumber").intValue = 1;
|
||||
textProp.FindPropertyRelative("senderIndex").intValue = -1;
|
||||
textProp.FindPropertyRelative("imagePos").enumValueIndex = 0;
|
||||
var flipXProp = textProp.FindPropertyRelative("flipX");
|
||||
if (flipXProp != null) flipXProp.boolValue = false;
|
||||
textProp.FindPropertyRelative("appearTime").floatValue = 0f;
|
||||
textProp.FindPropertyRelative("duration").floatValue = 0f;
|
||||
textProp.FindPropertyRelative("stepMethod").enumValueIndex = 0;
|
||||
textProp.FindPropertyRelative("timeAction").enumValueIndex = 0;
|
||||
textProp.FindPropertyRelative("slowMotionScale").floatValue = 0f;
|
||||
textProp.FindPropertyRelative("endAction").enumValueIndex = 0;
|
||||
}
|
||||
|
||||
private void ApplyTextData(SerializedProperty textProp, DialogueTextCopyData data)
|
||||
{
|
||||
if (textProp == null || data == null) return;
|
||||
textProp.FindPropertyRelative("content").stringValue = data.content ?? string.Empty;
|
||||
textProp.FindPropertyRelative("textNumber").intValue = data.textNumber;
|
||||
textProp.FindPropertyRelative("senderIndex").intValue = data.senderIndex;
|
||||
textProp.FindPropertyRelative("imagePos").enumValueIndex = data.imagePos;
|
||||
var flipXProp = textProp.FindPropertyRelative("flipX");
|
||||
if (flipXProp != null) flipXProp.boolValue = data.flipX;
|
||||
textProp.FindPropertyRelative("appearTime").floatValue = data.appearTime;
|
||||
textProp.FindPropertyRelative("duration").floatValue = data.duration;
|
||||
textProp.FindPropertyRelative("stepMethod").enumValueIndex = data.stepMethod;
|
||||
textProp.FindPropertyRelative("timeAction").enumValueIndex = data.timeAction;
|
||||
textProp.FindPropertyRelative("slowMotionScale").floatValue = data.slowMotionScale;
|
||||
textProp.FindPropertyRelative("endAction").enumValueIndex = data.endAction;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class DialogueTextCopyData
|
||||
{
|
||||
public int positionTag;
|
||||
public string content;
|
||||
public int textNumber;
|
||||
public int senderIndex;
|
||||
public int imagePos;
|
||||
public bool flipX;
|
||||
public float appearTime;
|
||||
public float duration;
|
||||
public int stepMethod;
|
||||
public int timeAction;
|
||||
public float slowMotionScale;
|
||||
public int endAction;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class DialogueCopyPayload
|
||||
{
|
||||
public List<DialogueTextCopyData> items = new List<DialogueTextCopyData>();
|
||||
}
|
||||
}
|
||||
|
||||
class DialogueTextNode : Node
|
||||
{
|
||||
public Port input;
|
||||
public Port output;
|
||||
public int elementIndex;
|
||||
public int textIndex;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d28dfb6d5ec60d4590e7d1b15af33fb
|
||||
@@ -1,6 +1,9 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
[CustomEditor(typeof(ScriptableObject), true)]
|
||||
public class ingame_galgame_so_Editor : Editor
|
||||
@@ -11,6 +14,28 @@ public class ingame_galgame_so_Editor : Editor
|
||||
private SerializedProperty speakersDataSOProp;
|
||||
private SerializedProperty dialogueListProp;
|
||||
|
||||
private ReorderableList dialogueListRl;
|
||||
private readonly Dictionary<string, ReorderableList> textListRlMap = new Dictionary<string, ReorderableList>();
|
||||
private string[] speakerNames;
|
||||
|
||||
private readonly GUIContent labelDialogueType = new GUIContent("对话类型");
|
||||
private readonly GUIContent labelTriggerMethod = new GUIContent("触发方式");
|
||||
private readonly GUIContent labelTimelineStandard = new GUIContent("时间线基准");
|
||||
private readonly GUIContent labelSpeakers = new GUIContent("角色数据");
|
||||
private readonly GUIContent labelPositionTag = new GUIContent("位置标签");
|
||||
private readonly GUIContent labelContent = new GUIContent("内容");
|
||||
private readonly GUIContent labelTextNumber = new GUIContent("文本序号");
|
||||
private readonly GUIContent labelSender = new GUIContent("发言者");
|
||||
private readonly GUIContent labelSenderIndex = new GUIContent("发言者索引");
|
||||
private readonly GUIContent labelImagePos = new GUIContent("图片位置");
|
||||
private readonly GUIContent labelFlipX = new GUIContent("水平翻转");
|
||||
private readonly GUIContent labelAppearTime = new GUIContent("出现时间");
|
||||
private readonly GUIContent labelDuration = new GUIContent("持续时间");
|
||||
private readonly GUIContent labelStepMethod = new GUIContent("步进方式");
|
||||
private readonly GUIContent labelTimeAction = new GUIContent("时间动作");
|
||||
private readonly GUIContent labelSlowMotionScale = new GUIContent("慢动作倍率");
|
||||
private readonly GUIContent labelEndAction = new GUIContent("结束动作");
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (target != null && target.GetType().Name == "ingame_galgame_so")
|
||||
@@ -21,6 +46,8 @@ public class ingame_galgame_so_Editor : Editor
|
||||
speakersDataSOProp = serializedObject.FindProperty("speakersDataSO");
|
||||
dialogueListProp = serializedObject.FindProperty("dialogueList");
|
||||
}
|
||||
dialogueListRl = null;
|
||||
textListRlMap.Clear();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
@@ -33,192 +60,232 @@ public class ingame_galgame_so_Editor : Editor
|
||||
|
||||
serializedObject.Update();
|
||||
EnsureProperties();
|
||||
BuildSpeakerNames();
|
||||
|
||||
if (dialogueTypeProp != null) EditorGUILayout.PropertyField(dialogueTypeProp);
|
||||
if (triggerMethodProp != null) EditorGUILayout.PropertyField(triggerMethodProp);
|
||||
if (timelineStandardProp != null) EditorGUILayout.PropertyField(timelineStandardProp);
|
||||
if (speakersDataSOProp != null) EditorGUILayout.PropertyField(speakersDataSOProp);
|
||||
DrawGlobalSection();
|
||||
DrawDialogueSection();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Dialogue List", EditorStyles.boldLabel);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// speaker dropdown data
|
||||
string[] speakerNames = null;
|
||||
Object speakersObj = speakersDataSOProp != null ? speakersDataSOProp.objectReferenceValue : null;
|
||||
|
||||
if (speakersObj != null)
|
||||
private void DrawGlobalSection()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
EditorGUILayout.LabelField("全局配置", EditorStyles.boldLabel);
|
||||
if (dialogueTypeProp != null) EditorGUILayout.PropertyField(dialogueTypeProp, labelDialogueType);
|
||||
if (triggerMethodProp != null) EditorGUILayout.PropertyField(triggerMethodProp, labelTriggerMethod);
|
||||
if (timelineStandardProp != null) EditorGUILayout.PropertyField(timelineStandardProp, labelTimelineStandard);
|
||||
if (speakersDataSOProp != null) EditorGUILayout.PropertyField(speakersDataSOProp, labelSpeakers);
|
||||
if (GUILayout.Button("打开蓝图视图"))
|
||||
{
|
||||
var speakersSO = new SerializedObject(speakersObj);
|
||||
var speakersList = speakersSO.FindProperty("speakers");
|
||||
|
||||
if (speakersList != null && speakersList.isArray)
|
||||
{
|
||||
int c = speakersList.arraySize;
|
||||
|
||||
speakerNames = new string[c + 1];
|
||||
speakerNames[0] = "(None)";
|
||||
|
||||
for (int i = 0; i < c; i++)
|
||||
{
|
||||
var e = speakersList.GetArrayElementAtIndex(i);
|
||||
var nameProp = e.FindPropertyRelative("spkrName");
|
||||
|
||||
speakerNames[i + 1] =
|
||||
nameProp != null ? nameProp.stringValue : $"Speaker {i}";
|
||||
}
|
||||
}
|
||||
var t = typeof(ingame_galgame_so_Editor).Assembly.GetType("IngameGalgameGraphWindow");
|
||||
var m = t != null ? t.GetMethod("Open", BindingFlags.Public | BindingFlags.Static) : null;
|
||||
if (m != null) m.Invoke(null, new object[] { target as ingame_galgame_so });
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawDialogueSection()
|
||||
{
|
||||
if (dialogueListProp == null)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== DRAW ELEMENTS =====
|
||||
EnsureDialogueList();
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
dialogueListRl.DoLayoutList();
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
for (int i = 0; i < dialogueListProp.arraySize; i++)
|
||||
private void EnsureDialogueList()
|
||||
{
|
||||
if (dialogueListRl != null && dialogueListRl.serializedProperty == dialogueListProp) return;
|
||||
dialogueListRl = new ReorderableList(serializedObject, dialogueListProp, true, true, true, true);
|
||||
dialogueListRl.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "对话列表");
|
||||
dialogueListRl.elementHeightCallback = index =>
|
||||
{
|
||||
var elemProp = dialogueListProp.GetArrayElementAtIndex(i);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
elemProp.isExpanded =
|
||||
EditorGUILayout.Foldout(elemProp.isExpanded, $"Element {i}", true);
|
||||
|
||||
// Move up
|
||||
GUI.enabled = i > 0;
|
||||
if (GUILayout.Button("Up", GUILayout.Width(32)))
|
||||
var elemProp = dialogueListProp.GetArrayElementAtIndex(index);
|
||||
float line = EditorGUIUtility.singleLineHeight;
|
||||
float space = EditorGUIUtility.standardVerticalSpacing;
|
||||
float h = line + space;
|
||||
if (elemProp != null && elemProp.isExpanded)
|
||||
{
|
||||
dialogueListProp.MoveArrayElement(i, i - 1);
|
||||
}
|
||||
|
||||
// Move down
|
||||
GUI.enabled = i < dialogueListProp.arraySize - 1;
|
||||
if (GUILayout.Button("Down", GUILayout.Width(42)))
|
||||
{
|
||||
dialogueListProp.MoveArrayElement(i, i + 1);
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
// Duplicate
|
||||
if (GUILayout.Button("D", GUILayout.Width(25)))
|
||||
{
|
||||
dialogueListProp.InsertArrayElementAtIndex(i);
|
||||
}
|
||||
|
||||
// Delete
|
||||
GUI.color = Color.red;
|
||||
|
||||
if (GUILayout.Button("X", GUILayout.Width(25)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog(
|
||||
"Delete Element",
|
||||
"Are you sure you want to delete this element?",
|
||||
"Delete",
|
||||
"Cancel"))
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
if (positionTagProp != null) h += EditorGUI.GetPropertyHeight(positionTagProp, true) + space;
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp != null)
|
||||
{
|
||||
dialogueListProp.DeleteArrayElementAtIndex(i);
|
||||
break;
|
||||
var rl = GetTextList(textListProp);
|
||||
if (rl != null) h += rl.GetHeight() + space;
|
||||
}
|
||||
}
|
||||
|
||||
GUI.color = Color.white;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (!elemProp.isExpanded)
|
||||
continue;
|
||||
|
||||
return h;
|
||||
};
|
||||
dialogueListRl.drawElementCallback = (rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var elemProp = dialogueListProp.GetArrayElementAtIndex(index);
|
||||
if (elemProp == null) return;
|
||||
float line = EditorGUIUtility.singleLineHeight;
|
||||
float space = EditorGUIUtility.standardVerticalSpacing;
|
||||
Rect r = rect;
|
||||
r.height = line;
|
||||
elemProp.isExpanded = EditorGUI.Foldout(r, elemProp.isExpanded, $"段落 {index + 1}", true);
|
||||
if (!elemProp.isExpanded) return;
|
||||
r.y += line + space;
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
var positionTagProp = elemProp.FindPropertyRelative("positionTag");
|
||||
if (positionTagProp != null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(positionTagProp);
|
||||
EditorGUI.PropertyField(r, positionTagProp, labelPositionTag);
|
||||
r.y += line + space;
|
||||
}
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
if (textListProp != null)
|
||||
{
|
||||
var rl = GetTextList(textListProp);
|
||||
if (rl != null)
|
||||
{
|
||||
r.height = rl.GetHeight();
|
||||
rl.DoList(r);
|
||||
}
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
};
|
||||
}
|
||||
|
||||
private ReorderableList GetTextList(SerializedProperty textListProp)
|
||||
{
|
||||
if (textListProp == null) return null;
|
||||
string key = textListProp.propertyPath;
|
||||
if (!textListRlMap.TryGetValue(key, out var rl) || rl.serializedProperty != textListProp)
|
||||
{
|
||||
rl = new ReorderableList(serializedObject, textListProp, true, true, true, true);
|
||||
rl.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "文本列表");
|
||||
rl.elementHeightCallback = index =>
|
||||
{
|
||||
var textProp = textListProp.GetArrayElementAtIndex(index);
|
||||
return GetTextElementHeight(textProp);
|
||||
};
|
||||
rl.drawElementCallback = (rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var textProp = textListProp.GetArrayElementAtIndex(index);
|
||||
DrawTextElement(rect, textProp);
|
||||
};
|
||||
textListRlMap[key] = rl;
|
||||
}
|
||||
return rl;
|
||||
}
|
||||
|
||||
private float GetTextElementHeight(SerializedProperty textProp)
|
||||
{
|
||||
if (textProp == null) return EditorGUIUtility.singleLineHeight;
|
||||
float space = EditorGUIUtility.standardVerticalSpacing;
|
||||
float h = 0f;
|
||||
float padding = 4f;
|
||||
SerializedProperty prop;
|
||||
prop = textProp.FindPropertyRelative("content"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("textNumber"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("senderIndex"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("imagePos"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("flipX"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("appearTime"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("duration"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("stepMethod"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("timeAction"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("slowMotionScale"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
prop = textProp.FindPropertyRelative("endAction"); if (prop != null) h += EditorGUI.GetPropertyHeight(prop, true) + space;
|
||||
return h + padding * 2f;
|
||||
}
|
||||
|
||||
private void DrawTextElement(Rect rect, SerializedProperty textProp)
|
||||
{
|
||||
if (textProp == null) return;
|
||||
float line = EditorGUIUtility.singleLineHeight;
|
||||
float space = EditorGUIUtility.standardVerticalSpacing;
|
||||
float padding = 4f;
|
||||
Rect r = rect;
|
||||
r.y += padding;
|
||||
|
||||
var contentProp = textProp.FindPropertyRelative("content");
|
||||
var textNumberProp = textProp.FindPropertyRelative("textNumber");
|
||||
var senderIndexProp = textProp.FindPropertyRelative("senderIndex");
|
||||
var imagePosProp = textProp.FindPropertyRelative("imagePos");
|
||||
var flipXProp = textProp.FindPropertyRelative("flipX");
|
||||
var appearTimeProp = textProp.FindPropertyRelative("appearTime");
|
||||
var durationProp = textProp.FindPropertyRelative("duration");
|
||||
var stepMethodProp = textProp.FindPropertyRelative("stepMethod");
|
||||
var timeActionProp = textProp.FindPropertyRelative("timeAction");
|
||||
var slowMotionProp = textProp.FindPropertyRelative("slowMotionScale");
|
||||
var endActionProp = textProp.FindPropertyRelative("endAction");
|
||||
|
||||
if (contentProp != null)
|
||||
{
|
||||
r.height = EditorGUI.GetPropertyHeight(contentProp, true);
|
||||
EditorGUI.PropertyField(r, contentProp, labelContent, true);
|
||||
r.y += r.height + space;
|
||||
}
|
||||
|
||||
r.height = line;
|
||||
if (textNumberProp != null) EditorGUI.PropertyField(r, textNumberProp, labelTextNumber);
|
||||
r.y += line + space;
|
||||
|
||||
if (senderIndexProp != null)
|
||||
{
|
||||
if (speakerNames != null && speakerNames.Length > 0)
|
||||
{
|
||||
int current = Mathf.Clamp(senderIndexProp.intValue + 1, 0, speakerNames.Length - 1);
|
||||
int chosen = EditorGUI.Popup(r, "发言者", current, speakerNames);
|
||||
senderIndexProp.intValue = Mathf.Max(-1, chosen - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var customPosProp = elemProp.FindPropertyRelative("customPositions");
|
||||
if (customPosProp != null) EditorGUILayout.PropertyField(customPosProp, true);
|
||||
EditorGUI.PropertyField(r, senderIndexProp, labelSenderIndex);
|
||||
}
|
||||
|
||||
var textListProp = elemProp.FindPropertyRelative("textList");
|
||||
|
||||
if (textListProp != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Texts", EditorStyles.boldLabel);
|
||||
|
||||
for (int j = 0; j < textListProp.arraySize; j++)
|
||||
{
|
||||
var textProp = textListProp.GetArrayElementAtIndex(j);
|
||||
if (textProp == null)
|
||||
continue;
|
||||
|
||||
textProp.isExpanded =
|
||||
EditorGUILayout.Foldout(textProp.isExpanded, $"Text {j}");
|
||||
|
||||
if (!textProp.isExpanded)
|
||||
continue;
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
var contentProp = textProp.FindPropertyRelative("content");
|
||||
var textNumberProp = textProp.FindPropertyRelative("textNumber");
|
||||
var senderIndexProp = textProp.FindPropertyRelative("senderIndex");
|
||||
var imagePosProp = textProp.FindPropertyRelative("imagePos");
|
||||
var appearTimeProp = textProp.FindPropertyRelative("appearTime");
|
||||
var durationProp = textProp.FindPropertyRelative("duration");
|
||||
var stepMethodProp = textProp.FindPropertyRelative("stepMethod");
|
||||
var timeActionProp = textProp.FindPropertyRelative("timeAction");
|
||||
var slowMotionProp = textProp.FindPropertyRelative("slowMotionScale");
|
||||
var endActionProp = textProp.FindPropertyRelative("endAction");
|
||||
|
||||
EditorGUILayout.PropertyField(contentProp);
|
||||
EditorGUILayout.PropertyField(textNumberProp);
|
||||
|
||||
if (speakerNames != null)
|
||||
{
|
||||
int current =
|
||||
Mathf.Clamp(senderIndexProp.intValue + 1, 0, speakerNames.Length - 1);
|
||||
|
||||
int chosen =
|
||||
EditorGUILayout.Popup("Sender", current, speakerNames);
|
||||
|
||||
senderIndexProp.intValue =
|
||||
Mathf.Max(-1, chosen - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(senderIndexProp);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(imagePosProp);
|
||||
EditorGUILayout.PropertyField(appearTimeProp);
|
||||
EditorGUILayout.PropertyField(durationProp);
|
||||
EditorGUILayout.PropertyField(stepMethodProp);
|
||||
EditorGUILayout.PropertyField(timeActionProp);
|
||||
EditorGUILayout.PropertyField(slowMotionProp);
|
||||
EditorGUILayout.PropertyField(endActionProp);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
r.y += line + space;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
if (imagePosProp != null) EditorGUI.PropertyField(r, imagePosProp, labelImagePos);
|
||||
r.y += line + space;
|
||||
|
||||
if (GUILayout.Button("Add Dialogue Element"))
|
||||
if (flipXProp != null) EditorGUI.PropertyField(r, flipXProp, labelFlipX);
|
||||
r.y += line + space;
|
||||
|
||||
if (appearTimeProp != null) EditorGUI.PropertyField(r, appearTimeProp, labelAppearTime);
|
||||
r.y += line + space;
|
||||
|
||||
if (durationProp != null) EditorGUI.PropertyField(r, durationProp, labelDuration);
|
||||
r.y += line + space;
|
||||
|
||||
if (stepMethodProp != null) EditorGUI.PropertyField(r, stepMethodProp, labelStepMethod);
|
||||
r.y += line + space;
|
||||
|
||||
if (timeActionProp != null) EditorGUI.PropertyField(r, timeActionProp, labelTimeAction);
|
||||
r.y += line + space;
|
||||
|
||||
if (slowMotionProp != null) EditorGUI.PropertyField(r, slowMotionProp, labelSlowMotionScale);
|
||||
r.y += line + space;
|
||||
|
||||
if (endActionProp != null) EditorGUI.PropertyField(r, endActionProp, labelEndAction);
|
||||
}
|
||||
|
||||
private void BuildSpeakerNames()
|
||||
{
|
||||
speakerNames = null;
|
||||
Object speakersObj = speakersDataSOProp != null ? speakersDataSOProp.objectReferenceValue : null;
|
||||
if (speakersObj == null) return;
|
||||
var speakersSO = new SerializedObject(speakersObj);
|
||||
var speakersList = speakersSO.FindProperty("speakers");
|
||||
if (speakersList == null || !speakersList.isArray) return;
|
||||
int c = speakersList.arraySize;
|
||||
speakerNames = new string[c + 1];
|
||||
speakerNames[0] = "(无)";
|
||||
for (int i = 0; i < c; i++)
|
||||
{
|
||||
dialogueListProp.InsertArrayElementAtIndex(dialogueListProp.arraySize);
|
||||
var e = speakersList.GetArrayElementAtIndex(i);
|
||||
var nameProp = e.FindPropertyRelative("spkrName");
|
||||
speakerNames[i + 1] = nameProp != null ? nameProp.stringValue : $"Speaker {i}";
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void EnsureProperties()
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class galPrefab : MonoBehaviour
|
||||
{
|
||||
[Header("NowUsing")]
|
||||
[SerializeField] private int nowUsing = 0; // 0: none, 1: RoleHost, 2: RoleHint, 3: Narration, 4: HintOrLyrics
|
||||
[Header("publics")]
|
||||
public Color defaultTextColor;
|
||||
|
||||
[Header("mode1: RoleHost")]
|
||||
public Image roleHostBGbar;
|
||||
public Image L_roleHostImage;
|
||||
public Image R_roleHosetImage;
|
||||
public TextMeshProUGUI roleHostName;
|
||||
public TextMeshProUGUI roleHostMessage;
|
||||
public Button host_nextButton;
|
||||
|
||||
[Header("mode2: RoleHint")]
|
||||
public Image roleHintBGbar;
|
||||
public Image roleHintImage;
|
||||
public TextMeshProUGUI roleHintName;
|
||||
public TextMeshProUGUI roleHintMessage;
|
||||
public Button hint_nextButton;
|
||||
|
||||
[Header("mode3: Narration")]
|
||||
public Image narrationBGbar;
|
||||
public TextMeshProUGUI narrationMessage;
|
||||
|
||||
[Header("mode4: HintOrLyrics")]
|
||||
public Image hintOrLyricsBGbar;
|
||||
public TextMeshProUGUI hintOrLyricsMessage;
|
||||
|
||||
[Header("fathers of 4modes")]
|
||||
public GameObject roleHostFather;
|
||||
public GameObject roleHintFather;
|
||||
public GameObject narrationFather;
|
||||
public GameObject hintOrLyricsFather;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Try to find cameras from Camera.allCameras first
|
||||
Camera foundCamera = null;
|
||||
Camera[] cameras = Camera.allCameras;
|
||||
|
||||
if (cameras != null && cameras.Length > 0)
|
||||
{
|
||||
foundCamera = cameras[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Camera[] camObjs = FindObjectsOfType<Camera>();
|
||||
if (camObjs != null && camObjs.Length > 0)
|
||||
{
|
||||
foundCamera = camObjs[0];
|
||||
}
|
||||
camObjs = null; // release temporary reference
|
||||
}
|
||||
|
||||
if (foundCamera == null)
|
||||
foundCamera = Camera.main;
|
||||
|
||||
if (foundCamera != null)
|
||||
{
|
||||
Canvas parentCanvas = GetComponentInParent<Canvas>();
|
||||
if (parentCanvas != null)
|
||||
{
|
||||
parentCanvas.worldCamera = foundCamera;
|
||||
}
|
||||
}
|
||||
|
||||
// release temporary reference
|
||||
cameras = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c868a66b282da94faaf38c62d26fcbe
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Spine.Unity.Editor;
|
||||
|
||||
[System.Serializable]
|
||||
public class Speaker
|
||||
@@ -12,7 +13,8 @@ public class Speaker
|
||||
[TextArea(3, 10)]
|
||||
public string spkrDescription;
|
||||
|
||||
public Sprite spkrSprite;
|
||||
public Sprite spkrHD_Sprite;
|
||||
public Sprite spkrProfile_Sprite;
|
||||
}
|
||||
|
||||
public enum speakerType{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00f0e57cae6a4694e99e3bc9d5d021af
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -20,6 +20,8 @@ public class ingame_galgame_so : ScriptableObject
|
||||
public enum ImagePosition { Left, Right }
|
||||
[Tooltip("对象图片左右位置")]
|
||||
public ImagePosition imagePos; // 对象图片左右位置
|
||||
[Tooltip("对象图片是否水平翻转")]
|
||||
public bool flipX;
|
||||
|
||||
[Tooltip("文本出现时间")]
|
||||
public float appearTime; // 文本出现时间
|
||||
@@ -46,7 +48,7 @@ public class ingame_galgame_so : ScriptableObject
|
||||
[System.Serializable]
|
||||
public class DialogueElement
|
||||
{
|
||||
public enum PositionTag { Default, Left, Right, Upper, Down, Center }
|
||||
public enum PositionTag { RoleHost, RoleHint, Narration, HintOrLyrics }
|
||||
|
||||
[Header("位置配置")]
|
||||
public PositionTag positionTag;
|
||||
|
||||
@@ -13,17 +13,18 @@ MonoBehaviour:
|
||||
m_Name: opGalSO
|
||||
m_EditorClassIdentifier:
|
||||
dialogueType: 0
|
||||
triggerMethod: 0
|
||||
triggerMethod: 1
|
||||
timelineStandard: 0
|
||||
speakersDataSO: {fileID: 11400000, guid: 8e500b367b7861f44897e5396b1989ce, type: 2}
|
||||
dialogueList:
|
||||
- positionTag: 0
|
||||
customPositions: []
|
||||
textList:
|
||||
- content: "\u7535\u68CD\u7B11\u4F20\u4E4B\u8E29\u8E29\u80CC"
|
||||
- content: 1
|
||||
textNumber: 1
|
||||
senderIndex: 0
|
||||
imagePos: 0
|
||||
flipX: 0
|
||||
appearTime: 0
|
||||
duration: 0
|
||||
stepMethod: 1
|
||||
@@ -33,10 +34,11 @@ MonoBehaviour:
|
||||
- positionTag: 0
|
||||
customPositions: []
|
||||
textList:
|
||||
- content: "\u7535\u68CD\u7B11\u4F20\u4E4B\u8E29\u8E29\u80CC"
|
||||
- content: 2
|
||||
textNumber: 1
|
||||
senderIndex: 0
|
||||
imagePos: 0
|
||||
flipX: 0
|
||||
appearTime: 0
|
||||
duration: 0
|
||||
stepMethod: 0
|
||||
@@ -46,13 +48,28 @@ MonoBehaviour:
|
||||
- positionTag: 0
|
||||
customPositions: []
|
||||
textList:
|
||||
- content: "\u7535\u68CD\u7B11\u4F20\u4E4B\u8E29\u8E29\u80CC"
|
||||
- content: 3
|
||||
textNumber: 1
|
||||
senderIndex: 0
|
||||
imagePos: 0
|
||||
flipX: 0
|
||||
appearTime: 0
|
||||
duration: 0
|
||||
stepMethod: 1
|
||||
timeAction: 0
|
||||
slowMotionScale: 0
|
||||
endAction: 0
|
||||
- positionTag: 0
|
||||
customPositions: []
|
||||
textList:
|
||||
- content: 4
|
||||
textNumber: 1
|
||||
senderIndex: -1
|
||||
imagePos: 0
|
||||
flipX: 0
|
||||
appearTime: 0
|
||||
duration: 0
|
||||
stepMethod: 0
|
||||
timeAction: 0
|
||||
slowMotionScale: 0
|
||||
endAction: 0
|
||||
|
||||
Reference in New Issue
Block a user