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

2018년 3월 29일 목요일

엑셀 수식 -> 텍스트, 텍스트 -> 수식 팁

엑셀 수식을 텍스트로 만들 때는 함수로 간단히 된다.

=FORMULATEXT()

반대의 경우는 준비된 함수가 없기 때문에

모듈을 새로 추가하여 아래와 같이 커스텀 함수를 만들어 준다.

Function Eval(Ref As String)

Application.Volatile

Eval = Evaluate(Ref)

End Function


추가 한 후 아래커스텀 함수를 사용하면 된다.

=Eval()

윈도우 일본어 IME (Japanese IME) 사용 팁 (일본어 입력 전환 방법)

일본어 입력기 사용 방법 


일본어 입력기 전환 : (왼쪽) Alt + Shift (MS IME 에서 설정한 언어 전환 기능) 

[일본어 입력기 상태 일 때] 
  • 히라가나 모드 : (왼쪽) Ctrl + CapsLock 
  • 카타가나 모드 : (왼쪽) Alt + CapsLock 
  • 로마자 모드 : (왼쪽) Shift + Caps Lock 

[한자 입력 후보를 고를 때]
  • F5 확장 입력기 창 띄움 (부수 기준 찾기) 
  • F6 현재 후보를 무시하고 히라가나로 변환 
  • F7 현재 후보를 무시하고 카타가나로 변환 
  • F8 반각 카타카나
  • F9 전각 영문 
  • F10 입력 그대로 반각 영문으로 변환 

[특수 문자 입력] (특수 문자는 기본적으로 전각이기 때문에 주의할 것)
  • !: かんたんふ 
  • ?:はてな 
  • →:やじるし 
  • ★:ほし 
  • 〇:まる 
  • ※:こめ 

2018년 3월 28일 수요일

MS WORD 와일드카드 바꾸기 기초 예제



ms word 패턴으로 찾아 바꾸기

예문)
원문 : 캐릭터 이름은 ㅇㅇㅇ 입니다.
바꿀 문장 : 캐릭터의 이름은 ㅇㅇㅇ 일지도 모릅니다.

ㅇㅇㅇ 을 유지하고 "캐릭터 이름은" 과 "입니다." 를 바꾸고 싶습니다.

찾기 및 바꾸기 창에서 패턴 일치(와일드카드) 사용에 체크한 후
아래와 같이 입력 한다.

찾을 내용 : 캐릭터 이름은 (*) 입니다.
바꿀 내용 : 캐릭터의 이름은 \1 일지도 모릅니다.

() 식으로 묶는다.
* 전부다를 의미하는 와일드 카드
\1 은 첫번째

여러개가 있는 경우 \1 \2 이런식으로 사용할 수 있다.

참고 링크 : https://support.office.com/ko-kr/article/word-%EB%AC%B8%EC%84%9C%EC%97%90%EC%84%9C-%ED%85%8D%EC%8A%A4%ED%8A%B8%EC%99%80-%EA%B8%B0%ED%83%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B0%BE%EA%B8%B0-%EB%B0%8F-%EB%B0%94%EA%BE%B8%EA%B8%B0-c6728c16-469e-43cd-afe4-7708c6c779b7



2018년 2월 13일 화요일

쉽게 만드는 UI 스크롤뷰

개인적으로 uGUI 의 사용을 늘리고 있다.
NGUI 는 널리 쓰이는 서드파티 에셋이지만, 안드/아이폰 이외의 작업에는 아무래도 호환성 문제가 생기고,
유니티 최신 엔진 업데이트시에 가끔 문제를 일으켰던 기억이 있기 때문이다.
예전에 안드로이드TV를 지원하게 만들다가, NGUI 는 KEY NAVIGATION 지원이 거의 전무하다 시피했던 기억이 난다.

개인 프로젝트는 최대한 uGUI 를 이용해서 만들고 있다.
SizeFitter 라든가 Layout 세팅 관련 컴포넌트 스크립트가 예상보다 많이 준비되어 있어서 간단히 만들 수 있다.

