블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2845)
Unity3D (891)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (188)
협업 (64)
3DS Max (3)
Game (12)
Utility (141)
Etc (99)
Link (33)
Portfolio (19)
Subject (90)
iOS,OSX (52)
Android (16)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (19)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday


[사진 : 서브웨이 서퍼 플레이 스크린샷]



출처 : http://answers.unity3d.com/questions/288835/how-to-make-plane-look-curved.html

http://devkorea.co.kr/bbs/board.php?bo_table=m03_lecture&wr_id=3315&page=0&sca=&sfl=&stx=&sst=&sod=&spt=0&page=0&currentId=42


위의 사진처럼 땅이 평평하지 않고 휘어지는 듯한 효과를 연출하기 위함이다. 

땅 자체를 곡선으로 만들수도 있겠지만 

카메라가 보는 부분의 렌더링을 수정함으로써 효과를 낼 수 있다.



BendTheWorldShader.unitypackage


위의 파일은 예제 파일이며, 

https://dl.dropboxusercontent.com/u/7761356/UnityAnswers/Web/BendTheWorld/WebPlayer.html

웹에서도 실행을 해볼 수 있다.



적용 방법 : 


위의 예제파일이나, 웹에서 보듯이 shader프로그래밍을 하면 된다.

shader 파일을 생성한다.



shader 파일에 아래와 같이 코드를 입력한다.


접기


Shader "Custom/Curved" {

Properties {

_MainTex ("Base (RGB)"2D) = "white" {}

_QOffset ("Offset"Vector) = (0,0,0,0)

_Dist ("Distance"Float) = 100.0

}

SubShader {

Tags { "RenderType"="Opaque" }

Pass

{

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

#include "UnityCG.cginc"


            sampler2D _MainTex;

float4 _QOffset;

float _Dist;

struct v2f {

    float4 pos : SV_POSITION;

    float4 uv : TEXCOORD0;

} ;

v2f vert (appdata_base v)

{

    v2f o;

    // The vertex position in view-space (camera space)

    float4 vPos = mul (UNITY_MATRIX_MV, v.vertex);

    

    // Get distance from camera and scale it down with the global _Dist parameter

    float zOff = vPos.z/_Dist;

    // Add the offset with a quadratic curve to the vertex position

    vPos += _QOffset*zOff*zOff;

    

    o.pos = mul (UNITY_MATRIX_P, vPos);

    o.uv = mul( UNITY_MATRIX_TEXTURE0, v.texcoord );

    return o;

}


half4 frag (v2f i) : COLOR

{

    half4 col = tex2D(_MainTex, i.uv.xy);

    return col;

}

ENDCG

}

}

FallBack "Diffuse"

}






작성한 shader 파일을 texture의 shader로 적용한다.





그러면 카메라의 위치에서 멀리 있는 객체일수록 z축의 아래로 쳐져 있는 듯한 효과를 나타낼 수 있다. 




이제, 휘어지게 보여질 객체에 스크립트에서 처리해야 한다



mOffset =  new Vector2(0.0f,-1.8f)

        mModelsRenderer = mModel.GetComponentsInChildren<Renderer>();

mModelsMeshFilter = mModel.GetComponentsInChildren<MeshFilter>();

foreachRenderer render in mModelsRenderer )

render.material.SetVector("_QOffset", mOffset );

foreachMeshFilter meshfilter in mModelsMeshFilter )

meshfilter.mesh.bounds = new BoundsVector3.zero, Vector3.one * 3000 );



render.material.SetVector("_QOffset", mOffset )

 는 휘어지는 방향과 크기를 정하며


meshfilter.mesh.bounds = new BoundsVector3.zero, Vector3.one * 3000 );

는 mesh범위를 키워 카메라에서 멀리 있어도 휘어지는 효과 그대로 화면에 보이도록 함이다.




출처 : http://jenemia.tistory.com/258

반응형
Posted by blueasa
, |

유니티 5.3.1 f1 로 버전업 했더니, NGUI 에서 범상치 않은 워닝을 내뱉었다.


1
2
3
Assets/NGUI/Examples/Scripts/Other/LoadLevelOnClick.cs(15,37): 
warning CS0618: `UnityEngine.Application.LoadLevel(string)' is obsolete: 
`Use SceneManager.LoadScene'

cs



Application.LoadLevel 로 씬 이동 하던 것을 SceneManager.LoadScene 으로 사용하란다.


그래서 유니티의 바람대로 SceneManager.LoadScene 으로 고쳐썼더니 네임스페이스가 없다고 한다....


검색해보니 UnityEngine.SceneManagement 라는 네임 스페이스가 추가된 듯.. 



1
using UnityEngine.SceneManagement;
cs


위와 같이 네임스페이스를 추가하니 정상적으로 작동한다.




알고보니 유니티 5.3에서 멀티 씬 편집(Multi-Scene Editing) 을 지원한다고 한다.


아래와 같이 프로젝트 뷰 에서 오른쪽 클릭을 한 후, Open Scene Additive 를 클릭하면...



▼ 이렇게 하이라키 뷰에 여러 씬이 열린다.





또한 SceneManager 추가되었고, 덕분에 자주쓰는 메소드들도 거의 다 구식이 되어버렸다.


