레이블이 uFrame인 게시물을 표시합니다. 모든 게시물 표시
레이블이 uFrame인 게시물을 표시합니다. 모든 게시물 표시

2015년 3월 12일 목요일

[uFrame 1.5] MVCVM인 이유

개요
uFrame에서 Controller가 ViewModel과 분리되어 있는 이유

본문

ViewModel은 기본적으로 복수개가 생성되는게 전제이므로, Controller (Business Logics)의 경우 구조적으로 ViewModel에 포함될 경우 ViewModel의 갯수만큼 메소드 역시 복제되는 결과를 낳는다. 결과적으로 메모리상에 같은 로직이 대거 복제되어 버리는 결과로 이어지기 때문에, Controller와 ViewModel은 분리되어 각 모델별로 Controller는 1개씩만 작성된다. 그렇기 때문에 Controller의 각 메소드의 제 1 인수는 ViewModel이다 (1:n의 관계이기에)

2015년 2월 6일 금요일

[uFrame 1.5] Customize Loading Scene

개요
현 시점에서 Loading Scene에 관한 문서화가 이루어져 있지 않은 관계로 사용방법을 정리하고자 한다.

참고
uFrame에 기본적으로 첨부되어있는 Loading scene을 참고

기본적으로 LevelLoaderView가 uFrameComplete에 구현되어 포함되어 있다.
OnGUI기반으로 작성된 UnityGUILevelLoaderView는 이 LevelLoaderView를 inherit하고있으며, 동일한 구조로 작성하면 된다.

Progress는 각 SceneManager의 *Scene.cs의 Load에서 progress에 대해 작업중인 메세지와 progress factor를 0.0-1.0 사이의 값으로 feedback해주면 된다.

수순

1. NGUI

이번에는 NGUI를 활용하여 Loading Scene을 구성해보고자 한다.

NGUI 3.x의 버전(이번에는 3.7.7)에서 하나의 UIRoot이하 UIWidget은, 각각 하나의 Layer를 가질 필요가 있다. Loading Scene은 로딩이 완료될때까지는 해당 Object가 파기되지 않으므로, 두개의 UIRoot가 공존하게 된다. 따라서 Loading용 UI는 Layer를 다르게 설정해 기존 UI와 구분되게할 필요가 있다.

이를 수행하지 않은 경우, 기존에 UIRoot에 대해 Anchor설정을 실시한 Object들은 제각각 알맞은 위치를 참조하지 않는 버그가 존재한다.

http://www.tasharen.com/forum/index.php?topic=11126.0

따라서, Loading용 UI레이어는 LoadingUI라던가 하는식으로 기존의 레이어와는 분리토록 하자.

그 이외에는 NGUI Slider나, 기타 NGUI용 위젯들을 이용하여 화면을 구성하고, 관련된 조작을 LevelLoaderView Inheritance에서 설정하면 되겠다.

2. LoadingSceneObject : MonoBehaviour

Loading scene용 Object는 DontDestroyOnLoad옵션이 걸려 이전 화면과 다음 화면의 transition이 종료될 때 까지화면에 존재하다, 특정 타이밍에 모두 파기되게 된다.

이를 위해서 Loading용 Scene의 GameObject에는 파기를 위한 마커와 같은것이 존재하는데, uFrame에서는 LoadingSceneObject : MonoBehaviour 와 같은 형태로 준비되어있다.
기본적으로 샘플로 제공된 Loading Scene의 LoadingSceneView라는 GameObject와 같은 구성에서 그 하위에 오브젝트들을 구성하면 LoadingSceneObject가 이미 첨부되어있기에 상관없으나, 그 밖에 화면을 구성하고자 한다면 LoadingSceneObject를 각 GameObject에 붙여두도록 하자. 이를 실시하지 않은 경우 Loading이 끝나더라도 오브젝트가 파기되지 않는다.

3. LevelLoaderView inheritances

Loading Scene의 LoadingSceneView(GameObject)에 LevelLoaderView의 inheritnace를 붙여줄 필요가 있다. UnityGUILevelLoaderView.cs를 참고하면 알겠지만, 아래에 간단하게 NGUI를 활용한 경우의 구성을 첨부한다.

 using UnityEngine;  
 public class CustomLevelLoaderView : LevelLoaderView  
 {  
      public UISlider m_slider;  
      public UILabel m_label;  
      public void Update() {  

           if(this.m_slider != null)
           {
                this.m_slider.value = Model.Progress;  
           }
           
           if (m_label != null) 
           {  
                this.m_label.text = Model.Status;  
           }  

      }  
 }  

4. Progress Feedback

예를들어 ItemScene.cs라는 SceneManager가 있다고 가정해보자, 그렇다면 해당 SceneManager의 경로는