오늘 초보자인 어떤 분이 GUI 를 만들다가 힘들어서 질문을 해왔다.
조금 생각해보니 처음 만드는 사람이라면 확실히 어려울 수 있을거 같다는 생각이 들어서
따라하기 스타일로 아래에 Scroll View 만들기를 정리해보려고 한다.

--------------------------------------------------

아래와 같은 하단 좌우 스크롤뷰 UI를 만들어보자.


1. Unity 에서 Hierarchy 메뉴에 우클릭 > UI > Canvas 를 하나 만들어서 적당히 세팅해준다. (위치와 크기의 세팅 등)

2. Canvas에서 우클릭해서 UI > Scroll View 를 클릭해서 추가해준다.



3. 생성된 Scroll View 의 사이즈와 위치를 정리해준 후, Inspector 에 아래 내용대로 체크/언체크 해준다.


좌우로만 움직일 스크롤 뷰라서 Horizontal 만 체크한다.


4. 컨텐츠 오브젝트의 제어 콤포넌트 추가. (여기가 어렵다.)
Hierarchy 에 Content 를 선택해 보면 Rect Transform 이외에 아무런 컴포넌트가 없다.
여기에 필요한건 Child 오브젝트를 추가할 경우 "해당 오브젝트 들의 레이아웃 설정"과 "사이즈를 맞춰주는 기능"이 필요하다.
예전에는 직접 코드를 짰는데, 찾아보니 uGUI 에 이미 준비되어 있다.


5. Content 오브젝트에 컴포넌트를 추가한다. (제일 중요한 부분)
A. Horizontal Layout Group 이라는 컴포넌트
B. Content Size Fitter 라는 컴포넌트


COntent Size Fitter 에 Horizontal Fit 는 Preferred Size 로 맞춰준다.

5. Content 이하에 Button 오브젝트 등 필요한 오브젝트를 추가하여 늘어 놓는다.

6. Unity 의 플레이 버튼을 클릭하면 게임 씬에서 아래와 같이 조작이 가능하다.

좌우로 스크롤 해보면 원하는대로 스크롤이 가능!


<끝>

2018년 1월 25일 목요일

정규식 쉽게 만들고 확인하기 사이트 링크 2개

정규식은 유용하지만 만들 때 많이 번거롭다.
귀찮음을 덜어줄 수 있는 사이트를 2개 소개한다.

# 만들기
http://www.txt2re.com/  
텍스트를 분석해서 정규식으로 만들어준다.
사용법은 좀 클릭해보면 쉽게 알 수 있다. (정규식을 아예 모르면 조금 어려울지도)



# 확인하기
https://regexr.com/
만든 정규식으로 샘플 스트링으로 즉시 확인해볼 수 있다.
(예전부터 많이 사용하던 사이트 ^^;; )

2017년 12월 1일 금요일

인벤토리 기초 구조 코드

다시 게임 제작개시, 이제 간단한 미니게임은 충분한 것 같고..
조금 더 나의 본질이 뭔가, 뭐가 하고 싶은가를 고민하다가 새 게임을 시작.

이번 게임은 수집, 성장 요소가 있는 게임이기 때문에 인벤토리가 필요해서 하나 만들었다.



간만에 풀코드.
InventorySystem.cs


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Kpaper;

namespace Kpaper
{
    public class InventorySystem : MonoBehaviour
    {
        #region Inventory
        
        // 인벤토리 시스템 기초 구조만 담긴 코드
        // _itemID 를 itemTable 에서 찾아서 정보를 표시하거나 하는 부분은 별도로 구현해야 한다.

        // 아이템의 아이디 갯수 itemID, count
        public Dictionary items = new Dictionary();

        // items 에 입력한 아이템 ID와 카운트를 더해준다. (add 다. assign 아님)
        public void setAddItem(int _itemID, int _count)
        {
            // 아이템이 목록에 없다면 넣어준다.(초기 갯수는 0개)
            if (items.ContainsKey(_itemID) == false)
            {
                items.Add(_itemID, 0);
            }

            // 아이템 수량 증가 적용
            items[_itemID] += _count;

            if (Debug.isDebugBuild)
                Debug.Log(string.Format("{0} {1}을 {2} 개", "아이템 삽입", _itemID, _count));
        }