변경점은 다음과 같다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// old
Application.LoadLevel(0);                                       // 로드. 
Application.LoadLevel("SceneName");
AsyncOperation ao = Application.LoadLevelAsync(0);              // 로드. (비동기)
AsyncOperation ao = Application.LoadLevelAsync("SceneName");
Application.LoadLevelAdditive(0);                               // 씬 병합 추가. 
Application.LoadLevelAdditive("SceneName");
Application.LoadLevelAdditiveAsync(0);                          // 씬 병합 추가. (비동기)
Application.LoadLevelAdditiveAsync("SceneName");
Application.UnloadLevel(0);                                     // 언로드. 
Application.UnloadLevel("SceneName");
Application.levelCount;                                // BuildSetting 에 등록 된 씬 개수. 
Application.loadedLevel;                                        // 현재 씬 인덱스. 
Application.loadedLevelName;                                    // 현재 씬 이름. 
 
// 5.3
SceneManager.LoadScene(0);                                      // 로드. 
SceneManager.LoadScene("SceneName");
AsyncOperation ao = SceneManager.LoadSceneAsync(0);             // 로드. (비동기)
AsyncOperation ao = SceneManager.LoadSceneAsync("SceneName");
SceneManager.LoadScene(0, LoadSceneMode.Additive);              // 씬 병합 추가. 
SceneManager.LoadScene("SceneName", LoadSceneMode.Additive);
SceneManager.LoadSceneAsync(0, LoadSceneMode.Additive);         // 씬 병합 추가. (비동기)
SceneManager.LoadSceneAsync("SceneName", LoadSceneMode.Additive);
SceneManager.UnloadScene(0);                                    // 언로드. 
SceneManager.UnloadScene("SceneName");
SceneManager.sceneCount;                                        // 현재 로드 된 씬 개수. 
SceneManager.sceneCountInBuildSettings;                // BuildSetting 에 등록 된 씬 개수. 
SceneManager.GetActiveScene().buildIndex;                       // 현재 씬 인덱스. 
SceneManager.GetActiveScene().name;                             // 현재 씬 이름. 
 
// 씬 정보 조회. 
Scene activeScene = SceneManager.GetActiveScene();
Scene scene1 = SceneManager.GetSceneAt(0);
Scene scene2 = SceneManager.GetSceneByName("SceneName");
Scene scene3 = SceneManager.GetSceneByPath("Assets/SceneName.unity");
Scene[] loadedScenes = SceneManager.GetAllScenes();
 
// Scene 구조체. 
int buildIndex;
string name;
string path;
bool isLoaded;
bool isDirty;       // 씬을 변경(수정)했는지 여부. 
int rootCount;      // 씬의 Root에 있는 GameObject 개수. 
bool IsValid();     // 유효한 씬인지 여부. 
 
// 기타. 
Scene scene = gameObject.scene;                 // 게임오브젝트가 속해있는 씬을 가져오기. 
GameObject go = new GameObject("New Object");   // 게임오브젝트를 생성하면 현재 씬에 추가 됨. 
SceneManager.MoveGameObjectToScene(go, scene);      // 게임오브젝트를 다른 씬으로 이동. 
SceneManager.MergeScenes(sourceScene, destinationScene);    // 씬을 병합. 
 
// SceneManager.Get~() 으로 가져올 수 있는 것은 로드가 끝난 씬만 가능. 
Scene scene = SceneManager.GetSceneByName("SceneName");
bool isValid = scene.IsValid();     // false 가 리턴 됨.
cs



정리하다보니 꽤 많네;;;


아, 그리고 DontDestroyOnLoad 메소드 비스므리 한 것은 아예 없었는데,


Tips 를 참조해 보면, DontDestroyOnLoad 의 사용은 피하는 것이 좋고, Manager 씬을 만들어서 병합하는 것이 좋다고 한다.


앞으로 개발 시 참고해야 할 사항인 것 같다.



PS. Unity 5.3 에서는 과금 플러그인을 이용할 필요가 없을 수도 있겠다.


Unity Service Tab 에서 여러가지를(Unity Ads, Analytics, Cloud Build, In-App Purchasing, Multiplayer) 지원함..






출처 : http://worksp.tistory.com/10

반응형
Posted by blueasa
, |

[파일]


Albatross-Programming-Unity-Unity로 다수의 인원이 개발할 때 알아두면 좋은 9가지.pdf


반응형
Posted by blueasa
, |


[파일]


인게임_광고의_올바른_방법(UnityAds).pdf


반응형
Posted by blueasa
, |

이전에 Coroutine을 사용했을때는 그냥 사용했는데.. 어디에 제대로 사용하는 것이 맞는것일까? 고민도 하구..
unityStudy 사이트에 너무 잘 설명해 놓은 글이 있어서 차라리 그 글을 한번 정독하면 큰 도움이 될것입니다
.

URL : 
[스크립팅] 코루틴(Coroutine) 기본 개념  활용 
두번째 해당 사이트는 영문입니다. : http://unitygems.com/coroutines/

아래는 백과사전 및 위 사이트에 대한 부분을 이해하기 위해 정리했습니다.

 

1.    동시 실행(협동) 루틴이라 불리 우는 Coroutine 정의

A.     호출 루틴과 피호출 루팅이 대등 관계를 유지하는 처리 절차.
부차적 프로그램의 수행이 완전히 끝나기 전에 제어가 호출 루틴으로 돌아가는 것이 동시 실행 과정이다. 그리고 제어가 부차적 프로그램으로 돌아 왔을 때는 중단된 부분부터 다시 수행이 계속 된다. 주종 관계를 갖지 않고 서로 호출하는 둘 이상의 모듈들.서브루틴의 제어 전달 개념과 유사한것. 각 호출에서 초기화되는 서브루틴과는 달리, 호출 시 관련된 모든 정보를 보존하는 능력을 갖는다. 그리고 다음에 다시 시작할 때에는 이전에 실행했던 다음부터 실행 할 수 있는 논리를 갖는다.

