개인적으로 MS Visual Studio가 편하기 때문에 주로 VS로 소스코드를 작성하고 있다. 하지만 Unity에서 디버깅을 하기 위해선 Mono 역시 버릴 수 없는 상황인지라.. 두 에디터를 동시에 사용하고 있는데.. 두 에디터의 소스코드 저장방식이 달라 몇가지 불편한 점이 있다.
<Line Einding 방식>
Visual Studio : Windows (CR LF)
Mono : Unix (LF)
<소스코드 인코딩 방식>
Visual Studio : Korean - Codepage 949
Mono : UTF-8
위와 같이 되어있기때문에 VS에서 한글 주석을 달으면 Mono에서 한글이 깨져나오게 된다.
그래서 한가지 방식으로 통일하였는데.. 대부분 Unity 에디터에서 파일을 생성하기 때문에 Mono방식으로 통일하기로 했다.
또한 Codepage 949 방식은 MS가 개발한 한글 인코딩 방식으로 EUC-KR과 비슷한 방식이다. 하지만 Mono에서는 Codepage 949 형식을 지원하지 않기때문에 충돌이 날 수 있다.
결론은 UTF-8방식으로 인코딩을 설정하면 된다.
VS에서 설정을 바꾸려면 프로젝트가 열린 상태에서
FILE > Advanced Save Options 에서 Encoding: Unicode (UTF-8 with signature) - Codepage 65001
Line endings: Unix(LF)
p.s: 인터넷 서핑하다 발견한 한가지 사실: Unix(LF)로 저장할시 Visual Studio에서 break point가 잘 안 잡힐 수 있다고 한다. 내경우엔 현재 VS로 디버깅 할 일이 없어.. 그냥 쓰기로 함.
위와 같이 설정하더라도 매번 소스파일을 생성할때 기본값으로 생성되므로 매크로를 이용해 UTF-8파일을 생성하고 싶다면 아래 링크를 참고하면 될 것 같다.
http://nving.tistory.com/66
2013년 5월 20일 월요일
2013년 1월 2일 수요일
Unity3D: Texture를 돌리고 돌리고~
이 글은 제 전 티스토리 블로그에서 옮겨 왔습니다.
2D 텍스쳐를 어떻게 돌릴까?
현재 Unity3D의 기본 GUI는 GUIUtility.RotateAroundPivot 함수로 GUI를 회전시킬수가 있다. 하지만 OnGUI()함수 자체가 이벤트 발생시에만 호출되기 때문에 실시간 Rotation Animation을 표현하기엔 부족하다.
그래서 직접 2D Texture Mesh를 생성해서 Texture을 회전 시켜봤다.
Material 회전 시키는 코드는 완전 초간단하다. Unity Documents 에서 Material.SetMatrix() 함수에 대한 예제를 참고하면 된다. 여기
위에 링크에서 부족한 부분은 Texture의 Alpha처리 부분이 없다는 것이다. 이 부분은 Unity3D 내장 쉐이더인 Unlit-Alpha.shader 코드를 참고하면 된다. Light의 적용을 받을 필요없는 2D Texture를 위한 것이다.
이제 남은 문제는 회전이 되는 Texture의 Pivot이 맞지 않는다는 것이다. 내가 원하는 것은 중점을 기준으로 돌고 도는 텍스처이기 때문... 원점을 기준으로 도는 텍스쳐를 원한다면 위에 코드로 충분할지도...
여기서 먼저 Unity엔진의 UV좌표를 이해해야 한다. 일반적으로 다른 엔진에서의 UV좌표는 아래와 같다.
하지만 Unity3D의 UV좌표는 좀 다르다. (왜 그런지는 나도 모르겠음;;;)
그래서 텍스쳐의 좌표계를 생각해 UV를 맞춘다면 낭패다. Unity의 UV좌표계는 아래와 같기 때문이다.
여튼 좌표계가 저따위니 적절하게 UV를 이동한 후 Material에서 position을 offset 만큼 이동시켜 회전시키면 된다.
(일단 다른 방법은 잘 몰라 이렇게 했음..-_-;;)
보통 Sprite Animation을 할때 기준점으로 부터 이미지 사이즈만큼 Frame별로 그려주면서 Animation을 하는데 그걸 이용하면 간단하게 이동시킬 수 있다.
여기서 Mesh에 직접 접근하기 위해 MeshFilter와 MeshRenderer를 생성하고 몇가지 설정을 한다.
1.
mesh_renderer.castShadows =
false
;
2.
mesh_renderer.receiveShadows =
false
;
3.
mesh_renderer.sharedMaterial = material;
// 회전시킬 material 설정
그리고 2D 텍스쳐를 찍어줄 카메라로 부터 해상도 값을 계산해 온다. (화면 높이값 적용)
1.
float
pixelPerWorldUnit = Camera.mainCamera.orthographicSize * 2 / defCameraPixels;
생성한 mesh의 vertices값에 이를 곱해 해상도를 적용시켜 줄 수 있다. 마지막으로 offset이 적용된 uv값을 아까 좌표계에 맞게 설정해주면 끝!! 이 아니고;;; 생성한 최종 메쉬를 Mesh Filter에 적용시켜줘야 끝난다.
01.
mesh.vertices =
new
Vector3[] {
02.
new
Vector3(0, -texHeight) * pixelPerWorldUnit,
03.
new
Vector3(0, 0) * pixelPerWorldUnit,
04.
new
Vector3(texWidth, -texHeight) * pixelPerWorldUnit,
05.
new
Vector3(texWidth, 0) * pixelPerWorldUnit
06.
};
07.
08.
mesh.triangles =
new
int
[] { 0, 1, 3, 0, 3, 2 };
09.
10.
// Assign the basis of the uv coordinate to the uv of texture
11.
mesh.uv =
new
Vector2[] {
12.
new
Vector2(topLeft.x, topLeft.y),
13.
new
Vector2(topLeft.x, topLeft.y + 1f),
14.
new
Vector2(topLeft.x + 1f, topLeft.y),
15.
new
Vector2(topLeft.x + 1f, topLeft.y + 1f)
16.
};
17.
18.
mesh.Optimize();
19.
mesh.RecalculateNormals();
20.
mesh.RecalculateBounds();
21.
meshFilter.sharedMesh = mesh;
Unity Editor에서의 설정 모습은 아래와 같다.
offset 을 (-0.5, -0.5) 로 설정한 이유는 아까 Unity의 UV좌표계가 왼쪽 아래부터 (0, 0) 좌표이기 때문이다. 더 간단한 방법이 있는지는 나도 모르겠지만 일단은 이렇게 하는걸로~-_-ㅋ
2012년 12월 25일 화요일
Game Object's transform and rigidbody in Unity3D
transform 과 rigidbody의 경우는 게임을 구현하면서 가장 많이 쓰이는 변수들 중 하나이다.
이것들을 매번 함수 내에서 특히 Update()내에 호출을 하게 되면 Unity의 경우 검색 비용이 꽤 비싸서 그다지 추천하지 않는다.
그래서 Awake()단계에서 private 변수로 저장해 놓고 쓰는 것을 권장하는데 나의 경우는 하나의 GameObject에서 여러개의 클래스를 Component 기반으로 사용하기 때문에 이것도 비효율적이라고 생각하여 Property라는 Class에서 아예 이것들을 저장 해놓고 Singleton으로 static 하게 접근하여 사용한다.
예를 들어
public class Properties : MonoSingleton <Properties >
{
public Transform thisTransform;
public Rigidbody thisRigidbody;
//*
// other properties
//*
// This function is called when the instance is used the first time
// Put all the initializations you need here, as you would do in Awake
public override void Init()
{
// ...
thisTransform = transform;
thisRigidbody = rigidbody;
}
}
public class OtherComponent : MonoBehaviour
{
public void Update()
{
Properties .Instance.thisTransform.Translate(Vector3 .up * Time .deltaTime);
}
}
public class AnotherComponent : MonoBehaviour
{
public void Update()
{
Properties .Instance.thisTransform.Translate(Vector3 .up * Time .deltaTime);
}
}
일단 매번 Awake()내에서 저장 할 필요도 없고 검색 비용도 줄인다. 소규모 프로젝트라면 절약 비용이 미비하겠지만 코드가 좀 더 깔끔해진다는 것 만으로도 좋지 않을까 싶다. 아니면 말고..ㅎㅎ
p.s: 단, 주의 할 점은 Properties가 singleton이기 때문에 Clone 객체들에서는 사용하지 말아야 한다.
2012년 12월 23일 일요일
Singleton in C#
가장 많이 쓰이는 디자인 패턴중 하나인 Singleton을 C#에서 어떻게 구현하는지 알아보자.
Singleton은 매우 간단하지만 경우에 따라 구현방법이 여러가지가 있다.
멀티스레드를 고려하지 않은 방법, 늦은 로딩 인스턴스, 스레드에서 안전한 인스턴싱, 그리고 간단하지만높은 성능의 방법등..
이러한 방법들이 가지고 있는 공통적인 특징들은 아래와 같다.
- 다른 외부 클래스에서 인스턴싱 되는것을 막아준다. 또한 파생 클래스에서도 인스턴싱 될 수 없다.왜냐면 Constructor가 private으로 선언되기 때문이다.
- 그리고 싱글톤 클래스는 sealed class로 구현된다. 엄격히 말하면 이것은 불필요하다. 왜냐면 위에서말한데로 외부에서 인스턴싱되거나 파생이 불가능하기 때문이다. 하지만 JIT(just-in-time compiler)-인터프리트 방식과 정적 컴파일 방식을 혼합한 것임.- 가 최적화 하도록 도와줄수도 있다.
- static변수는 생성된 인스턴스를 하나의 레퍼런스로만 사용되도록 한다.
- public static는 인스턴스를 생성한 클래스의 싱글 레퍼런스를 얻는다는 의미이다.
참고로 모든 싱글톤 구현방식은 접근하기 위한 public static Instance 를 사용하고 있다.
not thread-safe
// 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 Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
위에 방식은 멀티스레드 상에서는 안전하지 않은 방법이다. 다른 두 스레드가 동시에 이 인스턴스에 접근하게 된다면 if (instance==null) 를 true로 판단할 수 있다.
Static Initialization
디자인 패턴에서 static Initialization을 피하는 이유중에 하나가 C++ 의 설계에서 static 변수들의 초기화가 모호성을 남기기 때문이다.
static변수의 경우 어플리케이션이 시작할때 BSS segment에 할당되는데 변수들간의 할당 순서가 규칙이 없기때문이다. 하지만 .NET Framework에서는 변수의 초기화를 핸들링하므로써 이러한 모호성이 해결되어졌다.
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton(){}
public static Singleton Instance
{
get
{
return instance;
}
}
}
위에 코드에서는 처음으로 참조하는 클래스의 멤버가 인스턴스를 생성하도록 구현되었다.
CLR(The Common Language Runtime)에서 변수의 초기화를 관리한다.
sealed class는 이 클래스가 다른곳에서 인스턴스가 추가되지 않도록 파생되는 것을 막아준다.
그리고 readonly 변수는 오직 static initialization 동안에만 할당되도록 할 수 있다.
다시말해 런타임시 이 변수에 다른 인스턴스로 초기화 할 수가 없다는 얘기이다.
이 구현방식은 앞서 예제와 비슷한다. 변수를 초기화가 CLR방식에 의존하고 있는거 빼고는...
싱글톤이 가지고 있는 두가지 문제를 해결해주고 있다.
첫째는 전역적 접근이 가능하다는 것과 둘째는 인스턴싱을 핸들링하므로써 늦은 초기화가 가능하다는 것이다.
위에서 보는 바와 같이 이 Singleton instance는 private static 멤버변수로 참조되어지기 때문에 어떠한 클래스가 이를 호출하기 전까진 인스턴싱되지 않을 것이다.
이 방식은 디자인패턴에서의 lazy instantiation 의 형태를 보여준다.
또한 디자인 패턴에서 말하는 초기화 모호성을 피하기 위해 nondefault constructor를 사용하거나 초기화 되기전 다른 task들을 수행해야했다.
하지만 .NET Framework 에서는 이러한 문제를 해결하기 위한 initialization을 수행하기때문에 위와 같은 옵션을 사용 할 필요가 없다. .NET의 static initalization을 싱글톤을 구현하기 알맞은 접근방법을 가지고 있다.
참고 사이트:
http://msdn.microsoft.com/en-us/library/ff650316.aspx
http://csharpindepth.com/articles/general/singleton.aspx
Multithreaded Singleton
아래의 코드는 멀리스레드 환경에서도 안전성을 위해 구현된 방식이다. 글 쓰다 지쳐서 걍 코드만 남김..;;;
더 자세한 내용은 아래 참고사이트를 보면 됨.(-_ -ㅋ)
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Singleton for Unity 3D
Unity에서 Singleton 패턴을 사용 할 경우 Unity 엔진의 특성에 맞게 신경 써야 할 것들이 있다. 하지만 기본적은 lazy instantiation 같은 개념은 동일하다. 또한 Generic 형식으로 사용하게 되면 원하는 클래스에 상속만 해주면 간단히 Singleton을 만들 수 있다.
아래 링크에 그에 대한 내용들이 있다.
피드 구독하기:
글 (Atom)