        // items 에서 해당 아이템 키가 있는지 확인하고 있으면 카운트 만큼 빼준다. 카운트가 0인 경우에는 아이템 키를 제거해준다.
        public void setRemoveItem(int _itemID, int _count)
        {
            // 아이템이 목록에 없다면 아무것도 하지 않는다.
            if (items.ContainsKey(_itemID) == false)
            {
                if (Debug.isDebugBuild)
                    Debug.Log("아이템이 목록에 없습니다.");
                return;
            }

            // 아이템 수량 감소 적용
            items[_itemID] -= _count;

            // 아이템 수를 감소 시켰더니 0개 이하이면 아이템을 사전 목록에서 제거한다.
            if (items[_itemID] <= 0)
                items.Remove(_itemID);

            if (Debug.isDebugBuild)
                Debug.Log(string.Format("{0} {1}을 {2} 개", "아이템 제거", _itemID, _count));
        }

        
        // 보유한 아이템 목록
        public List keys = new List();

        // 아이템 목록 새로 고침
        public void setRefreshInventory()
        {
            if (Debug.isDebugBuild)
                Debug.Log(items.Count + " 개의 아이템이 있습니다.");

            // 딕셔너리의 키 묶음을 들고와서 Keys 리스트를 만든다.
            keys = new List(items.Keys);

            // Keys 리스트를 기준으로 아이템 ID와 수량을 출력한다.
            for (int i = 0; i < keys.Count; i++)
            {
                int _itemID = keys[i];
                int _itemCount = items[_itemID];

                if (Debug.isDebugBuild)
                    Debug.Log("아이템 키 : " + _itemID + " 아이템 수량 : " + _itemCount); // 이 부분을 리스트로 만들어 쓰던가 하면 관리하기 편하다.
            }

        }

        // 아이템 아이디를 입력하면 해당 아이템의 보유 수량을 리턴한다. 아이템을 찾을 수 없으면 0을 보낸다.
        public int getItemCountByItemIndex(int _itemID)
        {
            if (items.ContainsKey(_itemID))
            {
                return items[_itemID];
            }
            else
            {
                Debug.Log(string.Format("인벤토리 안에서 찾을 수 없는 아이템ID {0} 를 요청했습니다.",_itemID));
                return 0;
            }
        }

        #endregion

        #region MonoBehavior

        private void Start()
        {
            // 시연
            
            // 임의로 1이라는 itemID를 가진 아이템을 10개 넣고 5개씩 2번 빼서 0으로 만들어 본다.

            // 인벤토리 리프레시
            setRefreshInventory();

            // 아이템 1을 10개 넣고
            setAddItem(1, 10);

            // 인벤토리 리프레시
            setRefreshInventory();

            // 아이템 갯수 찾기 테스트
            Debug.Log(getItemCountByItemIndex(2));

            // 1을 5개 제거
            setRemoveItem(1, 5);

            // 인벤토리 리프레시
            setRefreshInventory();

            // 1을 5개 제거
            setRemoveItem(1, 5);
            
            // 인벤토리 리프레시
            setRefreshInventory();

        }

        #endregion
    }
}

2017년 11월 23일 목요일

Windows 10 에서 시작버튼이 먹통이 되었다면?


explorer.exe 프로세스를 강제 종료 하고, 새 작업으로 실행하면 된다.

윈도우 시작 버튼 위에서 무반응인 버튼에 마우스로 우클릭 좌클릭 우클릭 좌클릭 을 반복하면 작업관리자를 강제로 불러낼 수 있다.

2017년 11월 16일 목요일

EXCEL VBA 에서 Http Request 하는 방법

VBA 도구를 만들다가 외부 API 와 통신할 일이 있어서 남기는 기록이다.
보통 Open API 를 이용하면 JSON 으로 리턴되므로 이걸 파싱해서 쓰면 된다.

아래코드를 실행 하기 전에, 참조를 추가해야 한다.