B.     프로그램에서 순서는 일반적으로 불려지는 쪽이 부르는 쪽에 속하고 있는 것이 대부분이지만 어느 쪽도 종속 관계가 아니라 대등한 관계로 서로 호출하는 것이다.
예를 들면, 게임 프로그램에서 각 플레이어 루틴은 서로 Coroutine 된다. 복수 프로세스 간에서 한정된 형태의 통신을 행하는 프로그램을 순차 제어로 실현한 것으로 볼 수 있다.

C.     C언어 등에서 일반적으로 사용하는 함수는 시작할 때 진입하는 지점이 하나 존재하고 함수가 모두 실행되거나,  return 구문에 의해서 종료되는 지점을 설정 할 수 있다.
이러한 함수를 서브 루틴(subroutine)이라 부르는데, 코루틴은 이를 더 일반화한 개념으로 진입하는 지점까지 여러 개를 가질 수 있는 함수를 의미. (서브 루틴도 코루틴의 한 종류)

D.     Coroutine 은 프로그램 상에서 보면 멀티 쓰레드와 비슷한 개념이다.
별도의 스택과 지역변수들을 가진 실행 중, 각자의 메모리 영역과 실행 명령 포인터를 가지고 있어
,
재개(Resume)와 양보(yield)가 가능한 구조로 되어 있다
.
중지(yield)하면 실제 프로그램(함수)는 종료되지 않고 위치를 대기시킨 후 값이 만들어지는 시점부터 다시 시작(resume) 할수 있다는 말이다.

 

2.    왜 필요한 것인가?

유니티에서 코루틴과 상호 작용하는 주체는 엔진이다
.
코루틴을 사용 할 때는 C#의 언어적인 기능을 익혀서 모든 것을 해결한다는 개념보다 스크립트에서 엔진이 가지는 기능을 활용하는 또 한가지의 관점으로 접근해야 한다
.
스크립트에서 StartCoroutine 함수를 통해 코루틴을 구동하면 코루틴은 첫 번째 데이터를 엔진에 전달하고 이 데이터를 분석한 엔진은 내부 루푸를 돌면서 필요한 때가 되면 다음 데이터를 전달하도록 코루틴을 다시 호출해 준다. 이때 엔진에 전달할 데이터가 정말 중요한데, 데이터들은 코루틴이 유니티 엔진에게 보내는 일종의 명령으로 생각하면 좋다
.



 

3.    자주 등장하는 조연 배우들…

A.     Yield 
Coroutine 
은 Yield 를 사용하여 중간에 제어권을 다른 함수에 넘겨주는 역할을 한다.
yield 를 사용하여 일정시간 대기 할 수 있는 함수도 있다
.
yield return new WaitForSecond(3.0f); 
3초  대기 후에 리턴을 해주는 순서다.  여기서 기본적인 추가 특징으로 update 함수상에서는 yield 문의 직접적인 사용이 금지가 됩니다.

B.     IEnumerator
(msdn) 
제네릭이 아닌 컬렉션을 단순하게 반복할 수 있도록 지원하는 인터페이스
우리말로 열거자 라고 하는데 , 데이터의 목록을 하나씩 넘겨 줄 때 사용되는 인터페이스 이다.
코루틴은 호출한 함수와 서로 상호작용하면서 진행하도록 설계되어 있습니다
.
코루틴은 자신을 호출한 함수에 데이터를 하나 넘겨주고 쉰다
.
받은 측에서는 데이터를 받고 나서 처리한 후에 코루틴에게 다음 데이터를 달라고 깨운다
.
쉬고 있던 코루틴은 일어나서 다시 데이터를 전달하고 .. 이를 계속 반복하는 구조로 동작한다
.
이런 작업에 적절한 인터페이스가 IEnumerator이며, C# 에서 코루틴을 사용할 때는 이를 사용한다
.
일반적으로 호출한 함수에게 데이터를 전달 할때, return 구문을 사용하게 되면 데이터를 전달하고 함수는 종료 된다.

C.     StartCoroutine 함수
IEnumerator 반환형을 받아 yield 이 만날 때 함수를 일시 정지하고, 다른 스크립트나 함수에게 활동을 넘긴다. 다시 말해 코루틴 함수를 구동하는 함수다.



 

4.    엔진이 제공하는 데이터들과 이를 수행하는 명령들.

A.     Yield return null : 다음 프레임까지 대기

B.     Yield return new WaitForSeconds(flat) : 지정된 초(float) 만큼 대기

C.     Yield return new WaitForFixedUpdate() : 다음 물리 프레임까지 대기

D.     Yield return new WaitForEndOfFrame() : 모든 렌더링 작업이 끝날 때 까지 대기

E.     Yield return StartCoroutine(string) : 다른 코루틴이 끝날 때 까지 대기

F.      Yield return new WWW(string) : 웹 통신 작업이 끝날 때까지 대기

G.     Yield return new AsyncOperation : 비동기 작업이 끝날 때 까지 대기 (씬로딩)

•null - the coroutine executes the next time that it is eligible

•WaitForEndOfFrame - the coroutine executes on the frame, after all of the rendering and GUI is complete

•WaitForFixedUpdate - causes this coroutine to execute at the next physics step, after all physics is calculated

•WaitForSeconds - causes the coroutine not to execute for a given game time period

•WWW - waits for a web request to complete (resumes as if WaitForSeconds or null)

•Another coroutine - in which case the new coroutine will run to completion before the yielder is resumed

 


 

 

 

5.    Coroutine 의 장점

