=================================
=================================
=================================
//아래와 같이 만들고 상속하여 사용한다.
public class CSingleton<T> : MonoBehaviour where T : class, new()
{
protected static T _inst = null;
public static T Inst
{
get
{
if (_inst == null)
{
_inst = new T();
}
return _inst;
}
}
}
class MyClass : Singleton<MyClass>
{
// contents
public void Print()
{
Log("Singleton OK");
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------------
//싱글톤 생성하면서 Init()초기화용 함수추가 소스(싱글톤 생성시 초기화가 필요할때 필요한 부분)
//----------------------------------------------
//기본 싱글톤
public class CSgtBase
{
public virtual void InitSgt() {}
}
public class CSingleton<T> : CSgtBase where T : CSgtBase, new()
{
protected static T _inst = null;
public static T Inst
{
get
{
if (_inst == null)
{
_inst = new T();
_inst.InitSgt();
}
return _inst;
}
}
}
//-------------------------------------------------------
//유니티 오브젝트 싱글톤
public class CSgtGObjBase : MonoBehaviour
{
public virtual void InitSgt() {}
}
public class CSingletonGObj<T> : CSgtGObjBase where T : CSgtGObjBase
{
protected static T _inst;
public static T Inst
{
get
{
if (_inst == null)
{
GameObject obj;
obj = GameObject.Find(typeof(T).Name);
if (obj == null)
{
obj = new GameObject(typeof(T).Name);
_inst = obj.AddComponent<T>();
_inst.InitSgt();
DontDestroyOnLoad(obj);
}
else
{
_inst = obj.GetComponent<T>();
}
}
return _inst;
}
}
}
=================================
=================================
=================================
출처: https://karl27.tistory.com/54
C# 싱글톤 패턴 상속용 클래스
알게된 배경
싱글톤 패턴은 비교적 자주 사용되는 패턴이고, 멀티 스레드 프로그램을 작성할 경우 서로 상성이 안좋기 때문에 크리티컬 섹션에 대해서 뮤텍스(C#에서는 락)을 잡아줘야 한다. 문제는 이러한 패턴은 매번 반복이 되기 때문에 부모 클래스로서 작성을 해놓고, 상속받아서 기능을 구현하는 것이 여러모로 편리하다고 생각이 들기 때문에 찾아보니 해당 패턴이 있었다.
그래서 메모겸 샘플 코드를 남긴다
부모 싱글톤
예시)
namespace Single { public class Singleton<T> where T : class, new() { protected static object _instanceLock = new object(); protected static volatile T _instance; public static T Instance { get { lock(_instanceLock) { if(null == _instance) _instance = new T(); } return _instance; } } } }
자식 싱글톤
예시)
namespace Single { class MyClass : Singleton<MyClass> { // contents public void Print() { Console.WriteLine("Hello Singleton?"); } } }
출처: https://karl27.tistory.com/54 [불확정한 세상]
=================================
=================================
=================================
출처: https://sillyknight.tistory.com/30
Unity Singleton을 제네릭으로 만들어놓고 써봅시다.
안녕하세요.
오늘은 유니티에서 자주 사용하는 대표적인 디자인 패턴인 Singleton을 쉽게 사용하기 위하여 제네릭으로 만들 겁니다.
제네릭이란 C++ 을 사용하신 분은 다들 아시는 템플릿과 비슷한 개념인데요.
유니티를 사용하는 상황에서는 C#을 쓰기 때문에 C++과는 차이점이 존재합니다.
아래는 Msdn에서 정의되어 있는 C#의 제네릭과 C++의 템플릿과의 주요 차이점입니다.
|
이것 외에도 구현 부분에서 가장 큰 차이점은 C#의 제네릭 형식 대체는 런타임에 수행되므로 인스턴스화된 개체에서
제네릭 형식 정보가 유지된다는 점입니다.
위에 부분을 숙지 하시고 제네릭을 만들어 봅시다.
using UnityEngine; public class Singleton<T> : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { if(instance == null) { GameObject obj; obj = GameObject.Find(typeof(T).Name); if (obj == null) { obj = new GameObject(typeof(T).Name); instance = obj.AddComponent<T>(); } else { instance = obj.GetComponent<T>(); } } return instance; } } public void Awake() { DontDestroyOnLoad(gameObject); } } |
자 위와 같이 비교적 쉽게 만들 수 있는데요. Manager를 만들 시 우리는 보통 Singleton 형태로 만드는데요. 아래와 같이 하
시면 끝입니다.
using UnityEngine; public class Manager: Singleton<Manager> { }
|
다들 즐거운 코딩하시고 싱글톤은 앞으로 제네릭으로 만들어 놓고 편하게 쓰시길 바랍니다.
감사합니다.
출처: https://sillyknight.tistory.com/30 [실리의 Unity 게임 세상]
=================================
=================================
=================================
출처: http://lonpeach.com/2017/02/04/unity3d-singleton-pattern-example/
Unity3d Singleton 패턴을 사용하는 방법
01. 싱글톤 패턴
싱글톤 패턴이란?
싱글톤 패턴은 가장 많이 알려진 패턴 중 하나입니다.
본질적으로 싱글톤은 자신의 단일 인스턴스만 생성될 수 있게 해주는 클래스이며 일반적으로 해당 인스턴스에 대한 간단한 액세스를 제공합니다.
일반적으로 유니티에서 매니저 클래스나 컨트롤러 클래스를 싱글톤으로 만들어서 관리해 주는 편입니다.
유니티에서의 싱글톤은 2가지 버전으로 구분할 수 있습니다.
- C# 싱글톤 버전
- Monobehaviour 버전
기존에는 싱글톤 패턴을 사용할 때 내가 편한 방식으로 사용을 했었고 가장 간단한 방식을 선호 했었는데. 조금은 안전한 싱글톤 패턴을 사용하기 위해서 고민이 필요할 것 같다.
1. C# 싱글톤 버전
스레드 세이프 하지 않은 버전
// Bad code! Do not use! public sealed class Singleton { private static Singleton instance=null; private Singleton() { } public static Singleton Instance { get { if (instance==null) { instance = new Singleton(); } return instance; } } }
간단히 구현된 스레드 세이프 한 버전
public sealed class Singleton { private static Singleton instance = null; private static readonly object padlock = new object(); private Singleton() { } public static Singleton Instance { get { lock (padlock) { if (instance == null) { instance = new Singleton(); } return instance; } } } }
스레드 세이프한 방법을 사용하자.
제네릭을 사용한 방법
using System; using System.Reflection; public class Singleton<T> where T : class { private static object _syncobj = new object(); private static volatile T _instance = null; public static T Instance { get { if (_instance == null) { CreateInstance(); } return _instance; } } private static void CreateInstance() { lock (_syncobj) { if (_instance == null) { Type t = typeof(T); // Ensure there are no public constructors... ConstructorInfo[] ctors = t.GetConstructors(); if (ctors.Length > 0) { throw new InvalidOperationException(String.Format("{0} has at least one accesible ctor making it impossible to enforce singleton behaviour", t.Name)); } // Create an instance via the private constructor _instance = (T)Activator.CreateInstance(t, true); } } } }
리플렉션 기능을 사용하여 생성된 인스턴스 수를 체크 후 1개 이상이면 익셉션 에러를 띄운다.
2. Monobehaivour 버전
간단한 방법
using UnityEngine; using System.Collections; public class Singleton: MonoBehaviour { public static Singleton instance = null; //Static instance of GameManager which allows it to be accessed by any other script. //Awake is always called before any Start functions void Awake() { //Check if instance already exists if (instance == null) { //if not, set instance to this instance = this; } //If instance already exists and it's not this: else if (instance != this) { //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager. Destroy(gameObject); } //Sets this to not be destroyed when reloading scene DontDestroyOnLoad(gameObject); } }
Generic을 사용한 방법
using UnityEngine; using System.Collections; /// <summary> /// Be aware this will not prevent a non singleton constructor /// such as `T myT = new T();` /// To prevent that, add `protected T () {}` to your singleton class. /// As a note, this is made as MonoBehaviour because we need Coroutines. /// </summary> public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour { private static T _instance = null; private static object _syncobj = new object(); private static bool appIsClosing = false; public static T Instance { get { if (appIsClosing) return null; lock (_syncobj) { if (_instance == null) { T[] objs = FindObjectsOfType<T>(); if (objs.Length > 0) _instance = objs[0]; if (objs.Length > 1) Debug.LogError("There is more than one " + typeof(T).Name + " in the scene."); if (_instance == null) { string goName = typeof(T).ToString(); GameObject go = GameObject.Find(goName); if (go == null) go = new GameObject(goName); _instance = go.AddComponent<T>(); } } return _instance; } } } /// <summary> /// When Unity quits, it destroys objects in a random order. /// In principle, a Singleton is only destroyed when application quits. /// If any script calls Instance after it have been destroyed, /// it will create a buggy ghost object that will stay on the Editor scene /// even after stopping playing the Application. Really bad! /// So, this was made to be sure we're not creating that buggy ghost object. /// </summary> protected virtual void OnApplicationQuit() { // release reference on exit appIsClosing = true; } }
사용 방법
public class Manager : Singleton<Manager> { protected Manager () {} // guarantee this will be always a singleton only - can't use the constructor! public string myGlobalVar = "whatever"; }
Generic을 사용한 방법에서는 Singleton을 상속받은 클래스에서는 생성자를 반드시 protected로 선언을 해서 외부에서는 생성이 되지 않게 막는다.
그리고 Singleton 클래스의 applicationIsQuitting 변수의 경우 별로 깨끗하지 않은 방법인것 같지만.. 유니티 에디터 상에서 갑자기 나가버리는 경우에 에러가 발생하는 경우라 반드시 필요한 변수이다. 이렇게 로직을 처리할 시에는 instance가 null이 나오는 경우가 생기므로 null 처리를 따로 처리해줘야 된다.
만약에 씬이 변환 되도 파괴되지 않은 싱글톤을 만들고 싶을 시에는 상속받은 클래스의 awake 함수에 아래와 같이 선언한다.
DontDestroyOnLoad(this.gameObject); 의 함수를 실행시켜 주자.
=================================
=================================
=================================
출처: https://unityindepth.tistory.com/38
출처: https://unityindepth.tistory.com/38 [UNITY IN DEPTH]
=================================
=================================
=================================
출처: http://rapapa.net/?p=3198
[ Programming Pattern 시리즈 ]
싱글턴 패턴 (Singleton Pattern) Link
컴포넌트 패턴 (Component Pattern) Link
커멘드 패턴 (Command Pattern) Link
관찰자 패턴 (Observer Pattern) Link
상태 패턴 (State Pattern) Link
Singleton Pattern의 GoF 정의는 아래와 같다.
“오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공합니다”
싱글턴 패턴은 게임 개발자들이 많이 사용하는 패턴이다. 특히 Manager류의 클래스를 만들거나, 오디오, 이벤트 등 디바이스 I/O를 다루는 곳에서도 자주 쓰인다.
유니티에서 싱글톤 객체를 구현하는 방법은 Scene에 빈객체를 생성한 후에 오직 하나의 객체만 생성되도록 만들고, DontDestroyOnLoad 메쏘드를 호출하여 Scene 변경시에도 Destroy를 막아주는 형태로 구현한다. 아래는 그 예이다.
<GameManager.cs>
이렇게 구현 해 놓으면 게임 내부의 어느 곳에서든지 GameManager.instance 로 모두 접근 가능하고, 하나의 객체로 중복 생성 없이 객체를 유지할 수 있다.
또한 싱글턴 객체를 상속하여 유익한 구조를 만들 수도 있다. 다음은 C++ 코드로 PS3와 NDS 파일 시스템 구분을 싱글턴 객체를 상속하여 손쉽게 구현하는 방식이다.
이렇게 구현해 놓으면 다른 모든 클래스에서는 플랫폼의 구분을 할 필요 없이 FileSystem.instance 호출 만으로 플랫폼에 맞는 File System을 획득하게 된다.
이처럼 싱글턴은 여러모로 유용하게 사용할 수 있으나 의외로 싱글턴이 문제를 일으키는 경우도 많다. 그래서 많은 개발자들이 싱글턴의 사용을 즐겨하지만 또 많은 개발자들이 싱글턴 오용의 위험성을 경고한다.
왜냐하면, 싱글턴은 일종의 전역 변수이기 때문이다.
전역 변수이므로 전역 변수가 가지는 모든 장점과 단점을 다 가지고 있다. 모든 곳에서 접근 가능하니, 객체의 변경 시점과 변경 주체를 알기가 쉽지 않다. 호출하는 모든 코드들을 다 뒤져야 할 수 있다. 또한 전역 변수이기 때문에 여러 클래스와 Coupling이 된다. 하나의 코드를 수정했을 때 싱글턴과 연결된 다양한 곳에서 문제를 발생 시킬 수 있는 것이다. 가능한한 Instance 접근을 통제하는 것이 결과적으로 더 적은 버그를 만들게 한다. 또한 전역 변수이기 때문에 멀티 쓰레드의 환경에서는 문제가 발생한다. 모든 곳에서 접근 가능하기 때문에 race condition이 발생할 수 있다. 그걸 피하기 위해서 필연적으로 싱글턴에선 mutex lock과 unlock을 반복해서 걸게 되는게 자연히 코드 전체적으로 Performance가 떨어지는 문제가 발생한다. 유니티 C#에서는 싱글톤에 연결된 reference 객체들이 사용이 끝났음에도 불구하고 null을 먹여주지 않으면 GC로 넘어가지 않는 문제도 발생한다.
Singleton의 대안으로는 가능한 Manager류의 생성을 피하고 각 클래스 안으로 코드를 집어 넣는 것이다. 또한 전역 접근이 불가능한 Singleton을 만드는 것도 방법이다. 대신 클래스끼리 서로 넘겨주고 받으면서 사용하거나, 상위 클래스로부터 얻거나, 이미 전역인 객체 안에 위치시켜서 접근 방식 자체를 줄이는 것도 생각해 볼 수 있다.
=================================
=================================
=================================
출처: https://bluemeta.tistory.com/16
1. 싱글턴 패턴
싱글턴 패턴이란 소프트웨어 디자인 방법 중에 하나입니다.
유니티로 게임을 개발하다보면 여러 게임오브젝트가 접근해야하는 스크립트가 있을 수 있습니다. 대표적으로 게임매니저(GameManager) 역할을 하는 스크립트인데요. 게임의 전체 볼륨을 조절한다거나 난이도 설정, 오브젝트 풀 관리 등의 목적으로 게임매니저 스크립트를 만들어 사용하곤 합니다. 이렇듯 단일 시스템 자원을 관리하는 타입이 필요한 경우가 있습니다.
전체 게임(씬)의 자원을 관리하는게임매니저 스크립트. 사람들이 정말 많이 사용하는지 유니티 에디터에서 전용 아이콘도 만들어줍니다. ^^
(절대강좌! 책 공부 중...)
게임매니저 스크립트와 같은 경우는 여러 스크립트에 영향을 줍니다. 그리고 일종의 전역변수(static variable)과 같은 역할도 겸하고 있습니다. 즉, 많은 다른 스크립트가 하나의 스크립트에 접근해야하고 접근할 때 스크립트마다 각각 인스턴스화하는 것이 아니라 하나의 인스턴스로 충분할 경우(전역 변수의 역할과 똑같죠?) 싱클턴 패턴을 사용하는 것이 효과적입니다.
싱글턴은 최초로 생성된(클래스가 메모리에 로드될 때 만들어지는) 인스턴스만 존재하고 이후에는 생성 자체가 불가능(private하다는 의미겠죠?)한 소프트웨어 디자인 방법입니다.
2. 유니티에서 싱글턴 패턴 만드는 방법
싱글턴 패턴을 만드는 방법은 여러 방법이 있고 이론적으로도 복잡하지만. 유니티에서 싱글턴 패턴을 만드는 방법은 아주 간단합니다.
아래 코드를 확인해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public static GameManager instance;
public int level;
void Awake () {
instance = this;
}
}
|
cs |
GameManager 타입의 전역 변수 instance를 선언한 후 Awake() 메소드에서 this를 할당해주면 바로 싱클턴 패턴을 만들 수 있습니다. 즉, 재귀적으로 자기 자신의 참조변수를 선언하고 this 키워드로 설정하면 됩니다. Awake() 메소드를 사용하는 이유는 GameManager 스크립트가 씬에 생성되자마자 싱글턴 인스턴스를 만들기 위함입니다. 이렇게 하면 별도의 GetComponent<GameManager>() 메소드를 사용하지 않고도 instance 변수에 접근할 수 있습니다. 다음과 같이 말이죠.
1
2
3
4
5
6
7
8
9
10
11
12
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WormCtrl : MonoBehaviour {
void Start ()
{
GameManager.instance.hp = 100;
}
}
|
cs |
WormCtrl이라는 스크립트에서 별도의 코드 없이 GameManager.instance 인스턴스에 접근할 수 있습니다. 그리고 GameManager의 hp를 바로 설정할 수 있고 다른 모든 스크립트에서 이 hp값을 공유합니다. 아주 편리한 기능이죠.
3. 싱글턴 패턴의 접근제한자
싱글턴 인스턴스가 가지고 있는 필드와 프로퍼티는 기본적으로 public이어야 합니다. 그렇지 않으면 다른 스크립트에서 싱글턴 인스턴스에 접근하더라도 해당 필드, 프로퍼티는 사용할 수 없기 때문입니다. 물론 싱글턴 내부에서만 사용할 경우에는 private라도 상관없겠지요.
4. 정리
- 싱글턴 패턴은 디자인 패턴 중 하나로 단일 시스템 자원을 관리하는 인스턴스이다.
- 싱글턴 패턴으로 만든 싱글턴 인스턴스는 게임(씬) 내에 하나만 존재한다.
- 싱글턴 패턴은 자기 자신을 타입으로 하는 참조변수의 선언과 Awake() 메소드에서 this 키워드로 그 참조변수를 설정하면 바로 사용 가능하다.
- 싱글턴 패턴의 필드, 프로퍼티는 그 성격상 접근제한자를 public으로 하는 것이 좋다.
=================================
=================================
=================================
'게임엔진관련 > 유니티 엔진' 카테고리의 다른 글
[Unity] 유니티개발 csv 파일 읽기 관련 (0) | 2019.03.21 |
---|---|
[Unity] 유니티개발 다국어 지원하기 관련 (0) | 2019.03.21 |
[Unity] 유니티 웹뷰 webView 개발 관련 (3) | 2019.03.04 |
[Unity] 유니티 GUI 버튼(Button)에 이벤트, 연결등등 관련 (13) | 2019.01.29 |
[Unity] UGUI 캔버스(canvas) 관하여 관련 (0) | 2019.01.17 |
댓글 영역