Visual Basic 도구, 참조 메뉴에서
Microsoft WinHTTP Services, version 5.1 이 사용하도록 체크되어 있어야 한다.



참고 소스 코드

Function requestHTTP()

Dim PostData As String
Dim T As String

'Web에서 가져오기, 에러 발생하면 참조모듈 확인 (Microsoft WinHttpRequest 가 참조되어야 함)
Dim httpRequest As New WinHttpRequest

'아래에 넘길 포스트 데이터를 적는다.
    PostData = "postData=_postData" 
    
        With httpRequest
        .Open "POST", "http://오픈할 Open API 주소"
        .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
        .Send PostData
        .WaitForResponse: DoEvents
        T = .ResponseText
        
    End With

requestHTTP = T
    
End Function

2017년 11월 14일 화요일

Unity WebcamTexture 의 동작에 문제가 있다면? - 해결 대안 제시

Unity API 를 통해서 장착된 WebCam을 컨트롤 해봤다.
되긴 되는데 신통찮다.

살아있는지 여부를 확인 하기 어렵고(try ~ catch 로 에러 핸들링도 불가),
각 캠이 지원하는 해상도 리스트도 가져올 수 없고 등등 불편하다.
 
안되는 장치도 있다.

Windows 10 출시 이후 발매된 웹캠 (특히, 마이크로소프트 스튜디오 시리즈)은 제대로 인식이 안된다.
장치가 1개만 설치되어 있을  때는 어영부영 돌아가는데, 2개 이상 설치되어 있을 때는 제대로 안된다.

Devices 에 인식이 제대로 안되고, 장치 이름 조차도 제대로 가져오지 못한다.

Logitech 의 웹캠은 대부분 잘 되는데, 이도 문제가 있으니...

Logitech Brio 4K 같은 경우는 고급 웹캠이라 그런지 화질과 동작 성능 양쪽에 문제가 없고
다양한 해상도와 컬러 포맷을 지원해서 그런지 Unity 와의 호환성에 크게 문제가 없다.

문제는 국민캠으로 불리는 Logitech C920 은 큰 문제가 없으나,
이 모델의 후속 기종인 C922가 문제가 된다.

640x480 의 기본 해상도는 별 차이 없이 잘 동작하는데,
1280x720 해상도를 요청하면 C922 의 경우에는 60FPS로만 동작하게 된다.
 
그러면  Unity 화면 상에서 뭔가 끊기는 느낌으로 동작하게 되는데...
왜 이런 거동을 보이는지 이해를 할 수 없지만,
내부를 본게 아니니 이해는 잠시 접어두고 방법 해결에만 집중했다.


이래저래 구글링 해외 포럼을 뒤져보니 비슷한 문제를 가진 사람이 많았고,
DirectShow를 이용해서 웹캠을 출력하면 될거라는 결론에 도달했다.

직접 만들어야 하나?
음... 더 이상 내부에서 작업량을 늘리고 싶지 않았다.


조금 더 찾아보니 다행히도 누군가 만들어둔 플러그인이 있었다. (영국의 RenderHeads 社)
AssetStore에서 아래의 Plugin의 데모 버전으로 시험해보니 큰 문제 없었기에 구입하는 것으로 결정.


[AVPro Live Camera]
https://www.assetstore.unity3d.com/kr/#!/content/3683

덱링크사의 제품까지 지원한다는데 이런 장비가 집에 없으니 모르겠고,
캡쳐카드를 통한 캡쳐도 화면이 이상하게 잘리거나 하는 문제 없이 거의 잘 되는 것 같다.

지원 플랫폼은 DirectShow를 이용하는 탓인지 Window Standalone 전용이기 때문에,
Windows에서 다양한 웹캠을 지원해야 하는
나와 비슷한 특수한 경우에 해당되는 사람들에게 추천한다.

2017년 11월 7일 화요일

Texture2D Rotate 코드

Texture2D 를 회전 시키는 코드인데,
매 Update 프레임에서 쓰기에는 오버헤드가 커서 사용하면 안된다.
그래도 어딘가 누군가에게는 도움이 될거라 생각해서 수집한 내용 기록..