A.     성능
yield return new WaitForSecond(3.0f); 
이라는 명령을 수행하면, 코루틴은 유니티 엔진에게 WaitForSeconds(3.0f) 라는 데이터를 보내고 쉬기 시작합니다.
코루틴이 없이 일반적으로 이를 구현한다면, Update 문에서 Time.deltaTime 을 사용하여 매 프레임마다 시간을 더해서 10초가 지났는지 감지해야 하는데, 프레임의 평균 소요 시간이 0.01초 라고 한다면 아이러니하게 10초 동안 대기 하기 위해 스크립트는Update 함수를 1000번 호출해야 합니다
.
특히 모바일 기기에서 코루틴의 활용은 성능 향상에 큰 영향을 미친다
.

B.     가독성
코루틴을 사용하면 읽기 좋은 코드가 만들어 진다. 같은 결과물을 나타내는 두개의 코드로 비교하면

//update 상에서 코루틴을 사용하지 않고 직접 구현시

public class UpdateTimer : MonoBehaviour {
    float accumulator = 0.0f;
    bool wait1Finished = false;
    bool wait2Finished = false;
    float waitTime1 = 1.0f;
    float waitTime2 = 2.0f;

    void Start() {
        Debug.Log ("Action Start!");
    }
    void Update () {
        accumulator += Time.deltaTime;
        if(!wait1Finished && !wait2Finished) {
            if(accumulator >= waitTime1) {
                Debug.Log ("Action1 End");
                wait1Finished = true;
                accumulator = 0.0f;  
            }
        } else if(wait1Finished) {
            if(accumulator >= waitTime2) {
                Debug.Log ("Action2 End");
                wait2Finished = true;
                accumulator = 0.0f;  
            }
        }
    }
}