{UnityProject}/Assets/{uFrameProject}/SceneManagers/ItemScene.cs

와 같은 경로가 될것이고, 정상적으로 작성된 SceneManager라면 아래와 같은 맴버 함수가 있을거라 생각된다.

public override System.Collections.IEnumerator Load(UpdateProgressDelegate progress)

여기서 progress에 대해 피드백을 실시하면 앞서 작성한 loading scene에서 LoadingSceneViewModel에서 보고된 데이터값을 subscribe하여 화면에 출력해주게 된다.

무의미하지만 적당하게 coroutine으로 작성된 예시를 보이자면

for (int i=0i<5i++) {
   progress("dummy "+i,i/5f);
   yield return new UnityEngine.WaitForSeconds(0.25f);        
}


와 같이 사용해볼 수 있겠다.

2015년 1월 18일 일요일

[uFrame 1.5] Diagram에서 일일히 connect하지 않고 직접 transition하기

개요

사실 다이어그램을 사용해서 플로우를 정리하는 것을 전제로하는 프레임워크에서 이런 설정은 사용에 따라 독이 될수도 있지만, 어떤 구조에서는 이 일일히 연결하는 작업이 오히려 구성에 있어서 중첩구현, 구조의 복잡화 등을 야기할 수 있다고 생각이 된다.

따라서 diagram에서 scene transition 설정을 일일히 설정하지 않고 암묵적으로 고정값으로 transition을 수행하고 싶은 경우 아래와 같은 실행코드를 command의 실행내용에 첨부하자.

수순

전체에서 공유할 1개의 subsystem과 그 기본 element를 각각 작성후, element에 대해서 공유할 커맨드를 추가하고, 각 subsystem에서 이 element름 참조하여 inheritance base로서 상속하여 Execute{COMMAND}를 각 view에서 호출 가능하게 한것을 전제로 한다.
그냥 다른 subsystem에서 view를 구성하여, 연결하지 않은 상태의 scene에서 공통적인 view를 호출하면 그만인 문제였다. 단, 각 Command는 사용하기 위해서 Registered Instance에 등록 될 필요가 있다. 상속하게 되는경우 base만큼의 메모리가 중첩 사용되어서 메모리 사용에 있어서 좋지 않다.

다이어그램에서 이 COMMAND는 따로 transition설정치 않고, COMMAND의 실행 구문에 아래의 코드를 추가하여 별다른 설정없이 특정 scene으로 transition하게끔 설정한다.

{SceneManager} = 작성한 scene manager의 이름
{LevelName} = scene file name
            GameManager.TransitionLevel<{SceneManager}> (  
                (container) =>   
                     {   
                          container._{SceneManager}Settings = new {SceneManager}Settings ();   
                          // something do on finished.  
                          Debug.Log("transition done");  
                     },  
                     new string[]{"{LevelName}"}  
           );  
상기의 기본 코드를 기반으로 작성한 generic function
 
 using System;

 /// <summary>  
 /// Transition uFrame Scene.  
 ///   
 /// Recommend place this function on singleton class or statically
 ///   
 /// Synopsys  
 /// TransitionScene<TitleScene> ("TitleScene");  
 ///   
 /// Compitable with uFrame 1.5.1 rc2  
 /// @author Donghyun You  
 /// @since 2015. 1. 18.  
 /// </summary>  
 /// <param name="sceneName">Scene name that registered on builtin levels</param>  
 /// <param name="onFinished">On finished.</param>  
 /// <typeparam name="T">The 1st type parameter.</typeparam>  
 public void TransitionScene<T>(string sceneName,Action onFinished=null) where T : SceneManager {  
      if (string.IsNullOrEmpty (sceneName))   
      {  
           throw new ArgumentNullException("sceneName");  
      }  
      Type type      = typeof(T);  
      onFinished      = onFinished ?? delegate() {};  
      GameManager.TransitionLevel<T> (  
           (container) =>   
           {   
                var settingParam = container.GetType ().GetField("_"+type.Name+"Settings");  
                var settingInstance = Activator.CreateInstance(Type.GetType (type.Name+"Settings"));  
                settingParam.SetValue(container,settingInstance);  
                // something do on finished.  
                onFinished();  
           },  
           new string[]{sceneName}  
      );  
 }  

2015년 1월 16일 금요일

[uFrame 1.5] 개발규약

 개요
uFrame을 통한 개발에 있어서 일부 알아두어야할 사전 규약, 구조중 별도 문서화 하기 애매한 기능들을 이하에 정리.

상시 수정함.

본문