# 출처 : https://answers.unity.com/questions/685656/rotate-an-image-by-modifying-texture2dgetpixels32.html

public static Texture2D RotateImage(Texture2D originTexture, int angle)
        {
            Texture2D result;
            result = new Texture2D(originTexture.width, originTexture.height);
            Color32[] pix1 = result.GetPixels32();
            Color32[] pix2 = originTexture.GetPixels32();
            int W = originTexture.width;
            int H = originTexture.height;
            int x = 0;
            int y = 0;
            Color32[] pix3 = rotateSquare(pix2, (Math.PI / 180 * (double)angle), originTexture);
            for (int j = 0; j < H; j++)
            {
                for (var i = 0; i < W; i++)
                {
                    //pix1[result.width/2 - originTexture.width/2 + x + i + result.width*(result.height/2-originTexture.height/2+j+y)] = pix2[i + j*originTexture.width];
                    pix1[result.width / 2 - W / 2 + x + i + result.width * (result.height / 2 - H / 2 + j + y)] = pix3[i + j * W];
                }
            }
            result.SetPixels32(pix1);
            result.Apply();
            return result;
        }
        static Color32[] rotateSquare(Color32[] arr, double phi, Texture2D originTexture)
        {
            int x;
            int y;
            int i;
            int j;
            double sn = Math.Sin(phi);
            double cs = Math.Cos(phi);
            Color32[] arr2 = originTexture.GetPixels32();
            int W = originTexture.width;
            int H = originTexture.height;
            int xc = W / 2;
            int yc = H / 2;
            for (j = 0; j < H; j++)
            {
                for (i = 0; i < W; i++)
                {
                    arr2[j * W + i] = new Color32(0, 0, 0, 0);
                    x = (int)(cs * (i - xc) + sn * (j - yc) + xc);
                    y = (int)(-sn * (i - xc) + cs * (j - yc) + yc);
                    if ((x > -1) && (x < W) && (y > -1) && (y < H))
                    {
                        arr2[j * W + i] = arr[y * W + x];
                    }
                }
            }
            return arr2;
        }

2017년 11월 6일 월요일

Unity Texture -> RenderTexture -> Texture2D -> Color32[] 로 변환의 험란한 길

영상 처리 작업을 하던 중 Color32[]를 이용할 일이 있었는데.
Unity 로 이걸 할라 하니 이래저래 삽질이 있었다.

적당히 구글링 해보니 Texture 를 Texture2D.ReadPixel 을 이용해서 Texture2D로 읽는 팁이 있었는데,
막상 해보니 그리는 프레임에 이걸 하면 동작하지 않는다.

좀 멀리 돌아온 감이 있는데,
텍스쳐를 렌더 텍스쳐로 바꾸고 이걸 텍스쳐2D로 만든 다음에 Colors32를 들고 오면 된다.

하루종일 삽질한 것 치고 우아하지 않아서 고민하다가..
지쳐서 그냥 이쯤에서 마무리.

C#으로는 한계가 있는 느낌.. 하아...


    private Texture2D _texture2D;
    private Texture _mainTexture;
    private RenderTexture _renderTexture;

    public Color32[] getTexture2D_AsPixel32()
    {
        if (_mainTexture == null)
            _mainTexture = _liveCamera.OutputTexture;

        if (_texture2D == null)
        {
            _texture2D = new Texture2D(_mainTexture.width, _mainTexture.height, TextureFormat.RGBA32, false);
        }
        //RenderTexture currentRT = RenderTexture.active;

        if (_renderTexture == null)
            _renderTexture = new RenderTexture(_mainTexture.width, _mainTexture.height, 32);

        // mainTexture 의 픽셀 정보를 renderTexture 로 카피
        Graphics.Blit(_mainTexture, _renderTexture);

        // renderTexture 의 픽셀 정보를 근거로 texture2D 의 픽셀 정보를 작성
        RenderTexture.active = _renderTexture;

        _texture2D.ReadPixels(new Rect(0, 0, _renderTexture.width, _renderTexture.height), 0, 0);
        _texture2D.Apply();

        return _texture2D.GetPixels32();

    }

