[링크] HTML5 모바일 웹 게임?
'Programming > Html5' 카테고리의 다른 글
[링크] Phaser로 웹 게임 만들기 (0) | 2018.10.16 |
---|---|
[링크] HTML5 미니게임 개발 튜토리얼 1 (0) | 2017.03.23 |
[링크] 플래시 게임을 대체할 HTML5 게임 엔진 순위 (2) | 2017.02.22 |
[링크] Phaser로 웹 게임 만들기 (0) | 2018.10.16 |
---|---|
[링크] HTML5 미니게임 개발 튜토리얼 1 (0) | 2017.03.23 |
[링크] 플래시 게임을 대체할 HTML5 게임 엔진 순위 (2) | 2017.02.22 |
유니티에서 화면의 변화를 일으키기 위해서는 Update() 함수 내에서 작업을 하게 됩니다. 이 Update() 함수는 매 프레임을 그릴때마다 호출되며 60fps의경우라면 초당 60번의 Update() 함수 호출이 발생하게 됩니다. 하나의 프레임 안에서 어떤 작업을 한다면 이 Update() 함수에 코드를 작성하면 될 것입니다.
하지만 다수의 프레임을 오가며 어떤 작업을 수행해야 한다면 어떻게 해야 할까요? 혹은 특정 시간, 가령 3초 동안 특정 작업을 수행해야 한다면 어떻게 해야 할까요? 3초니깐 3 x 60 = 180 프레임동안 작업을 수행하도록 하면 될까요?
안타깝게도 기기의 성능이나 상황에 따라 프레임 드랍(Frame drop)이라는 상황이 발생하게 됩니다. 60fps의 게임일지라 하더라도 디바이스의 성능에 따라 그 이하로 떨어질 수 있다는 의미가 됩니다. 이렇게 되면 더더욱 3초 동안 작업을 수행한다는게 쉽지 않은 일이 됩니다.
예로 다음의 코드를 준비하였습니다. 특정 오브젝트를 페이드 아웃(Fade out) 시키는 예제 코드입니다. 이 코드를 수행하면 스프라이트의 알파값이 점점 작아져서 결국 화면에서 사라지게 됩니다.
위의 코드를 보면 매 프레임마다 스프라이트 렌더러의 알파값을 0.1씩 감소시키고 있습니다. Update() 함수가 10번 호출되면 사라지게 되겠네요. 이는 1/6 초만에 사라지게 된다는것을 의미합니다. 이것도 1/6초만에 사라질지 보장받기가 어렵습니다.
그럼 혹시, 1초에 걸쳐 (60fps가 정상적으로 보장될 경우 60 프레임에 걸쳐) 사라지게 하려면 어떻게 하면 될까요? 대충 알파값을 0.017씩 감소시키면 될까요? 프레임이 아닌 시간 단위로 특정 작업을 수행할 수 있을까요? 여기서 생각할 수 있는 수단은 Time.deltaTime 이 있습니다.
하지만 우리가 여기서 알아보고자 하는것은 델타 타임이 아닌 코루틴이므로 코루틴에 대해서 알아보도록 하겠습니다. 코루틴은 프레임과 상관없이 별도의 서브 루틴에서 원하는 작업을 원하는 시간만큼 수행하는 것이 가능합니다.
다음은 코루틴을 사용하여 1초동안 페이드 아웃을 진행하는 예제 코드입니다.
이전 코드에서는 Update() 에서 모든 작업을 처리하던것을 Start() 에서 RunFadeOut() 코루틴을 실행하는것으로 변경된 것을 볼 수 있습니다. 여기서 주목해야 하는 부분은 yield return new WaitForSeconds(0.1f); 부분입니다.
이 복잡해 보이는 코드는 0.1초 동안 잠시 멈추라는 의미를 가진 코드입니다. 이제 위의 코드를 통해서 페이드 아웃 효과는 0.1초씩 10번을 수행하며 1초동안 사라지는 모습을 보여주게 됩니다. 이 코루틴은 Update() 함수에 종속적이지 않으며 마치 별도의 쓰레드와 같이 동작을 하게 됩니다. 이와 같은 코드로 프레임율에 영향을 받지 않는 시간 기반의 서브루틴을 구동할 수 있게 되었습니다.
그렇다면 여기서 궁금증을 유발하는 부분이 몇가지 있는데요 RunFadeOut의 리턴 타입은 IEnumerator(열거자) 입니다. 또한 while 문 내부에 보면 yield(양보)라는 구문이 보이는군요. 그 뒤로 return이 따라나오는 것도 일반적인 언어에서 보기 힘든 문법입니다. 이것들이 어떤 관계를 가지고 있는지 알아보겠습니다.
우선 다음의 일반적인 C# 코드를 한번 살펴보도록 하겠습니다.
위의 Main() 함수를 실행하게 되면 다음과 같은 결과물이 출력됩니다.
조금 헷갈리지만 알고보면 어렵지 않은 코드입니다. 이 코드는 다음과 같은 순서로 동작하게 됩니다.
조금 특이하지만 함수의 반환값이 IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T> 인 경우에는 위와 같은 동작을 하게 됩니다. 함수의 동작이 비동기적으로 동작하게 되므로 파라미터에 ref나 out을 사용할 수 없다는 제약 사항이 있습니다. 위의 코드 동작 예시는 코루틴이 어떻게 동작하는지 알기위한 기본적인 코드라고 생각됩니다. 이제 다시 코루틴으로 돌아가 보겠습니다.
StartCoroutine을 직접 구현해 본다면 위와 같은 형태의 코드가 될 것 같습니다. 먼저 코루틴 함수의 포인터 역할을 하는 열거자를 받은 다음에 MoveNext()를 통해 첫번째 yield를 만날때까지 수행하고 그 결과값을 받습니다. 그리고 그 결과값에 맞는 작업을 수행해줍니다. 그리고 이것을 함수가 완료될 때까지 반복합니다.
위의 코드에서는 4번의 MoveNext()가 호출될 것이며 3번의 yield문을 만날 것입니다. 마지막 MoveNext()에서는 false가 반환될 것이므로 코루틴이 종료됩니다. 만약 함수의 실행이 완료되기 이전에 임의로 코루틴을 종료시키고 싶다면 yield break를 호출하면 됩니다. 즉시 MoveNext()에서 false가 반환되어 종료됩니다.
결론적으로 StartCoroutine은 IEnumerator를 반환하는 함수를 인자로 받으며 이 함수는 특이하게도 실행된 결과를 의미하는것이 아니라 함수 포인터와 같은 개념으로 사용이 됩니다.
이 코드를 한번 봐보겠습니다. 일반적인 함수의 개념으로 보자면 StartCoroutine에는 RunCoroutine() 함수의 결과값이 파라미터로 넘겨지게 되어있습니다. 하지만 여기서 RunCoroutine()은 단 한줄도 실행이 되지 않습니다. 함수의 포인터 역할을 하는 IEnumerator가 넘겨지게 되고 MoveNext()를 호출할 때마다 yield 문을 만날때까지 수행됩니다. 만나게 되면 MoveNext()가 true를 반환하고 함수가 끝나거나 yield break; 를 만나게 되면 false를 반환하게 됩니다. true를 반환할 경우 Current를 통해 반환된 값을 꺼내볼 수 있습니다.
일반적으로 사용할 수 있는 방법입니다. 수행하고자 하는 코루틴의 IEnumerator 열거자를 넘겨서 실행되도록 합니다. 다음과 같은 방법으로 사용이 가능합니다.
위와 같은 방법은 일반적인 방법으로 waitTime 파라미터 값을 넘길 수 있으며 코루틴이 실행되는데에 추가적인 오버헤드가 전혀 없는 방법입니다. 뿐만 아니라 Start() 함수의 반환값을 IEnumerator로 변경하여 아예 코루틴이 실행 완료될때까지 기다리도록 의존적인 방법으로 실행하는 것도 가능합니다.
위의 코드는 WaitAndPrint(waitTime) 코루틴이 실행 완료된 이후에야 Done이 출력되는 과정을 보여줍니다.
대부분의 경우는 StartCoroutine을 사용하기 위해 전자의 방법을 사용합니다. 하지만 StartCoroutine을 문자열 형태의 코루틴 함수 이름으로도 호출하는 것이 가능합니다. 이렇게 호출하면 StopCoroutine 역시 함수 이름만으로 호출하는것이 가능해 집니다.
위의 코드는 DoSomething(someParameter) 코루틴 함수를 함수 이름과 넘겨질 파라미터를 통해 호출하는 과정을 보여주고 있습니다. 그리고 1초 기다린 뒤에 실행했었던 DoSomething 코루틴을 종료시킵니다. 이러한 함수 이름을 문자열로 넘겨 실행하는 방법은 StartCoroutine을 수행하는데에 오버헤드가 크고 파라미터를 한개밖에 넘길 수 없다는 제약사항이 있습니다. 물론 배열을 넘기는것 역시 가능합니다.
위에서 본 예시에는 WaitForSeconds 클래스를 양보 반환함으로써 원하는 시간(초)만큼 기다리는 것이 가능하다는것을 알 수 있었습니다. 추가로 더 알아 보도록 하겠습니다.
WaitForSeconds와 하는 역할은 동일하지만 결정적으로 다른것이 있습니다. 유니티상의 시간은 임의로 느리게 하거나 빠르게 하는 것이 가능합니다. 이를 Time.timeScale을 통해서 조정을 할 수 있습니다. 매트릭스에서 보던 총알이 느리게 날아오면서 그것을 피하는 모션을 구현해 본다면 이 값을 1보다 낮추게 되면 현재 시간의 진행보다 느려지게 되며 1보다 빠르게 변경하면 현재의 시간의 진행보다 빨라지게 됩니다. 하지만 WaitForSecondsRealtime는 이러한 Scaled Time의 영향을 받지 않고 현실 시간 기준으로만 동작을 하게 됩니다.
다음 FixedUpdate() 가 실행될때까지 기다리게 됩니다. 이 FixedUpdate()는 Update()와 달리 일정한 시간 단위로 호출되는 Update() 함수라고 생각하시면 됩니다.
하나의 프레임워 완전히 종료될 때 호출이 됩니다. Update(), LateUpdate() 이벤트가 모두 실행되고 화면에 렌더링이 끝난 이후에 호출이 됩니다. 특수한 경우에 사용하면 될 것 같습니다만 잘 모르겠군요.
WaitForEndOfFrame를 이야기 했다면 이것을 꼭 이야기 해야 할 것 같습니다. yield return null; 을 하게 되면 다음 Update() 가 실행될때까지 기다린다는 의미를 갖게 됩니다. 좀 더 정확하게는 Update()가 먼저 실행되고 null을 양보 반환했던 코루틴이 이어서 진행 됩니다. 그 다음에 LateUpdate()가 호출됩니다.
이번엔 특정 조건식이 성공할때까지 기다리는 방법입니다. WaitUntil에 실행하고자 하는 식을 정의해 두면 매번 Update() 와 LateUpdate() 이벤트 사이에 호출해 보고 결과값이 true면 이후로 재진행을 하게 됩니다. 다음의 예제 코드를 보겠습니다.
이 코드는 Update() 함수를 통해 매 프레임마다 frame 멤버 변수값을 1씩 최대 10까지 증가시키게 됩니다. 실행중인 코루틴은 frame값이 10또는 10보다 커질때까지 기다리다가 이 식이 충족되게 되면 다음으로 진행을 하게 됩니다. 여기서 사용되는 식은 람다 표기법이 사용됩니다. 다음과 같은 느낌이라고 생각하시면 될 것 같습니다.
WaitWhile은 WaitUntil과 동일한 목적을 가지고 있지만 한가지만 다릅니다. WaitUntil은 람다식 실행 결과값이 true가 될때까지 기다린다면 WaitWhile은 false가 될때까지 기다립니다. 즉 WaitWhile은 결과가 true인 동안 계속 기다리게 됩니다.
위의 코드는 첫프레임부터 람다식의 결과가 true이게 됩니다. 10프레임에 도달하면 false가 되어서 이후 진행이 되겠네요.
이번에는 심지어 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다. 의존성 있는 여러작업을 수행하는데에 유리하게 사용 될 수 있습니다.
위와 같은 코드를 실행해 본다면 결과는 다음과 같이 출력됩니다.
이 방법은 기존에 StartCoroutine을 실행할 때 넘겨주었던 코루틴 함수의 열거자를 파라미터로 사용하여 그것을 중단시키는 방법입니다. 다음과 같은 사용이 가능합니다.
Start() 함수에서 WaitAndPrint(waitTime) 코루틴 함수의 열거자를 획득하여 클래스의 멤버 변수로 설정해 두고 이 코루틴을 실행합니다. 이 코루틴은 1초에 한번씩 WaitAndPrint 를 출력하게 되며 유저가 스페이스키를 누르게 되면 멤버 변수에 담겨 있는 기존 코루틴의 열거자를 이용하여 실행중인 코루틴을 중단시킵니다.
이 방법은 이전 방식보다 오버헤드는 크지만 간편하게 사용할 수 있는 방법입니다. 다음과 같이 멤버 변수 없이도 간편하게 사용할 수 있습니다.
이때에 주의할 점으로는 StopCoroutine을 문자열로 종료시키려면 StartCoroutine 역시 문자열로 실행했었어야 한다는 점입니다. StartCoroutine(IEnumerator routine) 으로 실행한 다음에 StopCoroutine(string methodName) 으로 종료시킬 수 없습니다.
마지막으로 현재 Behaviour (클래스라고 이해하면 될 것 같습니다)에서 실행한 모든 코루틴을 한번에 종료시키는 함수입니다. 이와 같은 방법으로 현재 클래스에서 실행한 모든 코루틴을 한번에 중단시키게 됩니다.
어디선가 Example()을 실행하게 되면 DoSomething 코루틴이 실행되게 되면 곧바로 StopAllCoroutines() 이 호출되어 모든 코루틴이 종료됩니다.
참고 :
http://docs.unity3d.com/kr/current/Manual/Coroutines.html
http://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
[펌] Async-Await instead of coroutines in Unity 2017 (0) | 2019.02.21 |
---|---|
[펌] 웹 페이지 상의 이미지를 읽어와 출력하기 (0) | 2018.12.21 |
[펌] StopCoroutine() 의 활용 2 - Coroutine continue failure (0) | 2018.04.13 |
Unity3D MonoBehaviour Lifecycle(흐름도) (0) | 2017.12.20 |
[펌] Unity BigInteger (0) | 2017.04.26 |
[Link]
[참조]
[링크] Gmail (지메일) 에 Youtube 동영상 바로 삽입하기 (임베딩 형태로) (0) | 2019.06.20 |
---|---|
[펌] 윈도우10 설정 ms-settings 명령어 활용하기 (0) | 2019.03.05 |
[링크][카카오 욕필터] 새버전 (0) | 2018.05.21 |
[펌] NotePad++ 에서 , -> 엔터(\n)로 변환(줄바꿈) (0) | 2018.05.17 |
[펌] 윈도우7 업데이트 0% 문제 해결 (0) | 2018.03.25 |
병합과 재정렬은 대개 한 Topic(작업 단위)의 작업이 끝난 다음, 작업 내용을 Master branch에 반영해야 할 경우 수행하는 작업입니다.
새로운 Topic에 대한 작업을 할 때는 대개 Master Branch에서 새로운 Branch를 따서 작업한 뒤, 나중에 다시 Master Branch에 합치는 순으로 작업을 진행합니다.
병합과 재정렬에 대한 이해는 GIT으로 작업하기 위해 PM 뿐만 아니라 팀원도 알고 있어야 합니다. 병합과 재정렬에 관련된 작업 흐름을 어느 정도 이해하고 있어야 불필요한 추가 작업을 막을 수 있고, '이렇게 해도 되는데 왜 꼭 이렇게 하라고 하는거지?'라는 불만을 갖지 않게 될테니까요.^-^
다른 Branch에 있는 Commit을 선별적으로 현재 Branch에 반영하기 위한 명령어입니다. Cherry-pick이라는 이름에서 뭐에 쓰는 건지 예측이 될 것입니다.
체리 나무에 달려 있는 체리를 하나씩 골라 따듯이, 커밋들이 달려 있는 커밋 나무(?)에서 필요한 커밋들을 하나씩 선별해서 가져 오기 위한 명령어가 바로 cherry-pick입니다.
git cherry-pick {Commit ID} |
이 때, 현재 Branch는 작업 내역을 반영할 Branch(대개 Master)여야 하고, 가져오려는 Commit이 여러개인 경우 먼저 작성한 Commit부터 순서대로 가져와야 합니다.
Cherry-pick은 엄연히 말하면 Commit을 가져 오는 것이 아니라, 가져올 Commit과 같은 Commit을 새로 만들어서 현재 Branch에 덧붙이는 작업입니다. 즉, 현재 Branch에 붙는 Commit은 Commit ID가 달라집니다.
왜냐하면 A를 X로 바꾸는 Commit과 B를 X로 바꾸는 Commit은 작업 내용이 서로 다른 Commit이기 때문입니다. 설명이 복잡해 졌는데, 이해가 잘 안간다면 다음 한 문장만 기억해 두면 됩니다.
'Cherry-pick은 Commit을 새로 하는 것과 같다.'
Rebase는 Cherry-pick과 유사하지만, 여러 개의 Commit을 동시에 다룰 수 있습니다. 즉, Cherry-pick으로 하는 작업은 Rebase 명령어로도 할 수 있습니다. 다만, Rebase는 여러 개의 Commit을 하나로 합치거나, 특정 Commit을 건너 뛰는 등 보다 복잡한 작업을 수행할 수 있습니다.
대상 Branch의 변경 사항을 모두 가져와서 현재 Branch에 반영하려 할 때 다음과 같은 명령어를 사용합니다.
즉, 현재 Branch와 대상 Branch의 공통 조상부터 대상 Branch의 마지막 Commit까지의 모든 Commit을 순서대로 하나씩 가져와서 현재 Branch에 덧붙입니다.
git rebase {가져올 Branch 이름} |
결과적으로, 대상 Branch는 변경되지 않고 현재 Branch에만 새로운 Commit이 생성되어 덧붙여집니다.
Rebase 명령에 -i(interactive) 옵션을 덧붙여 사용하면 Commit들의 순서를 바꾸고 첨삭하거나, 몇 개의 Commit을 하나로 합치는 등의 작업을 수행한 뒤 가져올 수 있습니다.
Rebase 명령과 -i 옵션의 조합은 '리베이시'라고도 불리우며, 병합 작업 뿐만 아니라 현재 Branch에서 최근에 작업한 몇 개의 Commit들을 편집하고자 할 때도 유용하게 사용할 수 있습니다.
예를 들어, 다음과 같이 입력하면 현재 Branch의 HEAD로부터 3개의 Commit들을 편집할 수 있습니다.
git rebase -i HEAD~3 |
이 때, Rebase 작업 이후 Commit들은 Cherry-pick과 마찬가지로 모두 ID가 바뀝니다.
쉽게 생각해서 위 명령은 HEAD로부터 3개의 Commit들을 현재 Branch에서 모두 '들어낸 뒤', 순서를 바꾸거나 합치는 등의 작업을 하고 다시 하나씩 새로 Commit하는 것입니다.
'리베이시' 명령은 개발을 진행하면서 은근히 많이 사용되므로 눈여겨 보는 것이 좋습니다. 특히 위에서 예로 든 명령의 경우 심심치 않게 자주 사용하게 될 것입니다.
3-Way Merge란 하나의 Branch를 다른 Branch에 합치는 작업을 의미합니다. 엄연히 말하면 부모 Commit이 둘 이상인 새로운 Commit을 만들어서 현재 Branch에 덧붙이는 작업입니다.
git merge --no-ff {합칠 Branch 이름} |
옵션으로 넣은 --no-ff 는 Fast-forward Merge가 가능하더라도, 무조건 3-Way Merge를 수행하라는 의미입니다.
3-Way Merge 작업을 수행하고 나면 합칠 Branch에서 가져온 Commit이 몇 개 였던지 간에 현재 Branch에는 딱 하나의 Commit만 새로 생성됩니다. 따라서, Merge를 취소하고 싶다면 새로 생성된 Commit만 삭제해 주면 됩니다.
Fast-forward Merge는 합칠 Branch가 현재 Branch와 분기된 이후, 현재 Branch에 새로 생성된 Commit이 없을 경우 현재 Branch를 가리키는 HEAD를 합칠 Branch의 마지막 Commit으로 옮김으로써 Merge를 수행하는 방법입니다.
뭔가 복잡한 설명이 되었는데요, 그림을 보면서 설명해 드리도록 하겠습니다.
( 그림 출처: http://www.deferredprocrastination.co.uk/blog/2012/git-un-merge/ )
왼쪽 그림은 Commit B의 위치에서 develop branch를 새로 만든 뒤, 이후 develop branch에서 C, D, E의 세 개 Commit을 작성한 상황을 나타내고 있습니다.
develop branch에서 세 개의 Commit을 새로 작성하는 동안, master branch에는 새로운 Commit이 하나도 추가되지 않았습니다. 이 상황이 바로 Fast-forward Merge가 가능한 상황입니다.
여기에서 Fast-forward Merge를 수행하면 3-Way Merge처럼 두 개의 조상을 갖는 새로운 Commit을 만들어서 master에 덧붙이는 것이 아닌, master branch를 가리키는 Commit Pointer를 E Commit으로 옮기는 것으로 Merge를 끝마치게 됩니다.
즉, 결과적으로 Master branch에서 C, D, E Commit을 새로 작성하고 E commit에 develop이라는 새로운 이름을 붙여 준 것과 같아집니다.
Fast-forward Merge는 수행 속도가 빠르고 불필요한 Branch를 없애 주는 역할을 하지만, 두 개의 branch의 구분이 사라지기 때문에 프로젝트 관리 면에서 모호함이 발생할 수 있습니다. (위 그림을 보면 master branch와 develop branch의 구분이 사라졌음을 알 수 있습니다.)
git merge {합칠 Branch 이름} |
Merge 명령에 별도의 옵션을 주지 않으면 기본적으로 Fast-forward Merge를 수행합니다. 단, Fast-forward Merge가 불가능한 조건일 경우 3-Way Merge를 수행합니다.
경우에 따라서 작업 기록을 남겨 두기 위해 Fast-forward Merge를 수행하지 말아야 될 경우가 있습니다. 이 경우 --no-ff 옵션을 주어서 3-Way Merge를 수행하면 됩니다.
Rebase와 Merge 모두 새로운 작업 내용을 Master branch와 합치는 데 사용할 수 있는 유용한 명령어입니다. 다만, 이 둘을 각각 언제 사용해야 할 지 잘 모르겠다면 다음 문장을 기억하고 있으면 됩니다.
'Merge는 Commit ID가 보존되고, Rebase는 새로운 Commit이 생성되므로 Commit ID가 바뀐다.'
그래도 잘 모르겠다면 PM에게 물어보면 됩니다. PM이 작업을 진행하는 스타일에 따라서 작업 내용을 Main stream branch에 반영할 때 Merge를 사용할 지, Rebase를 사용할지 달라지기 때문입니다.
GIT에 처음 입문하면 Commit ID가 달라지던 말던 작업 내용이 잘 반영되면 그만이지, 뭐가 중요하냐고 생각할 수도 있습니다. 하지만, 프로젝트의 규모가 커지면 이야기가 달라집니다.
원격 저장소에는 가급적 같은 작업을 수행한 Commit이 두 개 이상 존재하지 않도록 유지해야 합니다. 같은 작업 내용을 갖는 Commit이 두 개 이상 존재하면 지저분해지고, 프로젝트 관리상 좋지 않기 때문입니다.
역사가 오랜(?) 오픈소스 작업을 할 때는 Commit Log에 작업을 위한 정보가 담겨 있는 경우가 많고, 따라서 오랜 옛날의 Commit Log를 뒤져야 하는 경우가 많습니다. 이럴 때 같은 작업을 수행한 Commit이 둘 이상이라면 그것들을 모두 살펴봐야 하는 불상사가 발생합니다.
일반적으로, 로컬 저장소에서 병합하고 Push하는지, 혹은 작업 Branch를 Push하고 병합하는지에 따라 무엇을 사용할지가 결정됩니다.
핵심은 같은 작업을 하는 Commit이 둘 이상 발생하지 않도록 하는 것이므로, 다음과 같이 구분해서 사용하면 됩니다.
Rebase
로컬 저장소에서 작업을 위해 개인적으로 만든 Branch를 Main stream branch에 반영하여 Push 하기 위해 사용합니다. 로컬에 개인적으로 만든 Branch는 Push 이후 정리를 하면서 대개 삭제합니다. 대개 Hotfix와 같이 단기간에 끝나는 Topic의 경우 이 방법으로 작업합니다.
Merge
로컬 저장소에서 분기하고 작업한 Branch를 리뷰 등을 위해 원격 저장소에서 Push한 뒤, Review가 끝나고 PM이 Main stream branch에 병합하는 순서로 작업을 진행할 때 사용합니다. Branch가 그대로 유지되기 때문에 나중에 추가 작업을 해야 할 경우나, 큰 규모의 Topic인 경우 이 방법으로 작업합니다.
[펌] [GitLab] You are not allowed to push code to protected branches on this project (0) | 2019.07.12 |
---|---|
[펌] sourcetree 비밀번호 저장 안되는 이슈 mac (0) | 2018.12.27 |
[펌] Git: Zombie tags from hell (0) | 2018.02.21 |
[펌] Synology As A Git LFS Server (0) | 2017.11.14 |
[펌][SourceTree] 갑자기 실행이 안될때 (0) | 2017.10.23 |
[Link] NTP client library for .Net platforms (0) | 2019.03.28 |
---|---|
[링크] 코드에 부가 정보를 기록하는 어트리뷰트 (Attribute) (0) | 2019.01.31 |
[펌][C#] 초를 (Hour : Minutes : Seconds : Milliseconds) 시간으로 변환하는 가장 좋은 방법은 무엇입니까? (0) | 2018.07.12 |
[Link] EPPlus(Create advanced Excel spreadsheets using .NET) (0) | 2018.04.16 |
ODBC/OleDB로 Excel 읽어서 처리할 때, 255자로 짤리는 경우 (0) | 2018.04.13 |
[링크]
http://api.unrealengine.com/latest/KOR/
https://docs.unrealengine.com/en-us/Videos
http://rgy0409.tistory.com/category/Programs/Unreal%20Engine?page=1
[펌] 유니티 사용자가 본 언리얼엔진4 (0) | 2018.10.31 |
---|---|
언리얼 개발 키트, 에픽 게임스 - Epic UDK (0) | 2012.06.10 |
언리얼 볼만한 곳 (0) | 2012.04.29 |
[참고] https://blueasa.tistory.com/2185
-------------------------------------------------------------
맥의 하드용량이 내가 파일을 하드에 저장하는 것을 인지하는 것 보다 더 빨리 줄어드는 것 같다. 그래서 Hazel 에 규칙을 만들어서 주기적으로 안쓰는 파일을 지우거나 외장하드에 백업하기도 한다.
최근에는 맥북의 SSD에 16GB정도가 남아 있었는데, spotlight 인덱싱 때문인지 임시적으로 0이 될때도 있어서, 몇일 전에는 애플메일에는 spotlight 인덱싱을 뺐더니 하드확보는 되는 것 같다. magican으로 임시파일들을 청소하기도하고, Hazel 규칙을 만들어서 청소하기도 한다.
근데 오늘 뜻하지 않게 약 70GB를 확보하게 되었다.
결론 부터 얘기하면, Xcode 가 빌드할때 마다 아카이브하고 있는 파일들을 청소해서이다.
Xcode 프로젝트에서 기존에 있던 파일명으로 새로 파일을 만들고나서 빌드 오류가 나서 해결책을 찾다가 ~/Library/Developer/Xcode/DerivedData directory 라는 것을 발견했는데, 여기게 62GB가 있었다.
1. ~/Library/Developer/Xcode/DerivedData 지우기
찾아보니 이 디렉토리에 프로젝트 별로 빌드에 관한 정보가 다 저장되어 있다고 한다. 그래서 프로젝트 인덱싱이 잘 안되면 이 디렉토리를 지우는 것이 좋다는 팁도 있는데, 이게 계속 쌓이기만 하고 있는 것이 문제인 것 같다. 이 디렉토리를 지우고 다시 빌드를 하면 다시 생기니 여러 프로젝트를 하는 경우에 이 디렉토리를 지워도 되는 것 같다.
이 디렉토리르 지워서 62GB 가 생겼다.
2. ~/Library/Developer/Xcode/Archives 지우기
찾은 김에 Xcode 디렉토리들을 하나씩 봤는데, Archives 디렉토리도 있었다. 이건 릴리즈한 것에 대해서 디버깅을 할 수 있는 정보들이 있었다. 이것도 Xcode 에서 archive 할때마다 쌓이는 모양이다. 이 디렉토리는 지워서 8GB를 얻었다.
3. ~/Library/Developer/Xcode/iOS Device Logs 지우기
여기에 560MB 가 있었고, 로그를 볼일이 없어서 지웠다.
4. ~/Library/Developer/Xcode/ iOS DeviceSupport 필요 없는 시뮬레이터 지우기
여기에 8.64 GB 가 있었는데, 보니 iOS 5 부터 시뮬레이터들이 있었다. 최근것 남기도 다 지웠다.
Xcode 디렉토리들을 지워서 약 70GB를 확보 했다. 256 GB SSD 에서 70GB는 겁나 큰 수확이었다.
DerivedData directory 는 빌드할때 문제가 있을때 지우고 해보거나 하는 식의 팁들이 있었지만, 내 경우에는 하드용량을 확보하기 위해서 지우게된 셈이다.
매번 볼수는 없으니 Hazel 로 이 빌드 폴더가 5 기가 이상이 되면 자동으로 지워지게 규칙을 만들었다.
혹시 Xcode 를 사용하는 분 중에서 하드용량 확보 필요가 있다면 ~/Library/Developer/Xcode/ 디렉토리 용량이 얼마나 되는지 확인한번 해보는 것도 좋을 것같다.
[펌] MAC을 이용하여 IPv6 테스트 환경 구성하기 (0) | 2018.04.12 |
---|---|
[펌] macOS에서 숨겨진 폴더, 숨긴 파일을 표시하는 가장 간단한 방법 (0) | 2018.01.15 |
[펌] java.lang.NoClassDefFoundError:failed resolution of :Lorg/apache/http/ProtocolVersion (0) | 2019.05.29 |
---|---|
[링크] linker command failed with exit code 1 (use -v to see invocation) (7) | 2019.01.03 |
[펌] Error building Player: CommandInvokationFailure: Unable to merge android manifests. See the Console for more details 출처: http://jaehogame.tistory.com/entry/유니티-Error-building-Player-CommandInvokationFailure-Unable-to-merge-and.. (0) | 2018.05.18 |
[Bug] A script behaviour (script unknown or not yet loaded) has a different serialization layout when loading. (0) | 2018.01.17 |
[iOS] Google Analytics doesn't work on new iOS project (0) | 2017.11.08 |
[펌] (Draw.io) 온라인 다이어그램 툴 (0) | 2019.06.03 |
---|---|
[펌] 무료 집단(groupy) 대체 프로그램 10개(탐색기 확장) (0) | 2019.01.23 |
[링크] 다중모니터 프로그램 울트라몬 대신 무료 듀얼모니터프로그램 ZBar (0) | 2017.09.19 |
[링크] 무료 프로그램 (0) | 2017.09.19 |
[링크][HockeyApp] 앱 배포, 관리를 도와주는 하키앱 소개 (0) | 2017.08.30 |
Unlit - Transparent Colored GrayScale.zip
NGUI의 ScrollView 안에 있는 오브젝트의 UITexture에 GrayScale을 적용하려고 아래 [참고]의 쉐이더를 썼는데
제대로 안되길래 보니 Clipping 개수에 따른 추가 쉐이더가 없어서 겸사겸사 만들어서 올려 놓음.
[NGUI] 초당 터치 횟수 제한 (0) | 2019.07.08 |
---|---|
[링크/NGUI] UI 기본구조와 주요 컴포넌트 (0) | 2019.05.07 |
[펌] EmojiLabel (for NGUI with dynamic font) (0) | 2018.06.07 |
Useful stuff for NGUI (0) | 2018.06.07 |
[NGUI] 스크롤뷰(패널) 맨끝으로 드래그했을때 처리 (0) | 2018.01.11 |