1. RenderSettings의 설정
    uFrame에서는 Scene단위로 RenderSetting이 가능하도록 RenderSettings와 같은 내용이
   GameManager에 준비되어 있다. 해당 Scene으로 이동했을때 마다 GameManager>RenderSettings에 설정된 내용대로 다시 설정된다.

   일단 기존의 RenderSettings에서 설정후, GameManager의 LoadFromScene버튼으로 바로 불러오는것 또한 가능하다.

[uFrame 1.5] Scene Transition

개요
uFrame에서 scene transition을 가능하게 하기까지의 수순을 정리
생각보다 복잡하다.

수순

1. SceneManager를 작성
2. SceneManager에 대해 1개의 subsystem을 작성. 이를 connect한다.

subsystem은 scene을 transition할 command를 가지는 1개의 element를 필요로 하며, view또한 필요로 한다.

3. 1개의 SceneManager용으로 작성된 Subsystem에 대해 root element1개를 작성
4. root element에 대해 view를 1개 작성하고 이를 root element에 연결한다.
5. root element에 scene transition용 command를 작성한다.
6. scene간의 이동이므로 적어도 상기 2개의 scene을 구성한다.
7. 각 SceneManager에 대해 각각 transition을 작성, 이동할 scene과 연결한다.
8. Save and compile
9. SceneManager에 대해 실제 Scene을 작성한다(SceneManager의 context menu)
10. 작성된 scene에 4에서 작성한 view를 각각 화면상의 특정 오브젝트에 attach하거나 create함.
11. 각 scene의 SceneManager의 instance에서,<COMMAND> Transition -> Scene의 목록을 늘려 이동할 scene파일의 이름을 지정한다.
12. 작성된 scene파일을 build target에 추가한다
13. Loading이라는 특수 scene또한 build target에 추가한다.
14. 게임을 실행
15. 게임을 실행하면 view component의 inspector는 그 내용이 달라져있다. 제일 아래의 command에서  transition용 command를 실행.

위에서는 정적인 scene에 대해 이동하게 설정하나, string으로 scene파일을 지정하게끔 설정하는것 또한 가능하다. command에 대해 string을 받게끔 설정하고, SceneManager 소스코드에서public override IEnumerable<string> GetToTitleSceneScenes (string arg)를 override하여 return []{arg};와 같이 설정하여 SceneManager insepector에서 설정한것이 아닌 Command의 호출시의 인수에 의거하여 Scene을 이동하게끔 설정한다 (공식 video tutorial에 나와있는 내용)

http://invertgamestudios.com/uFrameAPI/Default/webframe.html#Scene%20Transitions.html

2015년 1월 15일 목요일

[uFrame 1.5] uFrame에서 특정 타입을 diagram에서 이용 가능하게함

개요
uFrame의 plugin을 작성하여, uFrame에서 특정 타입이 이용 가능하게 함.

수순
uFrame의 기본적인 플러그인 소스코드가 아래 패스에 배치되어 있음.
이를 참고로, 동일한 플러그인을 작성하여 Editor폴더 이하에 배치하면 로드됨.

Editor는 굳이 uFrameComplete폴더 이하일 필요는 없음

[Unity Project/Assets]/uFrameComplete/uFrame/uFramePlugins/CorePlugin/Editor/UFrameEditorPlugin.cs

namespace dependancies

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Invert.StateMachine;
using Invert.uFrame;
using Invert.uFrame.Code.Bindings;
using Invert.uFrame.Editor;
using Invert.uFrame.Editor.ElementDesigner;
using Invert.uFrame.Editor.ElementDesigner.Commands;
using UniRx;
using UnityEngine;


Inheritance

public class UFrameModelTypesPlugin : DiagramPlugin


Required Overrides
 public override decimal LoadPriority  
   {  
     get { return 1; }  
   }  
   public override bool Enabled  
   {  
     get { return true; }  
     set {}  
   }  
   public override void Initialize (uFrameContainer container)  
   {  
     var typeContainer = uFrameEditor.TypesContainer;  

     // Color는 기본 설정에 포함되어있지 않음.
     typeContainer.RegisterInstance (new ElementItemType () {  
       Type = typeof(Color),  
       Group = "",  
       Label = "Color",  
       IsPrimitive = true,  
       IsUnityEngine = true,  
     },"Color");  

   }  

현재 1.5rc2버전을 기준으로
Namespace이하에 배치된 타입에 관해서는 자동 생성에서 하위 namespace route가 없어져버리는 버그가 발생하고 있다. 다른 해결방법을 찾지 못한다면 자동생성후 매번 using namespace ...를 해줘야하는 불편함이 있다.

2014년 11월 22일 토요일

MVVM @ Unity3D