2017년 11월 3일 금요일

해상도 값을 이용한 화면 비율 알아내기

웹캠에서 지원하는 해상도를 정리하다가
적당히 만들고 있었는데 번거로워서 만든 것
_width와 _height 를 입력하면 스트링으로 가로세로 비율이 나온다.



    // _width 는 가로 해상도, _height 는 세로 해상도 픽셀 값
    public string getResolutionRatio(int _width, int _height)
    {
        int a;
        int b;

        // 화면의 가로/세로 중 긴 쪽을 앞으로 하기
        if (_width < _height)
        {
            a = _width;
            b = _height;
        }
        else
        {
            a = _height;
            b = _width;
        }

        // 최대 공약수, 유클리드 호제법
        int gcd = gcd3(a, b);

        return string.Format("{0}:{1}", _width / gcd, _height / gcd);
    }

    private int gcd3(int a, int b)
    {
        return a % b == 0 ? b : gcd3(b, a % b);
    }

2017년 10월 14일 토요일

타임서버에서 시각 가져와서 Unity 에서 사용하기 (NST, NIST)

NIST 타임서버에서 시간가져오기 (NST)

아래와 같은 코드로 가져올 수 있다.
Unity 에서 사용할 수 있다.


using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TimeServer : MonoBehaviour {

    [SerializeField]
    private string _comment = "만료시킬 날짜를 적으세요 (한국시각 기준)";

    public int _yyyy, _mm, _dd;
    private DateTime _expireDateTime, _nowServerDateTime, _nowLocalDateTime;
    private TimeSpan _duration;

 // Use this for initialization
 void Start () {

        // 한국 시각
        _duration = System.TimeSpan.FromHours(9);
        _expireDateTime = new DateTime(Mathf.Clamp(_yyyy, 1900, 3000), Mathf.Clamp(_mm, 1,12), Mathf.Clamp(_dd, 1, 31));

        _nowLocalDateTime = DateTime.Now;
        _nowServerDateTime = GetNISTDate().Add(_duration);

        if (Debug.isDebugBuild)
        {
            Debug.LogWarning("만료지정일 : " + _expireDateTime);
            Debug.LogWarning("현재 로컬 시각 :" + _nowLocalDateTime);
            Debug.LogWarning("현재 서버 시각 :" + _nowServerDateTime);
        }

        if (_nowLocalDateTime < _expireDateTime)
        {
            if (_nowServerDateTime < _expireDateTime)
            {
                // Debug.Log("실행");
            }
            else
            {
                // Debug.Log("서버 체크 결과 만료 됨");
            }
        }
        else
        {
            // Debug.Log("로컬 체크 결과 만료 됨");
        }


    }

#region NTPTIME

    //NTP time 을 NIST 에서 가져오기
    // 4초 이내에 한번 이상 요청 하면, ip가 차단됩니다.

    public static DateTime GetDummyDate()
    {
        return new DateTime(2017, 12, 24); //to check if we have an online date or not.
    }

    public static DateTime GetNISTDate()
    {
        System.Random ran = new System.Random(DateTime.Now.Millisecond);
        DateTime date = GetDummyDate();
        string serverResponse = string.Empty;

        // NIST 서버 목록
        string[] servers = new string[] {
        "time.bora.net",
        //"time.nuri.net",
        //"ntp.kornet.net",
        //"time.kriss.re.kr",
        //"time.nist.gov",
        //"maths.kaist.ac.kr",
        "nist1-ny.ustiming.org",
        "time-a.nist.gov",
        "nist1-chi.ustiming.org",
        "time.nist.gov",
        "ntp-nist.ldsbc.edu",
        "nist1-la.ustiming.org"
    };

        // 너무 많은 요청으로 인한 차단을 피하기 위해 한 서버씩 순환한다. 5번만 시도한다.
        for (int i = 0; i < 5; i++)
        {
            try
            {
                // StreamReader(무작위 서버)
                StreamReader reader = new StreamReader(new System.Net.Sockets.TcpClient(servers[ran.Next(0, servers.Length)], 13).GetStream());
                serverResponse = reader.ReadToEnd();
                reader.Close();

                // 서버 리스폰스를 표시한다. (디버그 확인용)
                if (Debug.isDebugBuild)
                    Debug.Log(serverResponse);

                // 시그니처가 있는지 확인한다.
                if (serverResponse.Length > 47 && serverResponse.Substring(38, 9).Equals("UTC(NIST)"))
                {
                    // 날짜 파싱
                    int jd = int.Parse(serverResponse.Substring(1, 5));
                    int yr = int.Parse(serverResponse.Substring(7, 2));
                    int mo = int.Parse(serverResponse.Substring(10, 2));
                    int dy = int.Parse(serverResponse.Substring(13, 2));
                    int hr = int.Parse(serverResponse.Substring(16, 2));
                    int mm = int.Parse(serverResponse.Substring(19, 2));
                    int sc = int.Parse(serverResponse.Substring(22, 2));

                    if (jd > 51544)
                        yr += 2000;
                    else
                        yr += 1999;

                    date = new DateTime(yr, mo, dy, hr, mm, sc);

                    // Exit the loop
                    break;
                }
            }
            catch (Exception e)
            {
                /* 아무것도 하지 않고 다음 서버를 시도한다. */
            }
        }
        return date;
    }
    #endregion
}


