//================================================================= /// <summary> /// 가운데가 아닌 텍스트의 위치를 여백에 따라 보정 /// </summary> /// <param name="textpos"></param> /// <param name="flow"></param> private static void ApplySideTextMargin(ref Vector3 textpos, IInGameSetting setting, FSNInGameSetting.FlowDirection flow) { //float xoffset = setting.TextMarginLeft - setting.TextMarginRight; float yoffset = setting.TextMarginBottom - setting.TextMarginTop; // 해당 사이드에서 여백만큼 떨어트리기 switch (flow) { case FSNInGameSetting.FlowDirection.Up: textpos.y += setting.TextMarginBottom; textpos.x += setting.TextMarginLeft; break; case FSNInGameSetting.FlowDirection.Down: textpos.y -= setting.TextMarginTop; textpos.x += setting.TextMarginLeft; break; case FSNInGameSetting.FlowDirection.Left: textpos.x -= setting.TextMarginRight; textpos.y += yoffset; break; case FSNInGameSetting.FlowDirection.Right: textpos.x += setting.TextMarginLeft; textpos.y += yoffset; break; } }
/// <summary> /// 연결된 모든 Chain과 최종 Parent까지 모두 복제한 사본을 리턴한다 /// </summary> /// <returns></returns> public Chain CloneEntireChain() { // 1. 최종 parent를 찾는다 + Chain을 거꾸로 뒤집어 보관해둔다 FSNInGameSetting root; Chain search = this; Stack <Chain> revChain = new Stack <Chain>(); // Chain을 거꾸로 쌓은 것 revChain.Push(search); // 맨 첫번째 Chain 우선 쌓아두기 while (search.m_parentChainVer != null) // (Parent가 더이상 Chain이 아니게 될 때까지 루프) { search = search.m_parentChainVer; // 다음 Chain으로 점프 revChain.Push(search); // 그 다음 Chain 쌓기 } root = search.m_parent as FSNInGameSetting; // Chain이 아닌 최종 root를 찾음 // 2. root 위의 chain 부터 하나씩 클로닝한다 IInGameSetting parent = root.Clone(); // root 부터 클론해서 사용 Chain curClone; do { // 거꾸로 Chain을 쌓은 stack을 모두 소비할 때까지 반복 (= 원래 Chain의 최상층까지 루프) Chain origChain = revChain.Pop(); curClone = CloneChain(origChain, parent); parent = curClone; // 현재 복제한 것이 다음번 parent } while(revChain.Count > 0); return(curClone); // 최상층 복제를 리턴 }
public override Vector2 CalculateTextSize(string text, IInGameSetting setting) { // GUI 루프 바깥에서는 GUI 콜을 할 수가 없음. 따라서 임의로 값을 계산한다. (테스트용이니까 어차피 괜찮음...) float size = setting.FontSize * 1.5f; // 약간 배수를 준다 int lineCount = 0; int maxColCount = 0; foreach (string line in text.Split('\n')) { lineCount++; int charCount = line.Length; int curColCount = 0; for (int i = 0; i < charCount; i++) { curColCount += (text[i] > 255)? 2 : 1; } maxColCount = Mathf.Max(maxColCount, curColCount); } Vector2 finalSize; finalSize.y = lineCount * size; finalSize.x = (float)maxColCount * size * 0.5f; return(finalSize); }
public FSNLayerObject(FSNModule parent, GameObject realObject, IInGameSetting setting) { m_object = realObject; m_trans = m_object.transform; m_coComp = FSNCoroutineComponent.GetFromGameObject(m_object); m_module = parent; }
public Chain(IInGameSetting parent) { m_parent = parent; m_parentChainVer = parent as Chain; m_currentRaw = new FSNInGameSetting(false); m_overridProperties = new HashSet <string>(); }
/// <summary> /// 가운데에 배치되는 텍스트의 위치를 여백에 따라 보정 /// </summary> /// <param name="textpos"></param> /// <param name="setting"></param> private static void ApplyCenterTextMargin(ref Vector3 textpos, IInGameSetting setting) { float xoffset = setting.TextMarginLeft - setting.TextMarginRight; float yoffset = setting.TextMarginBottom - setting.TextMarginTop; textpos.x += xoffset; textpos.y += yoffset; }
/// <summary> /// 새 Parent를 지정하여 체인 1개 복제 /// </summary> /// <param name="original"></param> /// <param name="newParent"></param> /// <returns></returns> static Chain CloneChain(Chain original, IInGameSetting newParent) { Chain cloned = new Chain(newParent); // 지정한 parent로 클로닝 cloned.m_currentRaw = original.m_currentRaw.Clone(); // 설정값 구조체 복제 cloned.m_overridProperties.UnionWith(original.m_overridProperties); // 오바라이드 목록도 복제 return(cloned); }
/// <summary> /// 레이어 오브젝트를 추가하고, 해당 스테이트로 초기화한다 /// </summary> /// <param name="element"></param> /// <param name="backward"></param> ObjT AddNewLayerObject(ElmT element, IInGameSetting nextSetting) { ObjT newObj = MakeNewLayerObject(element, nextSetting); newObj.ConenctKillEvent(OnObjectKilled, element.UniqueID); newObj.SetStateFully(element); m_objectDict[element.UniqueID] = newObj; return(newObj); }
/// <summary> /// 오브젝트가 존재하는 모든 모듈에 콜 보내기 /// </summary> /// <param name="segment"></param> /// <param name="setting"></param> public void AddAllModuleCall(FSNScriptSequence.Segment segment, IInGameSetting setting) { foreach (var callList in m_moduleCallTable.Values) { callList.Add(new FSNProcessModuleCallParam() { segment = segment, setting = setting }); } }
public override Vector2 CalculateTextSize(string text, IInGameSetting setting) { m_textGenSettings.fontSize = (int)setting.FontSize; m_textGenSettings.lineSpacing = setting.TextLineSpacing; float maxWidth = FSNEngine.Instance.ScreenXSize - setting.TextMarginLeft - setting.TextMarginRight; m_textGenSettings.generationExtents = new Vector2(maxWidth, 1f); Vector2 size; size.x = m_textGenerator.GetPreferredWidth(text, m_textGenSettings); size.y = m_textGenerator.GetPreferredHeight(text, m_textGenSettings); return(size); }
public BaseObjectLayerObject(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { // 내부 게임 오브젝트 생성 if (useInnerObject) { var inner = new GameObject(); inner.name = "(Inner)"; var tr = inner.transform; tr.parent = transform; tr.localPosition = Vector3.zero; tr.localRotation = Quaternion.identity; tr.localScale = Vector3.one; innerGO = inner; } }
public Text_NewUI(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { m_text = gameObj.AddComponent <Text>(); m_rectTrans = m_text.rectTransform; m_rectTrans.pivot = Vector2.zero; // 여백까지 고려한 텍스트 최대 width 설정 float textWidth = FSNEngine.Instance.ScreenXSize - setting.TextMarginLeft - setting.TextMarginRight; m_rectTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, textWidth); m_rectTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 1f); m_text.horizontalOverflow = HorizontalWrapMode.Wrap; // word-wrap m_text.verticalOverflow = VerticalWrapMode.Overflow; // 줄 갯수는 제한 없도록 m_text.lineSpacing = setting.TextLineSpacing; switch (setting.TextAlign) { case FSNInGameSetting.TextAlignType.Left: m_text.alignment = TextAnchor.UpperLeft; break; case FSNInGameSetting.TextAlignType.Middle: m_text.alignment = TextAnchor.UpperCenter; break; case FSNInGameSetting.TextAlignType.Right: m_text.alignment = TextAnchor.UpperRight; break; } var module = parent as FSNTextModule_NewUI; m_text.font = module.font; // TEST : 그림자 효과를 추가해본다.... var shadow = gameObj.AddComponent <Shadow>(); float shadowDist = Mathf.Max(1f, setting.FontSize * 0.08f); shadow.effectColor = new Color(0, 0, 0, 0.7f); shadow.effectDistance = new Vector2(shadowDist, -shadowDist); }
public Image_NewUI(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { m_image = innerGO.AddComponent <RawImage>(); // 안쪽의 오브젝트에 추가하기 //m_canvasRenderer = m_image.canvasRenderer; //m_renderer = m_image.GetComponent<Renderer>(); //m_image = gameObject.AddComponent<RawImage>(); // 안쪽의 오브젝트에 추가하기 m_rectTrans = m_image.rectTransform; m_rectTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0); m_rectTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0); m_rectTrans.pivot = Vector2.one / 2f; m_parentImageModule = parent as FSNImageModule_NewUI; var mat = m_parentImageModule.imageMaterial; if (mat != null) // 사용자 지정 마테리얼 설정 { //m_image.material= new Material(mat); m_image.material = mat; m_image.material.renderQueue = 2450; // 강제 렌더큐 설정 (Depth Write를 작동시키기 위해) } m_childCanvas = gameObj.AddComponent <Canvas>(); gameObj.AddComponent <CanvasRenderer>(); // FIX : Canvas 가 움직이지 않던 문제 해결. 버그인가봄.... m_childCanvas.overrideSorting = true; m_canvasTrans = gameObj.GetComponent <RectTransform>(); //var dummyrenderer = gameObj.AddComponent<RawImage>(); // (편법) child까지 렌더링 오더 소팅을 하기 위해 더미 렌더러를 생성한다. //dummyrenderer.enabled = false; // 렌더링할 필요가 없으므로 끄기 //m_canvasTrans = dummyrenderer.GetComponent<RectTransform>(); // 일반 transform을 이제 사용할 수 없다 //Debug.Log("relativeDepth : " + m_image.GetComponent<CanvasRenderer>().relativeDepth); //m_canvasTrans = m_rectTrans; //FSNCoroutineComponent.GetFromGameObject(gameObj).StartCoroutine(UpdateCo()); // 업데이트 루프 등록 }
private void AddLastOptionText(FSNSnapshot.Layer layer, Segments.Text textSeg, IInGameSetting setting) { // TODO : 상하좌우 여백, 정렬 등도 따져야함 // NOTE : 선택한 방향은 setting 쪽에 설정되어 오는 것으로... SnapshotElems.Text optionText = null; foreach (var elem in layer.Elements) // * 이전 레이어를 전부 뒤져서 진행 방향이 같은 선택지 텍스트를 찾아온다 { var textElem = elem as SnapshotElems.Text; if (textElem.type == SnapshotElems.Text.Type.OptionTexts && textElem.optionDir == setting.CurrentFlowDirection) { optionText = textElem; break; } } if (optionText != null) // * 찾은 경우에 한해서... { // 텍스트를 새로 만드는 것이 아니라 기존 것을 변경한다. // PushTextsToDirection 에서는 이 시점의 LastOption텍스트는 건들지 않는다. var textSize = CalculateTextSize(optionText.text, setting); var posToCenter = optionText.Position; TextPositionToCenter(ref posToCenter, textSize, optionText.optionDir, setting); // 중앙 위치 맞추기 optionText.Position = posToCenter; optionText.type = SnapshotElems.Text.Type.LastOption; // LastOption 타입으로 변경 CopyCurrentToFinal(optionText); // 임시 FinalState PushTextsToDirection(layer, setting.CurrentFlowDirection, Vector2.zero); // 기존 텍스트 일괄적으로 해당 방향으로 밀기 (내부 조건체크에 따라 LastOption은 이 타이밍에는 제외된다) } else { Debug.LogError("cannot find option text to direction : " + setting.CurrentFlowDirection.ToString()); } }
/// <summary> /// 해당 오브젝트의 클래스 프로퍼티 정보를 전부 얻어둔다 /// </summary> /// <param name="settingObj"></param> private static void CachePropertiesForClass(IInGameSetting settingObj) { System.Type type = settingObj.GetType(); if (s_propLookupTable.ContainsKey(type)) // * 이미 캐싱되었다면 패스 { return; } // var propInfoTable = new Dictionary <string, PropertyInfo>(); s_propLookupTable[type] = propInfoTable; // IInGameSetting 의 프로퍼티 이름으로 해당 클래스 타입에서 검색하여 PropertyInfo를 얻어온다 int nameCount = s_propertyNames.Length; for (int i = 0; i < nameCount; i++) { string name = s_propertyNames[i]; propInfoTable[name] = type.GetProperty(name); } }
protected override LayerObjects.Image_UnityGUI MakeNewLayerObject(SnapshotElems.Image elem, IInGameSetting setting) { GameObject newObj = new GameObject("Image_UnityGUI"); newObj.transform.parent = ObjectRoot; return(new LayerObjects.Image_UnityGUI(this, newObj, setting)); }
public Image_UnityGUI(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { }
public Text_UnityGUI(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { //var module = parent as FSNTextModule_UnityGUI; //gameObject.guiText.font = module.font; }
protected override LayerObjects.Text_UnityGUI MakeNewLayerObject(SnapshotElems.Text elem, IInGameSetting setting) { GameObject newObj = new GameObject("Text_UnityGUI"); newObj.transform.parent = ObjectRoot; //newObj.AddComponent<GUIText>(); return(new LayerObjects.Text_UnityGUI(this, newObj, setting)); }
/// <summary> /// 프로퍼티 정보를 얻어옴 /// </summary> /// <param name="propertyName"></param> /// <returns></returns> protected static PropertyInfo LookupPropertyInfo(IInGameSetting settingObj, string propertyName) { //Debug.Log(string.Format("LookupPropertyInfo : {0} {1}", settingObj.GetType(), propertyName)); CachePropertiesForClass(settingObj); return(s_propLookupTable[settingObj.GetType()][propertyName]); }
/// <summary> /// 콜 추가 /// </summary> /// <param name="module"></param> /// <param name="segment"></param> public void AddCall(IFSNProcessModule module, FSNScriptSequence.Segment segment, IInGameSetting setting) { if (!m_moduleCallTable.ContainsKey(module)) { m_moduleCallTable[module] = new List <FSNProcessModuleCallParam>(); } m_moduleCallTable[module].Add(new FSNProcessModuleCallParam() { segment = segment, setting = setting }); }
protected override LibSequentia.LayerObject MakeNewLayerObject(LibSequentia.SnapshotElement element, IInGameSetting setting) { GameObject newObj = new GameObject("LS_Control"); newObj.layer = gameObject.layer; var lobj = new LibSequentia.LayerObject(this, newObj, setting); newObj.transform.SetParent(ObjectRoot, false); return(lobj); }
protected override LayerObjects.Text_NewUI MakeNewLayerObject(SnapshotElems.Text elem, IInGameSetting setting) { setting = elem.cachedSetting; // 캐싱된 세팅을 사용한다. GameObject newObj = new GameObject("Text_NewUI"); newObj.layer = gameObject.layer; var lobj = new LayerObjects.Text_NewUI(this, newObj, setting); newObj.transform.SetParent(ObjectRoot, false); return(lobj); }
protected override LayerObjects.Sound MakeNewLayerObject(SnapshotElems.Sound element, IInGameSetting setting) { GameObject newObj = new GameObject("Sound"); var lobj = new LayerObjects.Sound(this, newObj, setting); newObj.transform.SetParent(ObjectRoot, false); return(lobj); }
public Sound(FSNModule parent, GameObject realObject, IInGameSetting setting) : base(parent, realObject, setting) { m_asource = realObject.AddComponent <AudioSource>(); m_asource.spatialBlend = 0; // 완전한 2D 사운드로 }
public GObject(FSNModule parent, GameObject outerGameObj, GameObject realGameObj, IInGameSetting setting) : base(parent, outerGameObj, setting) { var newObjTr = realGameObj.transform; newObjTr.SetParent(outerGameObj.transform); newObjTr.localPosition = Vector3.zero; newObjTr.localRotation = Quaternion.identity; newObjTr.localScale = Vector3.one; // 리스너 구하기 (null이어도 무관) m_listener = realGameObj.GetComponent <FSNBaseGameObjectEventListener>(); }
//============================================================================= /// <summary> /// 새 레이어 오브젝트 인스턴스 생성 /// </summary> /// <returns></returns> protected abstract ObjT MakeNewLayerObject(ElmT element, IInGameSetting setting);
protected override LayerObjects.GObject MakeNewLayerObject(SnapshotElems.GObject elem, IInGameSetting setting) { GameObject prefab = elem.prefab; GameObject outerObj = new GameObject("(Outer)"); GameObject newObj = Instantiate <GameObject>(prefab); var lobj = new LayerObjects.GObject(this, outerObj, newObj, setting); outerObj.transform.SetParent(ObjectRoot, false); return(lobj); }
/// <summary> /// 트랜지션 애니메이션 시작. /// </summary> /// <param name="toLayer"></param> /// <param name="startRatioForOlds">기존 오브젝트들은 해당 비율부터 애니메이션 시작</param> /// <param name="backward">진행 반대 방향으로 swipe를 한 경우에는 false</param> /// <returns>트랜지션이 모두 끝나는데 걸리는 시간</returns> public float StartTransition(FSNSnapshot.Layer toLayer, IInGameSetting nextSetting, float startRatioForOlds, bool backward) { UpdateTargetLayerDiff(toLayer); // 비교 업데이트 float longestDuration = 0f; // 트랜지션 중 제일 오래걸리는 것의 시간 // *** 유지되는 오브젝트들 IterateMatchingUIDs((int uId) => { var elem = toLayer.GetElement(uId) as ElmT; float trTime = elem.TransitionTime / nextSetting.TransitionSpeedRatio; // 전환속도 비율 적용 m_objectDict[uId].DoTransition(elem, startRatioForOlds, trTime, false); if (longestDuration < trTime) { longestDuration = trTime; // 제일 긴 트랜지션 시간 추적하기 } }); // *** 다음에 사라지는 오브젝트들 IterateOnlyInThisUIDs((int uId) => { var currentElem = m_curLayerRef.GetElement(uId); // 다음 레이어에 없어질 현재 레이어 객체 var refelem = toLayer.GetRemovedElementOrNull(uId) // (정방향) 다음 레이어에 지워지는 해당 오브젝트에 관한 정보가 있다면 이것을 사용 ?? currentElem; // 아니면 현재 레이어의 해당 오브젝트를 사용하여 finalState를 구한다 var finalElem = (!backward)? refelem.GenericFinalState // 정방향일 경우 마지막 스테이트로 움직인 뒤 소멸, : refelem.GenericInitialState; // 역방향일 경우 최초 스테이트로 움직인 뒤 소멸해야한다. float trTime = finalElem.TransitionTime / nextSetting.TransitionSpeedRatio; // 전환속도 비율 적용 m_objectDict[uId].DoTransition(finalElem as ElmT, startRatioForOlds, trTime, true); if (longestDuration < trTime) { longestDuration = trTime; // 제일 긴 트랜지션 시간 추적하기 } }); // *** 다음에 처음 등장하는 오브젝트들 IterateOnlyInOtherUIDs((int uId) => { var currentElem = toLayer.GetElement(uId); // 다음 레이어의 해당 객체 var refelem = m_curLayerRef.GetRemovedElementOrNull(uId) // (역방향) 현재 레이어에 지워진 오브젝트의 정보가 있다면 그것을 사용, ?? currentElem; // 아니면 다음 레이어의 오브젝트를 참조해서 InitialState를 구한다 var initialElem = backward? refelem.GenericFinalState : refelem.GenericInitialState; // 역방향이면 finalState, 정방향이면 InitialState 로 초기세팅한다 float trTime = initialElem.TransitionTime / nextSetting.TransitionSpeedRatio; // 현재 상태로 transition하지만 시간값은 최초 상태값에 지정된 걸 사용한다. var newobj = AddNewLayerObject(initialElem as ElmT, nextSetting); newobj.DoTransition(currentElem as ElmT, 0, trTime, false); if (longestDuration < trTime) { longestDuration = trTime; // 제일 긴 트랜지션 시간 추적하기 } }); // NOTE : 트랜지션이 완전히 끝난 뒤에 레이어를 교체해야할 수도 있다. 이슈가 생기면 그때 바꾸자... m_curLayerRef = toLayer; // 현재 레이어를 트랜지션 타겟 레이어로 교체. OnLayerTransitionStart(toLayer); // 이벤트 호출 return(m_useTransitionDelay? longestDuration : 0); // 트랜지션 딜레이를 사용하지 않는다면 딜레이 시간은 0으로 }
/// <summary> /// 콜 추가 /// </summary> /// <param name="module"></param> /// <param name="segment"></param> public void AddCall(IFSNProcessModule module, FSNScriptSequence.Segment segment, IInGameSetting setting) { if(!m_moduleCallTable.ContainsKey(module)) m_moduleCallTable[module] = new List<FSNProcessModuleCallParam>(); m_moduleCallTable[module].Add(new FSNProcessModuleCallParam() { segment = segment, setting = setting }); }
public ImageLayerObject(FSNModule parent, GameObject gameObj, IInGameSetting setting) : base(parent, gameObj, setting) { }
/// <summary> /// 오브젝트가 존재하는 모든 모듈에 콜 보내기 /// </summary> /// <param name="segment"></param> /// <param name="setting"></param> public void AddAllModuleCall(FSNScriptSequence.Segment segment, IInGameSetting setting) { foreach (var callList in m_moduleCallTable.Values) { callList.Add(new FSNProcessModuleCallParam() { segment = segment, setting = setting }); } }