using System.Collections; using System.Collections.Generic; using System.Text; using UnityEngine; public class StoryScript : MonoBehaviour { public const string InstallPath = "install"; /// <summary> /// 位置父节点的路径 /// </summary> public const string PosPath = "install/[Transform]"; /// <summary> /// 路点父节点的路径 /// </summary> public const string PathPointPath = "install/[PathPoint]"; /// <summary> /// TimelineNames父节点的路径 /// </summary> public const string TimelinePath = "install/[TimelineNames]"; /// <summary> /// TimelineNames父节点的路径 /// </summary> public const string FormPath = "install/[FormNames]"; /// <summary> /// 触发器盒子父节点的路径 /// </summary> public const string TriggerBoxPath = "install/[TriggerBox]"; /// <summary> /// 3D文字 /// </summary> public const string Text3DPath = "install/[Text3D]"; /// <summary> /// 触发器父节点的路径 /// </summary> public const string TriggersPath = "triggers"; /// <summary> /// 故事名 /// </summary> //public string storyName; /// <summary> /// 故事id /// </summary> public int id; /// <summary> /// 描述 /// </summary> public string describe; /// <summary> /// 需要预加载的Timeline /// </summary> public List<string> preLoadTimelineNames = new List<string>(); /// <summary> /// 需要预加载的UI界面 /// </summary> public List<string> preLoadFormNames = new List<string>(); /// <summary> /// 位置 /// </summary> public Dictionary<string, Transform> transforms = new Dictionary<string, Transform>(); /// <summary> /// 路点 /// </summary> public Dictionary<string, List<Transform>> pathPoint = new Dictionary<string, List<Transform>>(); /// <summary> /// 触发器盒子 /// </summary> public Dictionary<string, Transform> triggerBoxDic = new Dictionary<string, Transform>(); /// <summary> /// 3D文字 /// </summary> public Dictionary<string, GameObject> Text3DDic = new Dictionary<string, GameObject>(); /// <summary> /// 触发器 /// </summary> public List<StoryTrigger> storyTriggers = new List<StoryTrigger>(); private void CheckNode(string path) { //判断是否在Inspacter面板 if (transform.gameObject.activeInHierarchy) { var parentTf = transform.Find(path); if (parentTf == null) { var strArr = path.Split('/'); var gobj = new GameObject(strArr[1]); parentTf = gobj.transform; parentTf.SetParent(transform.Find(strArr[0])); #if UNITY_EDITOR if (UnityEditor.PrefabUtility.GetPrefabObject(gameObject) != null) { UnityEditor.PrefabUtility.ReplacePrefab(gameObject, UnityEditor.PrefabUtility.GetPrefabParent(gameObject), UnityEditor.ReplacePrefabOptions.ConnectToPrefab); } #endif } } } //获取节点下所有子节点的名字 public void GetNames(List<string> list, Transform parentTf) { list.Clear(); //var parentTf = transform.Find(path); int count = parentTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var child = parentTf.GetChild(i); var name = child.gameObject.name; list.Add(name); } } list.Sort((a, b) => { return a.CompareTo(b); }); } //将List中的所有string 转成Lua格式 public string GetLuaFormatByStringList(string title, List<string> stringList) { var count = stringList.Count; StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format(" {0} = {{", title)); if (count > 0) { Dictionary<string, bool> allTimelineNameDic = new Dictionary<string, bool>(); for (int i = 0; i < count; i++) { if (!allTimelineNameDic.ContainsKey(stringList[i])) { allTimelineNameDic.Add(stringList[i], true); } else { Debug.LogError("出现了相同的名字!!! " + stringList[i]); } } foreach (var item in allTimelineNameDic) { sb.AppendLine(string.Format(" \"{0}\",", item.Key)); } } sb.AppendLine(" },"); return sb.ToString(); } //获取所有需要预加载的UIForm名字 public List<string> GetAllFormNames() { CheckNode(FormPath); var parentTf = transform.Find(FormPath); if (parentTf != null) GetNames(preLoadFormNames, transform.Find(FormPath)); return preLoadFormNames; } //获取所有需要预加载的Timeline名字 public List<string> GetAllTimelineNames() { CheckNode(TimelinePath); var parentTf = transform.Find(TimelinePath); if (parentTf != null) GetNames(preLoadTimelineNames, parentTf); return preLoadTimelineNames; } //获取所有需要预加载的UIForm名字 lua格式 public string GetLuaFormatByAllFormNames() { return GetLuaFormatByStringList("preLoadFormNames", GetAllFormNames()); } //获取所有需要预加载的Timeline名字 lua格式 public string GetLuaFormatByAllTimelineNames() { return GetLuaFormatByStringList("preLoadTimelineNames", GetAllTimelineNames()); } //获取所有位置 public Dictionary<string, Transform> GetAllPos() { CheckNode(PosPath); transforms.Clear(); var posTf = transform.Find(PosPath); int count = posTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var child = posTf.GetChild(i); var name = child.gameObject.name; Transform tf; if (!transforms.TryGetValue(name, out tf)) { transforms.Add(name, child); } else { Debug.LogError("故事:" + gameObject.name + ",位置中有相同名字:" + name); } } } return transforms; } //获取所有位置 lua格式 public string GetLuaFormatByAllPos() { // transform = { // npc10001 = { { 13,0,17},{ 0,90,0} }, // interactor10016 = { { 13,0,19},{ 1,1,0} }, // interactor10015 = { { 13,0,21},{ 1,1,1} }, // }, var allTranform = GetAllPos(); StringBuilder sb = new StringBuilder(); sb.AppendLine(" transform = {"); foreach (var item in allTranform) { var tf = item.Value; var pos = tf.position; var dir = tf.eulerAngles; sb.AppendLine(string.Format(" {0} = {{{{{1},{2},{3}}},{{{4},{5},{6}}}}},", item.Key, pos.x < 0.001f ? 0 : pos.x, pos.y < 0.001f ? 0 : pos.y, pos.z < 0.001f ? 0 : pos.z, dir.x < 0.001f ? 0 : dir.x, dir.y < 0.001f ? 0 : dir.y, dir.z < 0.001f ? 0 : dir.z)); } sb.AppendLine(" },"); return sb.ToString(); } //获取所有路点 public Dictionary<string, List<Vector3>> GetAllPathPoint() { CheckNode(PathPointPath); pathPoint.Clear(); var allPathPoint = new Dictionary<string, List<Vector3>>(); var pathPointTf = transform.Find(PathPointPath); int count = pathPointTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var childTf = pathPointTf.GetChild(i); var name = childTf.gameObject.name; List<Vector3> pathPoints; List<Transform> pathPointTfs; if (!allPathPoint.TryGetValue(name, out pathPoints)) { pathPoints = new List<Vector3>(); pathPointTfs = new List<Transform>(); int childCount = childTf.childCount; for (int j = 0; j < childCount; j++) { pathPoints.Add(childTf.GetChild(j).position); pathPointTfs.Add(childTf.GetChild(j)); } allPathPoint.Add(name, pathPoints); pathPoint.Add(name, pathPointTfs); } else { Debug.LogError("故事:" + gameObject.name + ",路点中有相同名字:" + name); } } } return allPathPoint; } //获取所有路点 lua格式 public string GetLuaFormatByPathPoint() { // pathPoint = { // npc10001 = { { 1,0,1},{ 2,0,2} }, // npc10002 = { { 3,0,0},{ 4,0,4} }, // }, var allPathPoint = GetAllPathPoint(); StringBuilder sb = new StringBuilder(); sb.AppendLine(" pathPoint = {"); StringBuilder sbTemp = new StringBuilder(); foreach (var item in allPathPoint) { sbTemp.Remove(0, sbTemp.Length); var pathPoints = item.Value; for (int i = 0; i < pathPoints.Count; i++) { sbTemp.Append(string.Format(i == pathPoints.Count - 1 ? "{{{0},{1},{2}}}" : "{{{0},{1},{2}}},", pathPoints[i].x < 0.001f ? 0 : pathPoints[i].x, pathPoints[i].y < 0.001f ? 0 : pathPoints[i].y, pathPoints[i].z < 0.001f ? 0 : pathPoints[i].z)); } sb.AppendLine(string.Format(" {0} = {{{1}}},", item.Key, sbTemp.ToString())); } sb.AppendLine(" },"); return sb.ToString(); } /// <summary> /// 获取所有触发器盒子 /// </summary> /// <returns></returns> public Dictionary<string, Transform> GetAllTriggerBox() { CheckNode(TriggerBoxPath); var parentTf = transform.Find(TriggerBoxPath); if (parentTf == null) return triggerBoxDic; triggerBoxDic.Clear(); int count = parentTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var child = parentTf.GetChild(i); var name = child.gameObject.name; Transform tf; if (!triggerBoxDic.TryGetValue(name, out tf)) { triggerBoxDic.Add(name, child); } else { Debug.LogError("故事:" + gameObject.name + ",触发器盒子有相同名字:" + name); } } } return triggerBoxDic; } //获取所有触发盒子 lua格式 public string GetLuaFormatByTriggerBox() { // triggerBox = { // cub_001 = {"Box",{0, 0, 0}, {1, 1, 1}}, // sphere_001 = {"Sphere",{0, 0, 0}, 3}, // }, var allTriggerBox = GetAllTriggerBox(); StringBuilder sb = new StringBuilder(); sb.AppendLine(" triggerBox = {"); StringBuilder sbTemp = new StringBuilder(); foreach (var item in allTriggerBox) { sbTemp.Remove(0, sbTemp.Length); var tf = item.Value; var boxCollider = tf.gameObject.GetComponent<BoxCollider>(); if (boxCollider != null) { var centerPos = tf.position; var scale = tf.localScale * 0.5f; sbTemp.Append(string.Format("{{\"{0}\",\"Box\", {{{1:N4}, {2:N4}, {3:N4}}}, {{{4:N4}, {5:N4}, {6:N4}}}}},", item.Key, centerPos.x - scale.x, centerPos.y - scale.y, centerPos.z - scale.z, centerPos.x + scale.x, centerPos.y + scale.y, centerPos.z + scale.z)); } else { var sphereCollider = tf.gameObject.GetComponent<SphereCollider>(); if (sphereCollider != null) { var centerPos = tf.position; var radius = tf.localScale.x * 0.5f; tf.localScale = new Vector3(radius * 2, radius * 2, radius * 2); sbTemp.Append(string.Format("{{\"{0}\",\"Sphere\", {{{1:N4}, {2:N4}, {3:N4}}}, {4:N4}}},", item.Key, centerPos.x, centerPos.y, centerPos.z, radius)); } } sb.AppendLine(string.Format(" {0} = {1}", item.Key, sbTemp.ToString())); } sb.AppendLine(" },"); return sb.ToString(); } /// <summary> /// 获取所有3D文字 /// </summary> /// <returns></returns> public Dictionary<string, GameObject> GetAllText3D() { CheckNode(Text3DPath); var parentTf = transform.Find(Text3DPath); if (parentTf == null) return Text3DDic; var uiRoot = parentTf.GetComponent<UIRoot>(); //检查UIRoot组件 if (!uiRoot) { uiRoot = parentTf.gameObject.AddComponent<UIRoot>(); uiRoot.scalingStyle = UIRoot.Scaling.ConstrainedOnMobiles; uiRoot.manualWidth = 1136; uiRoot.manualHeight = 640; uiRoot.fitWidth = true; uiRoot.fitHeight = true; } var uiPanel = parentTf.GetComponent<UIPanel>(); //检查UIPanel组件 if (!uiPanel) { uiPanel = parentTf.gameObject.AddComponent<UIPanel>(); } Text3DDic.Clear(); int count = parentTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var child = parentTf.GetChild(i).gameObject; var name = child.name; GameObject gobjOut; if (!Text3DDic.TryGetValue(name, out gobjOut)) { Text3DDic.Add(name, child); } else { Debug.LogError("故事:" + gameObject.name + ",3D文字有相同名字:" + name); } } } return Text3DDic; } //获取所有3D文字 lua格式 public string GetLuaFormatByText3D() { // triggerBox = { // Text001 = {"Text001",{0, 0, 0}, {0, 0, 0},{"内容",18, 200, 26}}, // }, // {"名字",{posX, posY , posZ}, {rotaX, rotaY, rotaZ}, {"内容", foneSize, sizeWidth, sizeHeight}}, var allText3D = GetAllText3D(); StringBuilder sb = new StringBuilder(); sb.AppendLine(" Text3D = {"); StringBuilder sbTemp = new StringBuilder(); foreach (var item in allText3D) { sbTemp.Remove(0, sbTemp.Length); var gobj = item.Value; var tf = gobj.transform; var pos = tf.position; var eulerAngles = tf.eulerAngles; var uiLabel = gobj.GetComponent<UILabel>(); sbTemp.Append(string.Format("{{\"{0}\", {{{1}, {2}, {3}}}, {{{4}, {5}, {6}}}, {{\"{7}\", {8}, {9}, {10}}}}},", item.Key, pos.x, pos.y, pos.z, eulerAngles.x, eulerAngles.y, eulerAngles.z, uiLabel.text, uiLabel.fontSize, uiLabel.width, uiLabel.height)); sb.AppendLine(string.Format(" {0} = {1}", item.Key, sbTemp.ToString())); } sb.AppendLine(" },"); return sb.ToString(); } //获取所有触发器 public List<StoryTrigger> GetAllTriggers() { storyTriggers.Clear(); var triggersTf = transform.Find(TriggersPath); var count = triggersTf.childCount; if (count > 0) { for (int i = 0; i < count; i++) { var script = triggersTf.GetChild(i).GetComponent<StoryTrigger>(); if (script != null) { storyTriggers.Add(script); } } } return storyTriggers; } //添加触发器 public StoryTrigger AddTrigger(string name, int index) { var triggersTf = transform.Find(TriggersPath); var go = new GameObject(name); go.transform.parent = triggersTf; if (index != -1) { go.transform.SetSiblingIndex(index); } var storyTrigger = go.AddComponent<StoryTrigger>(); return storyTrigger; } //移除触发器 public void RemoveTrigger(int index) { var triggersTf = transform.Find(TriggersPath); var go = triggersTf.GetChild(index).gameObject; DestroyImmediate(go); } //获取所有触发器 lua格式 public string GetLuaFormatByTrigger() { var allTrigger = GetAllTriggers(); StringBuilder sb = new StringBuilder(); sb.AppendLine(" triggers = {"); var count = storyTriggers.Count; for (int i = 0; i < count; i++) { var storyTrigger = storyTriggers[i]; var actions = storyTrigger.actions; //若没有动作或动作都是None,不会导出该触发器 if (actions.Count == 0) continue; var isNotEmpty = false; for (int j = 0; j < actions.Count; j++) { isNotEmpty = isNotEmpty || actions[j].actionType != ActionType.None; } if (!isNotEmpty) continue; //触发条件 var triggerCondition = storyTrigger.triggerCondition; var triggerConditionParames = storyTrigger.triggerConditionParames; var triggerConditionStr = GetTriggerConditionStr(triggerCondition, triggerConditionParames); //限制条件 var limitCondition = storyTrigger.limitCondition; var limitConditionStr = GetLimitConditionStr(limitCondition, 0); var actionsStr = GetActionStr(actions); //动作 sb.AppendLine(" {"); sb.AppendLine(" ID = " + storyTrigger.id + ","); sb.AppendLine(" isActive = true,"); sb.AppendLine(" triggerCondition = " + triggerConditionStr); sb.AppendLine(" limitCondition = " + limitConditionStr); sb.AppendLine(" action = " + actionsStr); sb.AppendLine(" },"); } sb.AppendLine(" }"); return sb.ToString(); } //获取触发条件string lua格式 public string GetTriggerConditionStr(TriggerConditionType triggerConditionType, List<string> parames) { string result = "{"; switch (triggerConditionType) { case TriggerConditionType.Init: result += "\"init\""; break; case TriggerConditionType.EnterMap: result += parames[0] == "" ? "\"enterMap\"" : "\"enterMap\"," + parames[0]; break; case TriggerConditionType.TalkOver: result += parames[0] == "" ? "\"talkOver\"" : "\"talkOver\"," + parames[0]; break; case TriggerConditionType.InteractionOver: result += parames[0] == "" ? "\"interactionOver\"" : "\"interactionOver\"," + parames[0]; break; case TriggerConditionType.TimeLineOver: result += parames[0] == "" ? "\"timeLineOver\"" : string.Format("\"timeLineOver\",\"{0}\"", parames[0]); break; case TriggerConditionType.Variable: result += parames[0] == "" ? "\"variable\"" : "\"variable\"," + parames[0] + ", " + parames[1] + ", " + parames[2]; break; case TriggerConditionType.EnterTriggerArea: result += parames[0] == "None" ? "\"enterTriggerArea\"" : string.Format("\"enterTriggerArea\",\"{0}\"", parames[0]); break; default: Debug.LogError("未添加该类型Key"); break; } result += "},"; return result; } //获取限制条件string lua格式 public string GetLimitConditionStr(LimitCondition limitConditionBase, int layer) { if (limitConditionBase.GetType() == typeof(LimitCondition)) { var limitCondition = limitConditionBase as LimitCondition; var limitConditionType = limitCondition.curLimitConditionType; var parames = limitCondition.curLimitCoiditionParames; var limitConditionChilds = limitCondition.limitConditionChilds; var count = limitConditionChilds.Count; string result = layer == 0 ? "" : GetPreStr(layer); switch (limitConditionType) { case LimitConditionType.None: result += string.Format("{{\"{0}\"}},", "none"); break; case LimitConditionType.EnterMap: result += string.Format("{{\"{0}\",{1}}},", "enterMap", parames[0]); break; case LimitConditionType.TalkOver: result += string.Format("{{\"{0}\",{1}}},", "talkOver", parames[0]); break; case LimitConditionType.InteractionOver: result += string.Format("{{\"{0}\",{1}}},", "interactionOver", parames[0]); break; case LimitConditionType.TimeLineOver: result += string.Format("{{\"{0}\",\"{1}\"}},", "timeLineOver", parames[0]); break; case LimitConditionType.Variable: result += string.Format("{{\"{0}\",\"{1}\",\"{2}\",{3}}},", "variable", parames[0], parames[1], parames[2]); break; case LimitConditionType.EnterTriggerArea: result += string.Format("{{\"{0}\",\"{1}\"}},", "enterTriggerArea", parames[0]); break; case LimitConditionType.And: result += string.Format("{{\"{0}\",\n", "and"); for (int i = 0; i < count; i++) { result += GetLimitConditionStr(limitConditionChilds[i], layer + 1) + "\n"; } result += GetPreStr(layer) + "},"; break; case LimitConditionType.Or: result += string.Format("{{\"{0}\",\n", "or"); for (int i = 0; i < count; i++) { result += GetLimitConditionStr(limitConditionChilds[i], layer + 1) + "\n"; } result += GetPreStr(layer) + "},"; break; default: Debug.LogError("未添加该类型Key"); break; } return result; } return "{},"; } //Log,//日志 1 //SetTriggerActive,//设置触发器开关 2 //CreatNpc,//创建NPC 2 //CreatInteractor,//创建交互物 2 //SetVariable,//设置变量 2 //RemoveEntity,//移除物体 1 //SetNPCAI,//设置NPC的AI 2 //PlayTimeline,//播放Timeline 1 //LoadTimeline,//加载Timeline 1 //StartInteract,//开始交互 1 //SetPlayerTransform,//设置玩家位置和旋转 1 //SetPlayerScale,//设置玩家缩放 1 //OpenFromStoryEnd,//打开故事结束界面 1 //ChangeInteractState,//设置交互物是否可交互 2 //ShowTextTips,//显示文字提示 1 //ShowCalendar,//显示日历 2 public string GetActionStr(List<TriggerAction> triggerActions) { StringBuilder sb = new StringBuilder(); sb.AppendLine("{"); var count = triggerActions.Count; if (count > 0) { for (int i = 0; i < count; i++) { var actionType = triggerActions[i].actionType; var parames = triggerActions[i].actionParames; string result = ""; switch (actionType) { case ActionType.Log: result += string.Format("{{\"{0}\", \"{1}\"}}", "log", parames[0]); break; case ActionType.SetTriggerActive: result += string.Format("{{\"{0}\", {1}, {2}}}", "setTriggerActive", parames[0], parames[1]); break; case ActionType.CreatNpc: result += string.Format("{{\"{0}\", {1}, \"{2}\"}}", "creatNpc", parames[0], parames[1]); break; case ActionType.CreatInteractor: result += string.Format("{{\"{0}\", {1}, \"{2}\"}}", "creatInteractor", parames[0], parames[1]); break; case ActionType.SetVariable: result += string.Format("{{\"{0}\", \"{1}\", {2}}}", "setVariable", parames[0], parames[1]); break; case ActionType.RemoveEntity: result += string.Format("{{\"{0}\", {1}}}", "removeEntity", parames[0]); break; case ActionType.SetNPCAI: result += string.Format("{{\"{0}\", {1}, {2}}}", "setNPCAI", parames[0], parames[1]); break; case ActionType.PlayTimeline: result += string.Format("{{\"{0}\", \"{1}\"}}", "playTimeline", parames[0]); break; case ActionType.LoadTimeline: result += string.Format("{{\"{0}\", \"{1}\"}}", "loadTimeline", parames[0]); break; case ActionType.StartInteract: result += string.Format("{{\"{0}\", {1}}}", "startInteract", parames[0]); break; case ActionType.SetPlayerTransform: result += string.Format("{{\"{0}\", \"{1}\"}}", "setPlayerTransform", parames[0]); break; case ActionType.SetPlayerScale: result += string.Format("{{\"{0}\", {1}}}", "setPlayerScale", parames[0]); break; case ActionType.OpenFromStoryEnd: result += string.Format("{{\"{0}\", \"{1}\"}}", "openFromStoryEnd", parames[0]); break; case ActionType.ChangeInteractState: result += string.Format("{{\"{0}\", {1}, {2}}}", "changeInteractState", parames[0], parames[1]); break; case ActionType.ShowTextTips: result += string.Format("{{\"{0}\", \"{1}\"}}", "showTextTips", parames[0]); break; case ActionType.ShowCalendar: result += string.Format("{{\"{0}\", {1}, {2}}}", "showCalendar", parames[0], parames[1]); break; case ActionType.AddTriggerBox: result += string.Format("{{\"{0}\", \"{1}\"}}", "addTriggerBox", parames[0]); break; case ActionType.RemoveTriggerBox: result += string.Format("{{\"{0}\", \"{1}\"}}", "removeTriggerBox", parames[0]); break; case ActionType.ShowText3D: result += string.Format("{{\"{0}\", \"{1}\"}}", "showText3D", parames[0]); break; case ActionType.HideText3D: result += string.Format("{{\"{0}\", \"{1}\"}}", "hideText3D", parames[0]); break; case ActionType.ShowProgress: result += string.Format("{{\"{0}\", \"{1}\"}}", "showProgress", parames[0]); break; default: break; } sb.AppendLine(string.Format(GetPreStr(1) + "{0},", result)); } } sb.Append(GetPreStr(0) + "},"); return sb.ToString(); } public string GetPreStr(int layer) { string temp = ""; for (int i = -3; i < layer; i++) { temp += " "; } return temp; } }