//Start 
함수를 IEnumerator 로 선언시. (엔진이 자동으로 코루틴으로 실행해줌.
public class CoRoutineTimer : MonoBehaviour {
    float waitTime1 = 1.0f;
    float waitTime2 = 2.0f;   

    IEnumerator Start () {
        Debug.Log ("Action Start");
        yield return new WaitForSeconds(waitTime1);
        Debug.Log ("Action1 End");
        yield return new WaitForSeconds(waitTime2);
        Debug.Log ("Action2 End");
    }     
}

 

6.    특징 및 활용

A.     가장 많이 사용되는 건 WaitForSeconds 명령

멀티 쓰레드 프로그래밍의 Thread.Sleep 함수 처럼 원하는 시간 만큼 잘수 있다. 하지만 더욱 좋은 점은 엔진과 동일한 싱글 쓰레드로 돌아가기 때문에, 멀티 쓰레드 프로그래밍의 어려운 부분인 자원 관리 및 컨텍스트 스위칭(Context Switching)과 같은 다양한 고려 사항의 필요가 없음.

B.     두번째로 많인 사용하는 부분은 비동기 작업

웹에서의 데이터 수신, 씬 로딩과 같이 오래 걸리는 작업은 엔진에게 넘기고, 자신은 진행상황을 점검하면서 UI 처리만 수행하는 형태로 사용합니다.
아래와 같이 WWW 클래스가 대표적인 비동기 작업인데, 웹에서 데이터를 다운로드 받기 위해 스크립트는 엔진에게 www 클래스를 만들어 데이터를 받아올 URL과 함께 넘기고 자신은 쉰다
.
이를 받은 엔진은 비동기 처리를 위한 쓰레드를 생성하고, 네이티브 라이브러리를 사용하여 웹에 접속한  후 데이터를 다운로드 하면서 스크립트로부터 넘겨 받은 www 객체에 직장 상사에게 보고하듯 현재 진행상황을 저장해 둔다.(이 때 클래스의 레퍼런스를 넘겼기 때문에 다른 스크립트에서 진행상황을 읽어 들이는 것이 가능함
.)
엔진에서 다운로드가 끝나면 www 객체에는 완료 상황보고와 함께 받은 데이터가 저장되며, 엔진은 스크립트를 깨운다. 스크립트에서는 바로 그 떄부터 그것을 가지고 사용한다
.

//코루틴이 쉬는 동안 엔진은 열심히 다운로드 받고, Update 함수는 이를 보면서 열심히 진행상황을 로그에 남기는 예제임
.
public class WebBasic : MonoBehaviour {
    public string url;
    WWW www;
    bool isDownloading = false;

    IEnumerator Start()
    {
        www = new WWW(url);
        isDownloading = true;
        yield return www;
        isDownloading = false;
        Debug.Log ("Download Completed!");
    }

    void Update()
    {
        if(isDownloading)
            Debug.Log (www.progress); 
    }
}

//update 에서 이런 처리 부담스러워…프로그래스 바를 넣는식으로 변경하는 방법으로
..
public class WebAdvanced : MonoBehaviour {
    public string url;
    WWW www;

    IEnumerator Start()
    {
       www = new WWW(url);
       StartCoroutine("CheckProgress");
       yield return www;
       Debug.Log ("Download Completed!");
    }

    IEnumerator CheckProgress()
    {
        Debug.Log (www.progress);
        while(!www.isDone)
        {
            yield return new WaitForSeconds(0.5f);
            Debug.Log (www.progress);
        }
    }
}

C.     마지막으로 코루틴을 사용하여 작업을 원하는 대로 순차적으로 수행 할수 있다.

C#과 같은 고급 언어(High Level Language) 에서 지원하는 리플렉션(Reflection) 기능과 코루틴 기능이 혼합된 활용성에 있어서 백미라고 할수 있다
.
이의 활용 예를 위해 RPG 게임등에서 흔히 보이는 패턴인 A 와 B 중 하나를 선택하게 하는 다이얼로그를 띄운 후 , 사용자의 결정에 따라 A 를 선택하면 ActionA 를 수행하고  B 를 선택하면 ActionB를 수행하는 구문을 프로그래밍 할 때 이를 코루틴으로 구현하기 위해, 먼저 모든 행동을 코루틴으로 정의해 준다
.
그리고 각 행동들의 순서를 제어하는 코루틴을 만들어주고, 코루틴 안에서 행동들이 순차적으로 실행되도록 yield return new StartCoroutine 구문으로 차례대로 지정해 준다
.
첫번째 코루틴의 결과에 따라 다음 행동이 A 가 될지 B 가 될지 결정되므로, 첫 번째 결과 값을 string 변수로 지정하고, 변수 값을 StartCoroutine 에 넣으면 실시간으로 결과에 따른 해당 코루틴이 실시간으로 실행 된다. 아래는 실 구현 예제 


public class DialogExample : MonoBehaviour {
    bool showDialog = false;
    string answer = "";

    IEnumerator Start()
    {
        yield return StartCoroutine("ShowDialog");
        yield return StartCoroutine(answer);
    }

    IEnumerator ShowDialog()
    {
        showDialog = true;
        do
        {
            yield return null;
        } while(answer == "");
        showDialog = false;
    }

    IEnumerator ActionA()
    {
        Debug.Log ("Action A");
        yield return new WaitForSeconds(1f);
    }

    IEnumerator ActionB()
    {
        Debug.Log ("Action B");
        yield return new WaitForSeconds(2f);
    }
    void OnGUI()
    {
        if(showDialog)
        {
            if(GUI.Button(new Rect(10f, 10f, 100f, 20f), "A"))
            {
                answer = "ActionA";   
            } else if(GUI.Button(new Rect(10f, 50f, 100f, 20f), "B")) {
                answer = "ActionB";
            }
        }
    }
}

//
결과 값의 유효성을 강화하고 싶다면 아래와 같이 enum 를 보조적으로 사용하는 것도 좋은 방법이 될수 있다.

using UnityEngine;
using System.Collections;

public class DialogExampleEnum : MonoBehaviour {
    enum DialogActions {
        ShowDialog,
        ActionA,
        ActionB
    };

    bool showDialog = false;
    DialogActions action = DialogActions.ShowDialog;
    IEnumerator Start()
    {
        yield return StartCoroutine(action.ToString());
        yield return StartCoroutine(action.ToString());
    }

    IEnumerator ShowDialog()
    {
        showDialog = true;
        do
        {
            yield return null;
        } while(action == DialogActions.ShowDialog);
        showDialog = false;
    }
    IEnumerator ActionA()
    {
        Debug.Log ("Action A");
        yield return new WaitForSeconds(1f);
    }
    IEnumerator ActionB()
    {
        Debug.Log ("Action B");
        yield return new WaitForSeconds(2f);
    }
    void OnGUI()
    {
        if(showDialog)
        {
            if(GUI.Button(new Rect(10f, 10f, 100f, 20f), "A"))
            {
                action = DialogActions.ActionA;         
            } else if(GUI.Button(new Rect(10f, 50f, 100f, 20f), "B")) {
                action = DialogActions.ActionB;
            }
        }
    }
}
이러한 특징을 잘 홀용하면 AI 를 위한 유한상태 기계(Finite State Machine) 을 구현할 때에도 별도의 클래스를 만들지 않고 쉽게 코딩이 가능해 진다
.

D.     Coroutine 는 for 루프 내에서는 사용할 수 없지만, while 문이나 foreach 문에서는 사용이 가능하다.
IEnumerator Foo()
{
 while(someCondition)
 { 
   // 여기서 시간이 오래 걸리는 처리를 수행한다
.
   // 다음 프레임 전에 일시 정지
.
 }
}


*Tip : 이전부터 Debug.Log 을 사용하는 것을 꺼려 했다. 실제 빌드 후에 자동으로 사라지는 것이 아니기 때문에,
이 함수를 별도로 따로 빼서 클래스를 생성해서, 그 클래스를 직접 사용하는 편이 가장 좋다
.
http://answers.unity3d.com/questions/126315/debuglog-in-build.html

public static void Log (String method)
  {
       Debug.Log (method);
    }



[출처] http://kimseunghyun76.tistory.com/304

반응형
Posted by blueasa
, |

[펌] TexturePacker

Unity3D/Plugins / 2016. 5. 10. 12:32

[링크] https://www.codeandweb.com/texturepacker



[링크] Quickstart Guide with TexturePacker and Unity





Tutorials for Unity:
Sprite Sheets &
Normal Mapped Sprites

We currently have 2 detailed tutorials for Unity,
scroll down for our Quickstart Guide.











Quickstart Guide with TexturePacker and Unity

This overview shows you how to create your first sprite sheet and import it into your unity project.

These 6 steps will cost you only 5 minutes - but make your development much easier. Promised!

1.
Open TexturePacker, select
Unity - Texture2D sprite sheet
as framework.

TexturePacker: Select Unity Texture2D as framework

2.
Add sprites ...

Drag & drop sprites
onto TexturePacker.


... or folders

TexturePacker adds
all sprites inside the folder
and updates the texture
when the content changes.

Add Sprites to TexturePacker


3.
Set output files
Make sure to set the output path of both files inside the Assets folder of your Unity project.



Set the output path for your files


4.
Optional: Set Trim mode and Pivot Point.

Crop removes transparency from sprites, allowing a better packing ratio.




5.

Click Publish sprite sheet to write the sprite sheet to your Unity project




6.

Download and install our free
TexturePacker Importer
TexturePacker Importer
Free download from Unity Asset Store 

The sprite sheet is updated after each publish.




TexturePacker allows you to set a Pivot Point and Trim your sprite





TexturePacker: Click Publish sprite sheet







Your files will be imported automatically when using TexturePacker Importer





반응형
Posted by blueasa
, |

[파일]

BitmapFontImporter.unitypackage

BitmapFontImporter설명서.pptx



안녕하세요. NHN스타피쉬 TD 최윤빈 입니다.

Unity 엔진을 이용한 게임 개발 시 기존에는 NGUI를 주로 사용하셨을텐데
4.5 버전 이상부터 uGUI 라는 Unity 내장 GUI가 새로 나오면서
uGUI로 많이 갈아타고 계신걸로 알고 있습니다.

2015년 3월부터 개발중인 게임을 NGUI -> uGUI로 포팅작업을 시작하였고
그 과정에서 기존 NGUI에서 사용하던 방식대로 Bitmap font를 사용할 수 없어서 고민하다가
구글님의 도움을 받아 기존 NGUI와 유사하게 Bitmap font를 사용할 수 있도록
Custom font를 생성해주는 스크립트를 제작하였기에 공유코자 합니다.

또한 NGUI 에서는 Bitmap font를 Atlas에 묶어서 사용할 수 있었는데
uGUI 에서는 Atlas 기능이 없기때문에 직접 multiple sprite 로 묶어서 사용해야 합니다.
저희 팀에서는 TexturePacker를 사용하고 있는데요.
Bitmap font 들 또한 기존 처럼 묶어서 사용해야하기에
이를 지원하기 위한 기능도 포함 되어 있습니다. (Draw call 은 소중하니까요..)

요컨데, BitmapFontImporter 는

  • Bitmap font 제작 툴로 만든 png, txt 파일로부터 font 및 material 파일을 생성
  • Multiple sprite 지원

다음과 같은 기능을 제공합니다. 사용법은 첨부된 파일을 참고부탁드립니다.

클릭 두세번으로 손쉽게 비트맵 폰트 만드세요~





출처 : http://meetup.toast.com/posts/40

반응형
Posted by blueasa
, |

Unity에서 장치의 고유한 식별 번호를 얻고 싶은데...

아이폰으로는 테스트를 못해 봤습니다만... 잘 되지 않을까 싶네요.

안드로이드에서 장치의 식별자로 쓸만한 것이 3개 있는데

  1. Settings.Secure 의 ANDROID_ID
  2. WiFi의 MAC 주소
  3. 전화 모듈의 식별자

입니다.
아래 코드에서는 위 순서대로 가져오기를 시도해서 잘 가져오는 것을 반환하게 했습니다.

당연히... 별다른 이상한 오류 상황이 아니면 ANDROID_ID를 가져 오겠지요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public string GetDeviceID ()
{
    if (Application.platform == RuntimePlatform.Android)
    {
        try
        {
            using (AndroidJavaObject activity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject> ("currentActivity"))
            {
                // ANDROID_ID
                try
                {
                    using (AndroidJavaObject resolver = activity.Call<AndroidJavaObject> ("getContentResolver"))
                    {
                        using (AndroidJavaObject settingsSecure = new AndroidJavaObject ("android.provider.Settings.Secure"))
                        {
                            string deviceID = settingsSecure.CallStatic<string> ("getString", resolver, settingsSecure.GetStatic<string> ("ANDROID_ID"));
                            if (!string.IsNullOrEmpty (deviceID))
                            {
                                return deviceID;
                            }
                        }
                    }
                }
                catch (System.Exception)
                {
                }
 
                // WiFi MAC
                try
                {
                    using (AndroidJavaObject wifiManager = activity.Call<AndroidJavaObject> ("getSystemService", activity.GetStatic<string>("WIFI_SERVICE")))
                    {
                        string macAddr = wifiManager.Call<AndroidJavaObject> ("getConnectionInfo").Call<string> ("getMacAddress");
                        if (!string.IsNullOrEmpty (macAddr))
                        {
                            return macAddr;
                        }
                    }
                }
                catch (System.Exception)
                {
                }
                 
                // IMEI/MEID code
                try
                {
                    using (AndroidJavaObject telephonyManager = activity.Call<AndroidJavaObject> ("getSystemService", activity.GetStatic<string>("TELEPHONY_SERVICE")))
                    {
                        string imeiCode = telephonyManager.Call<string> ("getDeviceId");
                        if (!string.IsNullOrEmpty (imeiCode))
                        {
                            return imeiCode;
                        }
                    }
                }
                catch (System.Exception)
                {
                }
 
            }
        }
        catch (System.Exception)
        {
        }
    }
    else
    {
        // 이 방법은 안드로이드에서는 안된다. - Unity 4.3.4f1
        try
        {
            var nics = NetworkInterface.GetAllNetworkInterfaces ();
            if (nics.Length > 0)
            {
                return nics[0].GetPhysicalAddress ().ToString ();
            }
        }
        catch (System.Exception)
        {
        }
    }
    return "";
}

WiFi MAC 주소를 가져오려면 ACCESS_WIFI_STATE 권한이 필요합니다.

IMEI code 를 가져오려면 READ_PHONE_STATE 권한이 필요합니다.

그럼 이 권한은 어떻게 설정할까요?
만약 프로젝트 경로 아래에
Assets/Plugins/Android/AndroidManifest.xml 파일이 있다면 해당 파일을 수정하시면 됩니다.
이 파일이 없으시다면
(Unity 설치 경로)/Editor/Data/PlaybackEngines 폴더 밑에 있는
androidplayer 또는 androiddevelopmentplayer 폴더에 있는 파일을 복사해서 사용하시면 됩니다.

아래 내용을 추가하시면 되겠죠?

1
2
3
4
5
6
7
8
<uses-permission
    android:name="android.permission.READ_PHONE_STATE"
    >
</uses-permission>
<uses-permission
    android:name="android.permission.ACCESS_WIFI_STATE"
    >
</uses-permission>



출처 : http://bspfp.pe.kr/536

반응형
Posted by blueasa
, |

유니티 애즈(Unity Ads)를 이용하여, 광고를 시청하면 골드를 보상받는 예제를 포스팅합니다.


 구현하고자 하는 기능은 다음과 같습니다.

* 구현 기능

 - 버튼 클릭 -> 유니티 애즈 시청 -> 골드 보상




 다음은 작업의 전체 순서입니다.

#1. 유니티 애드 설정 (Web 작업)

#2. 유니티 프로젝트 적용 및 테스트 (Unity3D, 디바이스 작업)



#1. 유니티 애드 설정 


1. https://unityads.unity3d.com에 로그인 합니다.


2. 게임탭에서 '+새 게임 추가'를 클릭합니다.


3.플랫폼을 선택(안드로이드)하고, '여기'를 클릭합니다. 출시전이므로 어플리케이션 찾기를 건너뜁니다.


4. 이름을 입력하고, '게임 추가'버튼을 클릭합니다. 정보 인증 설정후 '계속'을 클릭합니다.


5. 게임탭에 새 게임이 추가되었습니다. 게임 ID는 본문 뒷부분에서 코드(UIManager.cs)에 사용합니다. 

 게임 이름(UnityAdsTest)을 클릭합니다.


6. '수익화 설정'탭에서, '고급 설정 보기'를 클릭합니다.


7. Video ad placement의 '설정'을 클릭합니다.


8. 옵션을 설정합니다. 강제 시청을 위해 '동영상 건너 뛰기 허용' 항목의 체크를 제거하고, '저장'을 클릭하여 완료합니다.




#2. Unity 프로젝트 적용 및 테스트


1. Unity3D 새 프로젝트를 생성합니다. 타이틀은 UnityAdsTest로 하였습니다.


2. Unity Ads 패키지를 임포트합니다. 유니티 애셋 스토어에서 다운받을 수 있습니다. (https://www.assetstore.unity3d.com/en/#!/content/21027)


3. Canvas및 버튼(BtnUnityAds)을 생성합니다. 각 설정은 임의로 합니다.


4. C# 스크립트, UIManager.cs를 생성하고 다음의 코드로 대체합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using UnityEngine;
using System.Collections;
 
using UnityEngine.UI;
using UnityEngine.Advertisements;
 
public class UIManager : MonoBehaviour {
 
    public Button _BtnUnityAds;
    ShowOptions _ShowOpt = new ShowOptions();
    int _Gold = 0;
 
    void Awake()
    {
        Advertisement.Initialize("63660"true);
        _ShowOpt.resultCallback = OnAdsShowResultCallBack;
        UpdateButton();
    }
 
    void OnAdsShowResultCallBack(ShowResult result)
    {
        if (result == ShowResult.Finished) _Gold += 100;
    }
 
    void UpdateButton()
    {
        _BtnUnityAds.interactable = Advertisement.IsReady();
        _BtnUnityAds.GetComponentInChildren<Text>().text 
            = "See ads and earn gold\r\nGold = " + _Gold.ToString();
    }
 
    public void OnBtnUnityAds()
    {
        Advertisement.Show(null, _ShowOpt);
    }    
 
    void Update() { UpdateButton(); }
}
 
cs

- 15: Advertisement.Initialize( "게임ID", 테스트광고 여부 )

게임ID는 유니티 애드 사이트에서 얻을 수 있습니다.

: 출시전 테스트를 위해서 테스트 광고 여부 인자를 true로 합니다. 

> true: 테스트용 광고가 나옵니다.

> false: 실제 광고가 나옵니다.


- 20: OnAdsShowResultCallBack( ShowResult result )

: 광고 보기후 호출되는 콜백입니다. result인자의 값에 따라 처리합니다.


- 27: _BtnUnityAds.interactable = Advertisement.IsReady()

Advertisement.IsReady()는 광고가 보여줄 수 있는 상태인지를 반환하는 함수입니다. 보여줄 수 없다면 버튼을 비활성화 시킵니다.


5. UIManager를 Canvas의 컴포넌트로 삽입합니다.


6. Canvas의 인스펙터창에서 UIManager: Btn Unity Ads의 인자로 BtnUnityAds오브젝트를 지정합니다.


7. BtnUnityAds의 OnClick 이벤트를 지정합니다. 오브젝트는 Canvas로, 함수는 UIManager:OnBtnUnityAds로 합니다.


8. 안드로이드 플레이어 설정을 마친후 빌드하여 테스트합니다.

    : 실행하면 버튼이 잠시후 활성화됩니다. ( Advertisement.IsReady() )


: 버튼을 클릭하면 보여지는 테스트용 광고


: 광고 종료후 Gold가 100으로 되었습니다.



출처 : http://gnupart.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%95%A0%EB%93%9CUnity-Ads-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%A0%81%EC%9A%A9

반응형
Posted by blueasa
, |
 

在Unity3D的Legacy动画系统中应用Root Motion

标签: unity3d动画Root Motion
 5591人阅读 评论(2) 收藏 举报
 分类:
 

目录(?)[+]

最近仔细比较了Unity3D目前版本中的两套动画系统:Legacy和Mecanim。Mecanim系统功能较之Legacy要强大很多,但是使用AnimatorController着实不方便(尽管使用AnimatorOverrideController可以避免重复编辑状态机),是因为游戏逻辑层面往往要用一个状态机或者类似的机制来控制角色的状态,而角色层面的状态逻辑和动画层面是无法一一对应的,两套复杂的状态机要配合起来。。。想想就觉得蛋疼啊!难怪很多朋友现在还在使用Legacy动画系统。Legacy动画系统其实功能也很全面了,包括Layer、过渡混合、上下身混合之类的功能完全能够胜任,而且控制起来就直接的多了。唯独Root Motion这个我很需要特性没有支持,本文就探讨一下如何在Legacy动画系统之上附加Root Motion功能,其实很简单大笑

何谓Root Motion

在不使用Root Motion的情况下,类似走、跑这样的位移控制是这样的:
  1. 请美术在导出动画时把位移去掉;
  2. 在程序代码里控制角色移动的速度,在播放动画的同时,计算其位移。
这种做法其实挺不科学的,程序控制的角色,只能当做一个质点来处理,并且大多数时候都是匀速运动,而动画中的角色的移动往往很难跟这个匹配。所以需要比较良好的计算和比较好的美术技巧才能避免角色“滑步”的现象。在“跑”这种快速移动这,滑步还比较好处理,如果是慢速移动。。。。再厉害的美术也爱莫能助了。这种情况下,最好还是使用Root Motion:
  1. 美术在导出动画的时候是附带位移的;
  2. 程序把动画的每一帧的位移是从动画中读取出来,再应用到角色上的,这样就能达到动画和位移的完美匹配了。

在Legacy中添加Root Motion功能

了解了Root Motion的概念之后,在Unity3D引擎中我们很简单就可以实现此功能了。Unity3D有一个统一的对象层次结构设计,这点非常赞,我们可以很简单找到角色的根骨骼,然后把其中的Transform变换读取出来,请见以下示例代码:
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //-- 计算当前帧的Root Motion  
  2.             Vector3 rootPos = m_rootBone.localPosition;  
  3.             m_rootMotion = rootPos - m_lastRootPos;  
  4.             m_lastRootPos = rootPos;  
  5.             rootPos.x = 0;  
  6.             rootPos.z = 0;  
  7.             m_rootMotion.y = 0;  
  8.             m_rootBone.localPosition = rootPos;  
请注意,我们在后续的代码中要把m_rootMotion附加的角色对象上,所以m_rootBone的postion被reset了。
在读取了此帧的Root Motion,在可以把它应用到当前对象之上了:
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //-- Apply Root Motion  
  2.     Vector3 nextPos = this.transform.position + m_rootMotion;  
  3.         this.transform.position = nextPos;  
另外,一个细节需要处理一下,在动画循环的那一帧,需要特殊处理一下。好的,看一下完整的源代码吧:
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class ApplyRootMotion : MonoBehaviour   
  5. {  
  6.     public Transform m_flagObject;  // 用来测试位置的一个对象  
  7.   
  8.     //-- Root Motion 控制变量  
  9.     Transform m_rootBone;  
  10.     Vector3 m_lastRootPos;  
  11.     Vector3 m_rootMotion;  
  12.     int m_lastAnimTime;  
  13.   
  14.     void Start ()   
  15.     {  
  16.         //-- 从SkinnedMeshRenderer中读取Root Bone  
  17.         SkinnedMeshRenderer skinMesh = this.gameObject.GetComponentInChildren<SkinnedMeshRenderer>();  
  18.         m_rootBone = skinMesh.rootBone;  
  19.   
  20.         //-- 变量初始化  
  21.         m_rootMotion = Vector3.zero;  
  22.         m_lastRootPos = m_rootBone.localPosition;  
  23.         m_lastAnimTime = 0;  
  24.     }  
  25.       
  26.     void Update ()   
  27.     {  
  28.         //-- Apply Root Motion  
  29.         Vector3 nextPos = this.transform.position + m_rootMotion;  
  30.         this.transform.position = nextPos;  
  31.   
  32.         //-- 测试代码:更新测试物体的位置  
  33.         Vector3 flagPos = m_flagObject.position;  
  34.         flagPos.x = nextPos.x;  
  35.         flagPos.z = nextPos.z;  
  36.         m_flagObject.position = flagPos;  
  37.   
  38.         //-- 测试代码:更新摄像机  
  39.         Camera.main.transform.LookAt(this.transform);  
  40.     }  
  41.   
  42.     void LateUpdate()  
  43.     {  
  44.         AnimationState animState = this.animation["walking"];  
  45.   
  46.         if ((int)animState.normalizedTime > m_lastAnimTime)  
  47.         {  
  48.             //-- 动画循环处理  
  49.             m_lastRootPos = m_rootBone.localPosition;  
  50.             m_rootMotion = Vector3.zero;  
  51.         }  
  52.         else  
  53.         {  
  54.             //-- 计算当前帧的Root Motion  
  55.             Vector3 rootPos = m_rootBone.localPosition;  
  56.             m_rootMotion = rootPos - m_lastRootPos;  
  57.             m_lastRootPos = rootPos;  
  58.             rootPos.x = 0;  
  59.             rootPos.z = 0;  
  60.             m_rootMotion.y = 0;  
  61.             m_rootBone.localPosition = rootPos;  
  62.         }  
  63.         m_lastAnimTime = (int)animState.normalizedTime;  
  64.     }  
  65. }  

最后是截图。。。好吧,静态图片看不出效果,可以下载完整Demo(请使用Unity 4.6版本打开),角色移动非常平滑,毫无滑步。

请移步百度网盘:http://pan.baidu.com/s/1o6kJsIe 密码:osoc






반응형
Posted by blueasa
, |