아래 코드 원본에서 주석 변경 및 내가 사용하기 위해 수정함.
경로 : https://stackoverflow.com/questions/516788/getting-current-gmt-time

2017년 9월 18일 월요일

Unity Custom Menu 만들기

귀찮은 작업이라고 생각해서 잘 안하는 편이었는데...
오늘 처럼 뭔가 단순하게 반복해야 하는 작업에는 메뉴로 등록하고 빨리 적용하는게 나을 것 같았다.

작업 내용은 어떠한가 하니
1. 어떤 오브젝트에 필요한 새 컴포넌트를 붙이고,
2. 구 컴포넌트의 값을 새 컴포넌트로 옮기고,
3. 구 컴포넌트를 삭제한 뒤,
4. 주석용으로 사용하는 컴포넌트를 붙여서 작성시각을 기록한다.

일괄로 하기엔 확인하면서 진행해야 해서 메뉴를 이용하는 정도가 딱 좋았다.
(컨텍스트 메뉴가 나았을지도? (웃음))

참고한 Document
https://docs.unity3d.com/ScriptReference/EditorGUILayout.html

예제는 이거면 금방 알 수 있다. (Toggle 레퍼런스에서 옮김)
필요한 변수를 선언하고
editorLayout 으로 연결하고
거기서 조작에 따라 처리할 내용을 기입하면 된다.


using UnityEngine;
using UnityEditor;

public class EditorGUILayoutToggle : UnityEditor.EditorWindow
{
    bool showBtn = true;

    [MenuItem("Examples/Editor GUILayout Toggle Usage")]
    static void Init()
    {
        EditorGUILayoutToggle window = (EditorGUILayoutToggle)EditorWindow.GetWindow(typeof(EditorGUILayoutToggle), true, "My Empty Window");
        window.Show();
    }

    void OnGUI()
    {
        showBtn = EditorGUILayout.Toggle("Show Button", showBtn);
        if (showBtn)
            if (GUILayout.Button("Close"))
                this.Close();
    }
}

2017년 9월 14일 목요일

Android Shell 로 뒤로가기(Back) 버튼 입력하기


Run Shell 에서 아래 커맨드를 입력한다. Root 권한이 있을 때만 실행이 가능하다.
Tasker 등에서 뒤로가기를 실행 해야 하는데 메뉴가 없을 때 유용하다.



input keyevent 4

//혹은

input keyevent 187

2017년 9월 8일 금요일

Unity Editor 를 켤 때 마다 무언가를 실행하기 (버전 정보 갱신)

버전 정보를 빌드 할 때 마다 일일히 써주는게 귀찮았다.