몇번의 프로젝트를 경험하며, 프론트엔드(클라이언트)에서의 프레임워크가 필요하다고 생각되어 이리저리 뒤지던차, 최근 Unite 2014에서 시연하던 내용중에 괜찮은 MVVM프레임워크가 발표되어 있어, 한번 손을 대보게되었습니다

uFrame이라는 프레임워크로

MVVM...에 가까운 환경을 제공합니다.

가깝다는 말이 무슨말이냐면, Microsoft에서 제창하고 있는 그 MVVM과 완전히 동일한 물건은 아니라는 말입니다.

개인적으로 MV*패턴에 있어서 가장 이해하고 있는 패턴은 Restful API개발등으로 연이 닿았던 CakePHP와 같은 Rails와 같은 계통의 MVC패턴을 개인적인 범주내에서는 가장 이해를 하고 있습니다.

MVVM은 Model, View, View-model의 약자로, MVC의 Model View Controller에 있어서 Controller가 View-Model이 대치된 형태의 디자인 패턴입니다.

웹에서의 MVC는 기본이 한번의 http리퀘스트에 대한 response까지만 해결을 하면 되기때문에, 기본적으로 클래스를 MVC의 각 역할에 맞춰, 단순한 한번의 호출에 대한 처리에 대한 정리만 해 놓은 정도의 내용입니다만. uFrame에서 말하고있는 MVVM에서의 데이터 연동은, 실시간 적용을 전제로 생각하는 구조를 하고있습니다. 일반적으로 Observer Pattern으로 이야기되는 그런 부분이죠.

Model에 변경이 있었을 경우, Binding된 View로 모든 데이터 변동이 적용되는 구조를 갖추고있는데, 이를 중간역할을 하는 View-Model이 담당을 하고있습니다.

여기에 더불어, uFrame에서는 ViewModel에 대해 Controller가 붙어있습니다.
그래서 엄밀히는 MVCVM이라 부른다는것 같긴합니다.

http://answers.invertgamestudios.com/chat/i-know-mvc-and-mvvm-but-i-m-not-certain-i-quite-get-uframe

일반적인 Rails의 MVC의 C는 엄밀히 이야기하자면 Framework에 정의된 routing의 결과 주소에 관한 endpoint에 대한 하나의 http리퀘스트의 처리 컨트롤을 지칭하고 있지만,

uFrame에서의 Controller는 View----Command----->ViewModel---->model과 같은 뷰 모델로의 커맨드 처리의 로직을 구현하는 부분에 해당하는것 같습니다.

실제로 관련 로직이 Controller에 배치되게끔 권장이 되고 있습니다.

현 시점에서 디자인패턴에 관한 이야기는 위와 같은 정도로 정리를 할 수 있을거같고, 향후에 더 조사를 하며 실제 프로젝트에 적용이 가능한지 정도까지를 조사를 진행해볼 생각입니다.
다만 1.5버전 자체가 아직 베타버전으로 파이널 릴리스가 나와있지 않기때문에 현재 작업을 해보면서 발생하는 문제나, 문서화의 부족등으로 인한(소스는 오픈소스가 아님) 난제가 없지않아 남아있기 때문에 아직은 사용상에 문제가 많이 발생할지도 모르겠습니다.


그럼에도 불구하고, 이 프레임워크를 사용해보려는 이유는 아래와 같습니다.

1. 스튜디오급 이상의 조직에서 개발되고있으며, 유지보수가 진행중
2. 다이어그램을 통한 클래스의 형상관리가 가능. 심지어는 다이어그램을 중심으로 해서 관련 기반 코드가 자동 작성됨(!)
3. 어느정도 정립된 패턴에서 비지니스 로직을 개발함으로서, 타인과의 소통이 용이, 스파게티 코드의 회피.
4. 기존 몇몇 mv*프레임워크가 없는건 아니지만, 현 시점에서 유지보수가 되고있는지는 미지수, 혹은 그런 흔적이 보이지 않음.


아직 개발도상에 있는 프레임워크지만, 중단기적으로 생각했을때 어느정도 기대해볼수 있지 않나라는 생각이 들어서... 가 주요 이유가 되겠습니다.

아무래도 실제 개발투입에 이용하기 어렵다는 결론이 나오면 다른 오픈소스 프레임워크 등으로 눈을 돌려야겠지만 말입니다.

요 며칠 실제로 만져보며 이것저것 해본결과, 어느정도 Element운용(메모리 사용량 등의 이유)에만 주의하면 충분히 좋은 프레임워크로서 이용 가능하지 않나 하는 생각이 듭니다.

그리고 문서화좀 더...

Overview
http://invertgamestudios.com/uFrameAPI/Default/webframe.html#uFrame%201.5%20Overview.html

Asset Store
https://www.assetstore.unity3d.com/en/#!/content/14381