빌드 전에 버전 정보를 갱신해주는 스크립트를 돌리면 되는데,
아래 두가지 이유로 에디터를 켤 때 (포커스가 올 때?) 마다 버전 정보를 갱신해 줬다.
1. 다른 사람이 세팅한 빌드 머신을 건드리기 귀찮아서
2. 에디터 건드릴 때 마다가 좋아서

여튼 아래는 간단히 짠 코드
버전 정보의 형식은 예시로 적당히 쓴 것이다.
4단위로 1.0.년.월일
예) 1.0.17.1159

혹시 실행이 안되거나 권한 없음 오류가 나면, 유니티 에디터를 실행할 때 관리자 권한으로 실행하면 된다.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[InitializeOnLoad]
public class Startup
{
    static Startup()
    {
        string VersionInfo = "1.0." + string.Format("{0:00}", System.DateTime.Now.Year).Substring(2, 2) + "." + string.Format("{0:00}", System.DateTime.Now.Month) + string.Format("{0:00}", System.DateTime.Now.Day);
        System.IO.File.WriteAllText(Application.dataPath + "/Resources/AppVersionInfo.txt", VersionInfo.ToString());
        Debug.LogWarning("오늘의 버전 정보 갱신 : " + VersionInfo + "\n저장 경로 : " +Application.dataPath+"/Resources/AppVersionInfo.txt");
    }
}

2017년 9월 7일 목요일

게임 컨트롤러의 스위치를 와이어로 연결할 때 와이어 구매 팁 (컨트롤러 자작)

브레드보드용 와이어를 쉽게 구해서 사용할 수 있는데,
얇은 선이 꼬인 것을 연선, 굵은 선 한가닥을 단선이라고 한다.
게임 스위치용으로는 단선이 좋다.

연선으로 해도 동작은 하는데, 미묘하게 레이턴시가 생긴다.

2017년 8월 28일 월요일

코드 조각 리스트<클래스>의 소팅 하기

평소에는 List<>.sort() 로 쉽게 정렬을 하지만,
직접 만든 클래스는 정렬이 어려워서 이럴 떄 사용할만한 코드 조각

public class BasicEntity
{
    public int Index = 0;
    public string Name = string.Empty;
    public float Value = 0f;
}

   // true 면 낮은 순부터 0 false 면 반대
    public List<BasicEntity> sortFilterEntity(List<BasicEntity> list, bool order)
    {
        List<BasicEntity> result = list;

        if (order)
        {
            result.Sort(delegate (BasicEntity A, BasicEntity B)
            {
                if (A.Index > B.Index) return 1;
                else if (A.Index < B.Index) return -1;
                return 0;
            });
        }
        else
        {
            result.Sort(delegate (BasicEntity A, BasicEntity B)
            {
                if (A.Index > B.Index) return -1;
                else if (A.Index < B.Index) return 1;
                return 0;
            });
        }

        for (int i = 0; i < result.Count; i++)
        {
            Debug.LogError(result[i].Name);
        }

        return result;
    }

2017년 8월 14일 월요일

Unity C# object 배열 메모

개발하다가 메모 하나...

다른 클래스 타입의 여러가지 오브젝트를 하나의 목록에 넣을 때,
배열 혹은 리스트를 사용하게 되는데...

C#의 object 는 System.Collections.Generic.List<T> 에 넣으면 Null Reference Exception 이 발생한다.

object[] 로 배열로 넣고 사용하면 된다.

2017년 8월 8일 화요일

구글지도로 위도 경도 URL 로 던지기

구글맵스에 아래와 같이 위도 경도 URL을 보낼 수 있다.
아래 링크는 판교역 1번 출구 근처

https://www.google.co.kr/maps/@37.3951627,127.1117136,18.5z

@위도,경도,줌 (15~18정도가 적절?)

--------------------------------------------

마커도 같이 보내고 싶으면 아래와 같은 방법으로 가능하다.
q= 로 표시할 지도의 경도 위도를 보내고
ll= 로 마커 찍을 경도 위도를 보낸다.
z=는 줌 레벨이다.

http://maps.google.com/maps?&z=18.5&q=37.3951627,127.1117136&ll=37.3951627,127.1117136