2017년 12월 4일 월요일

Rufus 윈도우 10 설치 USB 제작 툴

오랜만에 윈도우를 새로 설치할 일이 생겼다.

usb 에 부팅 이미지를 설치하려는데

늘 써오던 Microsoft USB TOOL 말고 Rufus 라는 툴을 사용해봤다.

포맷과 함께 iso 파일을 구워준다.

포터블 버전도 있어서 편하고 더 빠르기에 추천 링크를 남긴다.

다운로드 : http://rufus.akeo.ie




(광고가 아니라 직접 써보고 간결하고 확실하고 빨라서 좋아서 감동하여 추천하는 글입니다.)

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

인공지능 번역기 툴을 만들다가 남기는 후기

어플리케이션의 스트링 리소스를 한방에 (기계)번역하는 툴을 필요에 의해서 만들게 되었다.
(복붙이 너무 귀찮았어...)

구글 API 는 유료이길래 별 생각 없이 라이벌(?) 이라고 불리는 네이버 PAPAGO Open API 로 번역을 해봤다.

하루종일 삽질해서 Unity 용 툴, 엑셀용 VBA 툴 2가지를 만들었는데... (VBA가 더 어렵네 -_-;; )

막상 PAPAGO 의 번역 품질을 보니 쓰기 어려운 수준이라는 느낌을 받았다.
아래의 번역 시험 결과는 아주 소프트한 예시이다. (그나마 잘된걸 고른 것)

실제로 특수기호나 숫자가 섞이거나, 외래어 표기가 된 한글의 처리가 제대로 되지 않아서 쓰기 힘들었다.
예를 들면 "웹캠" 이라는 단어가 있으면 구글은 Web Cam 으로 PAPAGO는 "웹캠"으로 번역해버린다. (한글로 그대로 출력)

Oh My God.

뭐 가끔 쓰는 정도로 하는걸로 하고 오늘의 작업을 마무리..

Unity 툴은 에셋 스토어에 올려버렸고,

VBA 는 좀 더 다듬어서 블로그에 공개해야겠다.
누군가라도 쓰겠지 랄까 -_-;;;;

- [번역 시험 결과]----------------------------------------------

Source)
장치가 사용 중이거나 응답하지 않습니다.
영상 요청을 중단합니다.
다른 장치로 다시 시도해봐주세요.

Google)
The device is busy or not responding.
Abort video requests.
Please try again with another device.

Papago)
Device is busy or unresponsive.
Stops image request.
Try again with another device.

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월 31일 화요일

무라카미 하루키 스크랩


뭔가를 비난한다는 것, 엄격하게 비평하는 것 자체를 잘못이라고 말하는 것이 아니다. 모든 텍스트는 온갖 비평에 열려 있는 것이고, 또 열려 있어야 한다. 다만 내가 여기서 말하고 싶은 것은, 뭔가에 대한 네거티브한 방향의 계몽은 경우에 따라서는 여러 가지 사물을, 때로는 자기 자신까지도, 돌이킬 수 없을 정도로 훼손시켜버리고 만다는 사실이다. 그런 부정에는 보다 크고 따뜻한 포지티브한 '보상'같은 것이 마련되어 있어야 할 것이다. 그러한 뒷받침이 없는 네거티브한 연속적인 언동은, 즉효성이 있는 주사에 중독되는 것과 마찬가지여서, 일단 앞으로 나가기 시작하면 되돌릴 수 없다는 사실을 명심해두지 않으면 안 된다.


물론 내게도 작가나 작품에 대한 기호라는 것이 있다. 사람에 대한 기호도 있다. 하지만 그 옛날에 들었던 테네시 윌리엄스의 강의를 상기할 적마다 '역시 남에 대한 험담은 쓰지 말자.' 하고 절실히 생각한다. 그보다는 차라리 "이건 좋습니다, 아주 재미있습니다." 라고 말하고, 그와 똑같이 생각하고, 재미있다고 기뻐해주는 사람을 비록 소수라도 괜찮으니 발견하고 싶다. 이것은 와세다 대학 문학부가 내게 준 몇 안되는 산 교훈 중 하나이다.


그러나 오늘날의 이 즉흥적 사회에서 그런 유유한 태도를 유지하면서 살다 보면, 때때로 나 자신이 바보처럼 느껴질 때도 있다. 그보다는 목청을 높여서 통렬하게 누군가를 매도하는 쪽이 훨씬 더 스마트하게 보인다. 예를 들어, 작가보다는 비평가 쪽이 똑똑한 것처럼 보인다. 그렇지만 설령 개별 작가가 때로는 어리석게 보인다 하더라도(또 실제로 어리석다 하더라도), 무에서 뭔가를 만들어내는 작업이 얼마나 손이 가는 괴로운 작업인지를 몸소 경험하여 알고 있기 때문에, 그것을 한마디로 "저 녀석은 쓰레기다, 이건 허섭스레기다." 라고 매도해서 끝내버리는 일은 할 수 없다. 작품이 좋은 싫든간에. 이것은 작가로서의 내 생활 태도의 문제이며, 어떤 의미에서는 존엄의 문제이다.


 - 무라카미 하루키, 비밀의 숲 85, 86 페이지에서

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년 9월 5일 화요일

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;
    }

안드로이드 OBB 분할 관련 게시물 타래

이번 게임은 용량을 신경 쓰지 않은 탓에 100메가를 훌쩍 넘어버렸다.

사운드 리소스가 추가되면 더 커질텐데

스토어 등록에 대해서 고민을 하다가...


어차피 유료 패키지 게임이니까 다운로드 용량에는 신경쓰지 말고 만드는 것으로 고민

하지만 스토어 등록이 100메가를 넘으면 문제가 된다.


일단 구글 부터 해결 시도.

OBB 파일로 분할하여 빌드하는 기능이 유니티 5.5에 있어서 이것을 활용하기로 한다.

빌드 자체는 체크 박스 하나만 하면 되서 손쉬웠다.

참고링크 :
https://docs.unity3d.com/kr/current/Manual/android-OBBsupport.html



첫번째 문제
플레이스토어에 어디다가 분할 파일을 올릴 수 있지?

해결 -> 2번째 등록 (업데이트 APK 등록) 시에 분할 파일을 등록할 수 있는 항목이 추가된다.

처음에는 적당히 올리고, 빌드코드 2로 수정해서 새로 빌드하여, 업데이트 등록하면 된다.


두번째 문제
LoadResource Error

에셋번들처럼 뭔가 해줘야 하나?
구글 안드로이드 전용으로 플러그인이 있어서 이것을 최초 씬에서 로드하여 페치를 다운로드 받고 게임을 시작해야 한다.

작업 순서

1. 유니티 플러그인 다운로드
https://www.assetstore.unity3d.com/kr/#!/content/3189

2. 플러그인 폴더 내의 googleplaydownloader.cs 를 내 스크립트 폴더로 이동

3. googleplaydownloader 에 내 구글 개발자 계정의 Public Key를 코드에 추가

4. example 코드를 참고해서, 씬 처음에 부르도록 한다.

5. 내 경우는 obb 전용 씬을 하나 만들어서 먼저 모든 처리를 하고 게임 씬을 부르는 것으로 마무리

6. 스토어에 테스트 업로드 후 동작 확인 완료


사소한 문제는 있었지만, 생각보다 쉽게 적용할 수 있었다.

다음은 인앱결제를 적용해볼 예정이다.

2017년 8월 17일 목요일

Dell XPS 13 고주파음 제거 시도 (2) 펌웨어 업데이트

첫 글을 쓴지 얼마 되지 않았지만, 울며 겨자먹기로 아래와 같은 작업을 했다.

1. SSD를 다시 도시바 SSD로 복구 교체 - 10분

2. Dell Update 를 통한 Driver 최신 업데이트 - 15분
2-1. BIOS 업데이트
2-2. VGA 업데이트
2-3. Intel Chipset Driver Update

3. Dell 오류 체크 (간단, 고급 둘다 진행) - 20분 / 40분

어라?!
기분 탓인 것 같은데 2번의 BIOS 업데이트가 효과가 있는 것일까?
고주파 소음 (Coil Whine)이 없어진 것은 아닌데 참을 만한 수준으로 줄어든 것 같다.

일단 소유자 이전은 계속 진행 중이니 그 기간 동안 계속 써보는 것으로 해야지.

Dell XPS 13 고주파음 제거 시도 (1) SSD 교체 및 미국 워런티 한국으로 이전하기 (소유자 이전)

오늘은 뭔가 흔한 소비자의 글을 하나 써본다.

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

이번에 교체한 장비 DELL XPS 13 의 스펙을 한줄 요약 하면 아래와 같다.

DELL XPS 13 9350 13.3" QHD+ InfinityEdge TOUCH i7-6560U 16GB 512GB SSD
(2016년 스카이레이크 i7 모델 거의 풀옵)

스펙만 놓고보면 여기에 iris 그래픽도 탑재해서 무척 좋아보이지만,
어차피 울트라북 cpu 라 그렇게까지 날아다니진 않고 서브로 쓰기 딱 좋다.
코딩할 때 맘에 든다.

문제는 사용시에 지직 거리는 고주파음 (coil whine noise) 에 당첨이 되었다는 것.
뭐 어느정도는 있을 수 있다고 생각했기 때문에 그냥 쓰려고 몇주 사용했으나.
둔감한 편인 나에게도 참을 수 없는 소리란게 존재한다는 걸 알게 되었다 ㅠㅠ...
주관적인 측정이지만 동급 다른 모델들 보다 많이 나는 편인것 같다.


언제 노이즈가 나는지 확인해보려고 했는데,
대중없지만 디스크가 활발하게 움직일 때 많이 나는 것 같았다.
NVME SSD가 제일 큰 문제인가 싶다.

거기다가 이 SSD는 도시바제 인데,
sm961 > pm961 > Liteon > toshiba 이 상태의 뽑기에서 최하급이며
실제로 읽기/쓰기 성능이 많이 낮게 나온다 -_-...;;; (아 뭐지!? )

커뮤니티를 뒤져보니 기간 내에 딱 한번은 고주파음 관련으로 메인보드 교체가 가능하다고 하여 AS를 받아봐야겠다는 생각이 들었다.

헌데 문제는 미국 모델을 구입했기 때문에 AS 절차가 조금 귀찮다.
조금만 검색해봐도 나오는데 워런티 이전이니 뭐니 말 많고 복잡하며,
중고로 구입한 경우에는 더더욱 이전하기 힘들다 라는게 커뮤니티 사용자 들의 말이다.


음...  이거 쉽지 않겠다.

일단은 자력으로 해결을 시도해보았다.
SSD의 문제로 이걸 교체하면 괜찮아지지 않을까? SSD를 교체해보자.
어떤 커뮤니티 유저도 SSD를 교체하고 나아졌다는 사례가 있다.

삼성 SSD의 리테일 버전인 960 EVO를 구입해서 장착하기로 결심.
쌩돈이 나간다 ㅠㅠ... 그래도 작업을 위한 투자라고 생각해서 진행!

XPS 13의 하판은 T05H 드라이버 1개와 시계용 십자 드라이버 하나면 SSD는 교체할 수 있다. 다행히 예전에 구맥북프로 분해용으로 가지고 있던 드라이버를 찾아서 쉽게 분해했다.
난이도는 아주 쉬움. 작업 순서는 아래와 같다.

# 작업 순서 (XPS 13 Teardown 으로 구글링 하면 나오는 ifixit 의 게시물이 참고하기 좋다)
1. 기존 하드의 시작버튼을 눌러 복구 디스크 만들기를 클릭한다. (Windows 10 기능)
2. USB 16기가를 한개 연결해서 복구 디스크가 생성된 것을 확인하고 전원을 끈다.
3. 뒷판을 체결한 나사를 드라이버로 풀어낸다. (8개와 가운데 XPS 판넬을 들면 십자 나사가 하나 있다.)
4. 기타 피크 같은 얇은 플라스틱 판으로 뒷판을 분리 & 들어낸다.
5. 우측 하단의 배터리 연결 커넥터를 분리한다.. (혹시 모를 전기 충격 방지용)
6. SSD를 고정하고 있는 십자 나사를 돌려서 풀어낸다.
7. SSD를 살짝 위로 들어올려 빼내고 새로운 SSD를 장착한다.
8. 배터리 커넥터를 연결한 뒤, SSD 나사를 고정하고, 뒷판을 덮고 나머지 나사를 모두 체결한다.
9. 장치가 바뀌었다고 경고가 나올 수 있는데 F12 등을 눌러 Continue 를 선택한다.
10. 2에서 만든 USB 를 연결하고 부팅해서 윈도우를 재 설치한다.

윈도우 재설치 도중에 노이즈가 확 줄어든걸 보고 (거의 안나는 수준?)
흐뭇한 미소를 짓고 있던 나는 설치 완료 후 시작버튼을 누름과 동시에 좌절하고 말았다.

...

찌직찍찍...
왠지 예전보다는 줄어든 기분이 들지만 여전하게 찌직 거리는 잡음이 선명하게 들렸다.

아. 안되겠다. AS 시도해야겠어.

일단 Dell Support 에 서비스 코드를 조회해보니 2017 12월 까지 서비스 기간인 것을 확인해서 신청을 시도했다.


해당 기기의 서비스 지역이 미국이라서 진행이 어려웠다.
미국에서 구입한 물건이라 워런티를 국내로 이전해야 한다고 한다.
처리 시간은 10~15일 가량 걸리는 것 같은데, 신청한다고 다 되는 것도 아니고 최소한 전 소유자의 이름, 성, 우편번호를 알아서 신청해야 한다. 이게 틀리면 거절도 당한다고 하는군...

보통은 셀러들에게 연락하면 다 알려준다고 한다는데, 원래 구매자가 해외 구매고 시간이 지난터라 쉽지 않아서 걱정이 되었다.


다행히 친절한 전 주인에게 인터넷 영수증을 전달 받을 수 있었다.
이쪽 이베이 셀러에게 문의하여 워런티 이전을 진행하려고 했는데, 어느게 이메일인지 모르겠어서 한참 찾다 보니까 어떤 이메일의 주소가 maxmart.com 인 것을 발견.

왠지 쇼핑몰 같아서 접속해보니 역시 그랬다.
나름 규모가 있는 쇼핑몰 같아 보였고, contact 메뉴를 찾기 시작했는데...

이 쇼핑몰에 워런티 이전 요청이 자주 있었기 때문인지 모르겠으나,
아예 워런티 이전 신청 메뉴가 따로 있는 것을 발견!

여기의 입력폼에 내 이메일로 정보 구독을 신청하니 이름, 성, 우편번호가 나온다.
(단순히 정보만 가르쳐주면 되는거 같은데 내 이메일은 왜 수집해가는거야 이거 -_-;; )

어쨌든 정보를 입수했으니 이 정보를 가지고 Dell 홈페이지에 신청했다.

# 소유권 이전 신청 링크
https://www.dell.com/support/assets-transfer/kr/ko/krbsd1#/Identify

적당히 정보를 집어넣고 나니 신청이 완료 되었다고 나온다.
15일 후에 처리가 완료되면 방문 혹은 출장으로 AS 신청을 해서 교체를 받아볼 생각이다.

그 때는 고주파음 제거 시도 (2) 로 글을 올려야지...

[마무리]-----------------------------------------------------------------------------------------

아... 제 가격에 산 물건이 아니면 역시 공이 많이 들어간다 -_-;
잘 마무리가 되면 좋겠네... ㅠㅠ...

coil whine 문제 빼고는 문서 / 코딩 등등의 사용에 편하고 좋은 느낌이라 맘에 드는 물건이다.

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

MacBook 에서 XPS로...

의욕적으로 구입했던 맥북프로 2016 15인치 터치바에서
XPS 13 으로 이전할 결심을 굳혔다. 이유는...

1. 맥북프로가 자기 몸값을 못하는 것 같다. 이렇게 고사양 모델을 구입할 필요가 없구나.
(다음에 구입하게 되면 절대로 엔트리 모델에 SSD만 올려서 사야겠다. )

2. 빌드 퀄리티가 그렇게 좋다는 XPS 한번 써보고 싶다.

3. 요새 개발환경 윈도우도 괜찮은거 같다. (+ 내 회사 업무 환경과 같다...)

4. XPS 에 썬더볼트 단자가 있어서 eGPU 를 장착할 수 있기 때문에 추후 업그레이드가 가능하다. (전송속도는 반토막이라고들 하지만... 그게 어딘가?! )

2017년 7월 26일 수요일

어떤 오브젝트의 Mirror 된 회전 값은? (쿼터니언 거울 반전)

쿼터니언으로 미러링 할 때 메모

오일러앵글이 아니라 쿼터니언의 회전은 이해하기 어려울 수 있다.
회전각을 반전시키는 것은 더더욱...

예를 들기 위해 obj의 로컬로테이션을 미러하고 싶다고 가정했다.

보통은 아래와 같이 생각하지만,
new Quaternion(obj.localRotation.x * -1.0f, obj.localRotation.y, obj.localRotation.z, obj.localRotation.w);

실제로는 아래와 같아야 하고,
new Quaternion(obj.localRotation.x * -1.0f, obj.localRotation.y, obj.localRotation.z, obj.localRotation.w * -1.0f);

위도 비슷하지만 비틀림이 있기 때문에 아래와 같이 사용하는 것이 옳다.
new Quaternion(obj.localRotation.x, obj.localRotation.y * -1.0f, obj.localRotation.z * -1.0f, obj.localRotation.w);

참고 URL : https://www.gamedev.net/forums/topic/599824-mirroring-a-quaternion-against-the-yz-plane/


추가 메모  :
카메라 방향이 그대로 일 때 어떤 오브젝트의 이동과 회전을 거울 반전시키려면
포지션 x 축도 바꿔준다. (localPosition.x * - 0.1f)

2017년 6월 23일 금요일

Unity 에서 쓸 수 있는 CSV Reader (C#)

간단히 스트링 저장해놓고 불러 쓰는 용도로 사용하려고 준비...
개행은 \n이 아니라 br 태그로 사용하도록 만듬.

# CSVReader Class

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class CSVReader
{
    static string SPLIT_RE = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";
    static string LINE_SPLIT_RE = @"\r\n|\n\r|\n|\r";
    static char[] TRIM_CHARS = { '\"' };

    public static List<Dictionary<string, object>> Read(string file)
    {
        
        var list = new List<Dictionary<string, object>>();
        TextAsset data = Resources.Load(file) as TextAsset;


        var lines = Regex.Split(data.text, LINE_SPLIT_RE);

        if (lines.Length <= 1) return list;

        var header = Regex.Split(lines[0], SPLIT_RE);
        for (var i = 1; i < lines.Length; i++)
        {

            if (lines[i].Replace(" ","").Substring(0, 2) == "//")
            {
                Debug.Log(lines[i]);
            }
            else
            {
                var values = Regex.Split(lines[i], SPLIT_RE);
                if (values.Length == 0 || values[0] == "") continue;

                var entry = new Dictionary<string, object>();
                for (var j = 0; j < header.Length && j < values.Length; j++)
                {
                    string value = values[j];
                    value = value.TrimStart(TRIM_CHARS).TrimEnd(TRIM_CHARS).Replace("\\", "");
                    value = value.Replace("</ br>", "\n");
                    value = value.Replace("</ comma>", ",");
                    object finalvalue = value;
                    int n;
                    float f;
                    if (int.TryParse(value, out n))
                    {
                        finalvalue = n;
                    }
                    else if (float.TryParse(value, out f))
                    {
                        finalvalue = f;
                    }
                    entry[header[j]] = finalvalue;
                }
                list.Add(entry);
            }
        }
        return list;
    }
}


#사용법
csv 파일을 하나 만든다 내용은 아래와 같다.

key,value
a,a value
b,"b, value"
c,"c</ br>line break"
Assets/resources/kpaper.csv 에 파일이 있다고 가정하고 아래 코드 실행

List<Dictionary<string,object>> data = CSVReader.Read ("kpaper");
 
        for(var i=0; i < data.Count; i++) {
            Debug.Log ("key " + data[i]["key"] + " " +
                   "value " + data[i]["value"]);
        }









2017년 6월 20일 화요일

Unity 엔진 난독화 도구 Obfuscator


최근 개발 중인 프로그램의 출시 시즌이라 이래저래 배포 문제를 해결하고 있다.

유니티로 개발한 프로그램은 Managed\Assembly_cshap.dll 파일에 C#으로 짠 코드 대부분이 쉽게 보이게 되는 문제가 있다.
쉽게 코드를 보고 변조할 수 없도록 Encryption 을 걸면 좋겠지만, C# 특성상 적용이 어렵다.

최소한 난독화라도 걸고 출시해야 할 것 같아서 여러가지 솔루션을 찾아봤는데...
난독화 도구로는 아래 에셋이 좋은 것 같다. (JJ 감사합니다.)

옵션은 조금 만져줘야 하지만, 크게 손이 안가고 가장 편하고 확실한 느낌이다.
(물론 맞춰서 코드도 조금 고쳐야 하긴 했지만)



사용법은 구입 -> 설치 -> Editor\Beebyte\Obfuscator\ 안의 옵션 파일을 설정해주면 된다.

2017년 6월 13일 화요일

Unity 개발 팁, 자식 게임 오브젝트 찾기 간단 팁

자식찾기 간단 팁

보통은 GameObject.Find("string Object Name")을 사용하지 말라고 여기저기 나와있다.
성능 이슈가 있으면 개선하는게 맞지만,
굳이 개발 편의를 위해 있는 기능을 무조건 지양하는 것도 옳지 않은 것 같다.
코드가 줄어들 수 있고, 이해하기 쉽다면 어느정도는 적극 사용하는것도 좋겠지.

예를 들어 어떤 부모 오브젝트의 자식중에서 라고 한정해서 찾는다면 어떨까?
이것도 너무 빈번하게 찾는다면 문제가 되겠지만, 적은 수에서라면 비교적 덜 문제가 되지 않을까?
이를 시험해서 성능 평가 까지 적으면 좋겠지만, 시간이 없어서 테스트 코드만 간단히...

// 아래와 같이 자식 오브젝트에서 이름을 적은 녀석을 데려올 수 있다.
// transform의 하위에서 이름으로 찾고 그녀석의 gameobject 를 반환한다.
GameObject childObject GameObject.transform.Find("string Child Name").gameobject;

여기다가 SendMessage() 같은걸로 뭔가 동작시켜줄 수 있겠지.

이 두개를 사용하면 아이템 리스트와 하위 아이템을 좀 더 각각 독립적으로 만들어주는데 유용해서 은근히 쓰고 있다.

2017년 5월 29일 월요일

Unity 개발 팁 - isDebugBuild, EditorOnly Tag

빠르게 개발 할 때 많이 사용하고 있는 것이 있어서 개발팁으로 남긴다.

#1
Debug.isDebugBuild
빌드가 디버그 빌드라면 true 를 반환 하기 때문에 여러가지 확인용으로 사용할 수 있다.

샘플 코드

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    void Example() {
        if (Debug.isDebugBuild)
            Debug.Log("This is a debug build!");
        
    }
}

참고 문서
https://docs.unity3d.com/ScriptReference/Debug-isDebugBuild.html


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

#2
게임 Obeject의 Tag를 EditorOnly 로 지정하면
해당 오브젝트는 Editor 상에서만 사용하고,
실제로 빌드하면 해당 태그가 지정된 오브젝트는 제외되고 빌드되어 편리하다.
테스트용으로 필요하여 하이어라키에 추가해둔 오브젝트를 일일히 삭제할 필요가 없다.

2017년 5월 25일 목요일

Unity 키보드로 히든 키 입력하기

특정 키를 입력받고 있다가 정답이 되면 true 를 돌려주는 간단한 코드.
Start()에 입력된 값을 바꾸거나, Inspector 에서 적당히 미리 정답 값을 입력해두면 된다.

재미로 만들었다. 어딘가에 적당히 써보자.

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

public class HiddenKeyInput : MonoBehaviour {

    public bool _key = false;

    public List _pool, _seikai;

    void Start()
    {
        // 정답
        // 왼쪽시프트 + 상하좌우AB 를 순서대로 누른다.
        // _key 가 트루가 된다.
        // 시프트를 떼면 리셋, _key 가 false 가 되고 _pool 에 쌓여있던 내용도 초기화 된다.
        _seikai.Add("상");
        _seikai.Add("하");
        _seikai.Add("좌");
        _seikai.Add("우");
        _seikai.Add("에이");
        _seikai.Add("비");
    }

    // Update is called once per frame
    void Update () {

        if (Input.GetKey(KeyCode.LeftShift))
        {
            if (Input.GetKeyDown(KeyCode.UpArrow))
            {
                _pool.Add("상");
                Debug.Log("상");
            }
            if (Input.GetKeyDown(KeyCode.DownArrow))
            {
                _pool.Add("하");
                Debug.Log("하");
            }
            if (Input.GetKeyDown(KeyCode.LeftArrow))
            {
                _pool.Add("좌");
                Debug.Log("좌");
            }
            if (Input.GetKeyDown(KeyCode.RightArrow))
            {
                _pool.Add("우");
                Debug.Log("우");
            }
            if (Input.GetKeyDown(KeyCode.A))
            {
                _pool.Add("에이");
                Debug.Log("에이");
            }
            if (Input.GetKeyDown(KeyCode.B))
            {
                _pool.Add("비");
                Debug.Log("비");
            }

            if (_seikai.Count == _pool.Count)
            {
                
                for (int i = 0; i < _seikai.Count; i++)
                {
                    if (_seikai[i] == _pool[i])
                    {
                        if (i == _seikai.Count - 1)
                            _key = true;
                    }
                    else
                    {
                        break;
                    }
                }

            }
            
        }
        else
        {
            if (_pool.Count > 0)
            {
                _pool.Clear();
            }
            _key = false;
        }
  
 }
}

2017년 5월 15일 월요일

uGUI EventSystem 을 이용한 Mouse Hover Check

윈도우 프로젝트를 하고 있다보니 마우스 포인터를 감지할 일이 생겼다.
깔끔하고 쉬운 것으로는 Unity 에서 제공하는 컴포넌트를 사용하면 된다.

[1]
Event Trigger 를 이용하여 Pointer Enter / Exit 로 체크하는 방법.
사용할 uGUI 캔버스 안의 UI 오브젝트를 고른다. (hit 가 가능해야 함.)
Add Component 를 눌러서 Event Trigger 컴포넌트를 붙인다.
원하는 이벤트를 사용한다.

[2]
Event System 을 이용하여 전체적으로 확인하는 방법
특정 영역이 아니라 윈도우 안에 액티브 되었는지 확인이 필요하면
EventSystem 에서 IsPointerOverGameObject() 를 통해 확인할 수 있다.
아래는 샘플 코드이다.

public class KpaperTest_EventSystemHover : MonoBehaviour {

    public EventSystem _eventsystem;

 // Use this for initialization
 void Start () {
        _eventsystem = GameObject.Find("EventSystem").GetComponent();

    }
 
 // Update is called once per frame
 void Update () {

        if (_eventsystem.IsPointerOverGameObject())
            Debug.Log("Active!!!");

    }

2017년 5월 12일 금요일

uGUI 에 Image 를 표시하고 Sprite Animation 을 하자

uGUI 에 표시할 수 있는 스프라이트 이미지에는 애니메이터를 붙여도 애니메이션이 되지 않는다.
비용 부담을 신경 쓰지 않고 간단하게 애니메이션을 표시하는 방법으로
SpriteRenderer 로 넘겨주는 Sprite 이미지를 매 업데이트 시점마다 Image 에도 뿌려주면 잘 나온다.

샘플 코드를 해당 image 오브젝트에 붙여두자.
(애니메이터와 스프라이트 랜더러도 붙어있어야 한다.)



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


public class SpriteRendererToUguiImage : MonoBehaviour {

    [SerializeField]
    private SpriteRenderer _spriteRenderer;

    [SerializeField]
    private Image _image;


 // Use this for initialization
 void Start () {

        if (_spriteRenderer == null)
            _spriteRenderer = this.GetComponent<SpriteRenderer>();

        _spriteRenderer.enabled = false;

        if (_image == null)
            _image = this.GetComponent<Image>();

 }
 
 // Update is called once per frame
 void Update () {

        _image.sprite = _spriteRenderer.sprite;
  
 }
}

2017년 5월 8일 월요일

새 게임 Live2D 모델링 중간 과정

새로 만들고 있는 게임(?)의 모델링 중간 과정
여러가지 시행착오도 겪고 팀원들끼리 감정도 조금씩 닳고 있고
 여러가지를 소모하면서 그래도 열심히 오늘도 게임을 만들고 있다.
 누군가가 재밌어 해주면 정말 좋겠다.
 개발 도중의 스크린샷 (여주인공) Vertex 가 선택된 화면만 보니 왠지 조금 무섭다. ^^;;

하지만 애정(?)을 담아 만들고 있으니까
그래도 비쥬얼은 볼만한 작품이 나올 듯
원화가 친구가 엄청 분발해주고 있어서 나도 자극이 된다.


2017년 5월 2일 화요일

도메인 갱신 실수! (으악)

어느날 갑자기 블로그가 접속이 안되서 일시적인 문제인가 하고 넘어갔는데, 아뿔싸... kpaper.com 도메인 만료일이 지났다. 황급하게 복구 신청. 몇일 뒤면 원래 블로그 주소인 blog.kpaper.com 로 접속이 가능해질 듯..

2017년 4월 25일 화요일

FBX Animation 및 Key Event를 사용하기

최근 작업 중에 3D 캐릭터의 애니메이션 재생이 필요했는데,
상황이 닥치면 하려고 신경쓰고 있지 않다가,
가이드가 살짝 필요한 상황이 되어서 간단히 남겨본다.

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

Unity 는 FBX 파일의 애니메이션 재생이 가능하다.
하지만, FBX 파일 그대로는 ReadOnly 라서 이것을 따로 복제해서 사용해야 한다.

시간이 없어서 일단 글만 먼저 정리!

[FBX 에서 애니메이션 파일을 가져오기]

1. 캐릭터 모델 데이터와 애니메이션 FBX 를 준비한다. (맥스, 마야, 블렌더 등등)

2. 1을 Unity Asset 폴더에 넣는다.

3. Unity 내 Project 탭에서 애니메이션 FBX 를 클릭해서 드롭다운 메뉴를 연다.
Animation 아이콘이 보이면 이것을 Control + D 해서 복제 한다.

4. Hierarchy 에 사용할 3D 캐릭터 모델을 배치

5. 해당 모델에 Animator 를 세팅

6. Animator 에서 움직일 Animation 을 3에서 복제한 Animation 파일로 지정한다.
(FBX 파일 내에 있는 것 말고 복제해서 밖에 생긴 것을 지정)

7. Unity 내에서 WIndow > Animation 탭을 연다.

8. Animation 탭이 열린 상태로 Hierarchy 의 모델 데이터를 클릭하면, 현재 적용된 Animation 을 확인할 수 있고 유니티 내에서 수정도 가능하다.

9. 끝


[Animation Frame에 Key Event 넣기]

FBX 파일 그대로 사용하기는 불가능 (Read Only)하기 때문에 먼저 애니메이션 파일을 복제해두어야 한다. (위 부분 FBX에서 애니메이션 파일을 가져오기를 먼저 한다.)

1. 적당한 C# 스크립트를 하나 만든다.
Ex) AnimationEventManager.cs
public void KeyEventReceiver(GameObject _obj)
        {
            Instantiate(_obj, this.transform, false);
        }

2. 만든 스크립트를 사용할 모델의 게임오브젝트에 add 한다.
(Animator가 붙어있는 gameObject)

3. Unity > Window > Animation 탭에서 Key Event 를 붙이고 싶은 Animation 을 선택한다.

4. Add Key Event 를 선택

5. 만들어진 Key를 클릭해서 Inspector 를 보면 호출할 함수를 풀다운 메뉴에서 선택할 수 있다. (만일 안되면 아까 그 키를 오른 클릭해서 Edit Key Event 선택)
여기에서 아까 만든 스크립트의 KeyEventReceiver() 를 선택한다.

6. 같은 화면의 GameObject 패러미터에 해당 이벤트 동작 시마다 생성할 프리팹을 끌어다 놓는다.

7. 끝.


참고 페이지 : https://docs.unity3d.com/Manual/animeditor-AnimationEvents.html

2017년 4월 24일 월요일

일본의 샘플 코드에 자주 보이는 Hoge 의 의미. (메타구문변수명)

일본쪽 개발서나 개발 블로그를 참고하는 경우가 많은데,
이쪽 분들은 일본어를 로마자로 적어서 변수명 따위에 사용하는 경우가 많다.

대표적인 것이 name 이라는 변수가 있으면 namae 로 적는다던가.
(오타가 아닌 것... 일본어 名前 = 이름 = name 이다)

대부분 알아보는데 크게 문제는 없는데,
대충 무슨 뜻인지는 알겠는데, 사전에도 없는 이상한(?)게 있어서 오늘은 큰맘 먹고 알아보았다.

바로 "HOGE" 넌 뭐냐..

일단 일본어 사전을 검색해봤다.
비슷한게 안 나오네...
이외나 의외 아니면 그 외 아무거나 이런 뜻인줄 알았는데...

근처 일본인에게 도움을 청했다.

HOGE 가 뭡니까?!
대충 이런 느낌으로 쓰고 있는데요. 라며 샘플 코드 전달.

void Hoge()
{
    StartCoroutine(HogeProcess());
}

난 프로그래머가 아니라 잘 모르지만 알아볼게~ 라시던 분이 의외로 금방 답변을 해주셨다.

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

「ほげほげ」の由来は、「hogehoge」というメタ構文変数です。メタ構文変数とは、サンプルプログラムなどで意味のない名前が必要な場合に利用される、「意味のない名前」のことです。

入力する文字列は何でもいいのだけれど、入力しなければエラーになっていまう…という場合に用いられたのが「hoge」もしくは「hogehoge」です。

"ほげほげ"의 유래는 "hogehoge"라는 메타 구문 변수입니다. 메타 구문 변수는 샘플 프로그램 등으로 의미가없는 이름이 필요한 경우에 사용되는 "의미없는 이름"입니다.

입력 문자열은 무엇이든 좋은 것이지만, 입력하지 않으면 에러가 되어버리는... 경우에 사용 된 것이 "hoge"또는 "hogehoge"입니다.

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

흠흠 그렇군.
이제 뭔지 알았으니 조금 더 찾아봤다.

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

プログラミング言語では識別子(変数関数などの名前のこと)を自由に定義できるが、サンプルプログラムなどでまったく意味の無い変数に適当な名前がなく困ってしまうことがある。しかしどんな名前でも構わないからといって「wikipe」などとつけると、そのプログラムを見た他の人はその変数に何の意味があるのかと悩むことになる。そのようなときに、「abcd」や「hoge」(ほげ)をはじめとするメタ構文変数を利用する。メタ構文変数はプログラマの間でサンプル用の意味が無い変数名であることが認知されているので無用な混乱が避けられるほか、書く側も苦労して名前をひねりだす必要がなくなる。

프로그래밍 언어에서 식별자 (변수 나 함수 등의 이름에 대한 것)을 자유롭게 정의 할 수 있지만, 샘플 프로그램 등에서 전혀 의미없는 변수에 적당한 이름이 없어서 곤란 해 버릴 수있다. 그러나 어떤 이름이라도 상관 없다해서 "wikipe"라고 쓰면 그 프로그램을 본 다른 사람은 그 변수에 무슨 의미가 있는지 고민하게된다. 그런 때, "abcd" 또는 "hoge"(호게)를 비롯한 메타 구문 변수를 이용한다. 메타 구문 변수는 프로그래머 사이에서 샘플에 대한 의미가없는 변수 이름 인 것으로 알려져 있기 때문에 불필요한 혼란을 피할 수 있으며, 쓰는 사람도 고생해서 이름을 쥐어짤 필요가 없어진다.

출처  위키피디아

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

역시 별거는 아니었는데, 알고나니 묵은 체증이 풀린 느낌이라 좋다. :D

근데 좀 배신감(?)이 드는 것은...
오히려 Hoge 가 무슨 의미인가 고민하게 되었던 내 입장에선 조금 억울하네... (하하하)

2017년 4월 5일 수요일

Unity 엔진에서 Mesh 만들기 기본

이번에 좀 복잡한걸 (사람 얼굴 ㅠㅠ) 직접 그려야 하는 일이 발생하여,
귀찮음에 울면서 했다.

사실 Mesh 생성 방법 자체는 간단하다.

1. MeshFilter 를 생성
2. MeshRenderer 를 생성
3. MeshFilter 에서 Mesh 를 _mesh 등으로 가져온 뒤
4. 정점을 찍고,
5. uv 를 설정하고,
6. 삼각형을 그려준다. 이 때 그리는 순서에 따라서 앞뒤가 바뀌니까 주의.
만일 그린게 어디갔는지 보이지 않으면, 카메라를 돌려보자 반대로 그려져있을 수 있다.

1까지는 그럭저럭 금방했는데,
2와 3은 노가다로 열심히 맞춰서 만들었다.. -_-;
삼각형을 잘 그려야 한다. <-

아래는 삼각형을 그리는 예제.
void Start(){


        gameObject.AddComponent<MeshFilter>();
        gameObject.AddComponent<MeshRenderer>();
        _mesh = GetComponent<MeshFilter>().mesh;

        // 그릴 값을 입력.
        mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0) };
        mesh.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1) };
        mesh.triangles = new int[] { 0, 1, 2 };

}

새 공유기 ASUS RT-AC68U 속도 테스트



유선 속도 측정. 매우 만족스럽다.
무선은 좀 더 테스트 한 후에 업데이트 하는 것으로...

과거에 쓰던 RT-AC56R 에 비해서 대충 160% 성능 향상이 있는 것 같다.



현재 이런 상태로 설치되어 있다.
안테나를 포함해서 백스테이지 같은 느낌으로 뭔가 미묘하게 잘 어울린다.
(...)

사실은 68 말고 88 시리즈로 해서 건담 발판으로 쓰고 싶었다.


2017년 4월 4일 화요일

마스크 오브젝트 쉐이더 간단하게 만들기

역시 일단 먼저 해봐야 해.

Unity 엔진 내에서 Shader 를 하나 만들고 아래의 코드를 입력한다.
그리고 Material 도 새로 만들어 조금전에 만든 Shader를 선택
(아래 코드는 Kpaper/MaskObj )

마스킹 오브젝트를 이용해서 AR 컨텐츠를 만드는데 사용하면 된다.

참 쉽죠?


Shader "Kpaper/MaskObj" {
 SubShader{
  // regular geometry 이후에 마스크를 render 한다.

  Tags{ "Queue" = "Background" }

  // RGBA 채널을 그리지 않는다, Depth buffer 로만 사용

  ColorMask 0
  ZWrite On

  // 패스에서는 아무것도 하지 않는다.

  Pass{
 }
 }
}


2017년 3월 28일 화요일

Asus 라우터 rt-ac66u 구입 (배송중)

일본 아마존 공식 판매 계정에서 1400엔 쿠폰 + 결제시 2000엔 쿠폰 덕분에
해외 직 배송비 포함 1만엔 아래가 되기에 구입했다.

요새 사용중이던 공유기가 불안정해서 자주 리부팅하고 있는데...
이참에 교체하면 될 것 같다.

4월 중순 즈음 도착할 듯 하며, 자세한 포스팅은 그 때 다시 ^^;;


참고로 미국 티모바일용 모델인 tm-1900과 같은 모델이지만
정식 제품이고(펌웨어교체 불필요) 신품이라는 점이 메리트이다.

구매링크
https://www.amazon.co.jp/gp/product/B00GJIEYBI/ref=ox_sc_act_title_1?ie=UTF8&psc=1&smid=AN1VRQENFRJN5

2017년 3월 24일 금요일

Mac 용 Blender에 Addons 설치하는 법 (경로)

Mac 용 Blender에 Addons 설치하는 법

윈도우는 설치 폴더에 Addons 폴더를 찾기 쉬웠는데,
맥에서는 따로 Addons 경로 변경 환경설정을 해봐도 원하는대로 잘 되지 않았다.
패키지 안에 복사해주면 간단하게 해결된다.

응용 프로그램안의 Blender를 패키지 내용 보기(Show Package Contents)로 탐색하여 아래의 경로에 애드온을 복사한다.
Blender.app/Contents/Resources/2.76/Scripts/Addons/


# 초보자는 아래 순서대로 따라하면 된다.
1. 응용 프로그램에서 Blender.app 를 찾아서 오른 클릭
2. 패키지 내용 보기 클릭
3. Contents 클릭
4. Resources 클릭
5. 2.76 (혹은 준하는 버전 번호) 클릭
6. Scripts 클릭
7. Addons 클릭
8. Addons 폴더 안에 원하는 플러그인 복사하기


2017년 3월 22일 수요일

Unity 오브젝트에 주석을 달아버리는 간단한 팁

유니티 작업이 좀 많아져서 주석이 필요한 오브젝트에 붙여두고 싶었다.

에디터 편집 코드를 짜서 멋지게 만드는 것도 좋지만. (ex : OnInspectorGUI() 등을 이용)
시간이 부족할 때 가성비가 안좋으니 아래와 같이 해본다.

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


// 파일 명은 GameObjectComments.cs 로 해야 한다.

using UnityEngine;
using System.Collections;

    /// 
    /// 게임오브젝트의 인스펙터에 코멘트를 추가한다.
    /// 
    public class GameObjectComments : MonoBehaviour
    {

        /// 
        /// 주석 3줄까지는 바로 보인다.
        /// 
        [Multiline]
        public string text;
    }

요런식으로 여기저기 붙여두면, 빠르게 많이 만들어서 헷갈릴 때 도움이 될 주석을 달아두어 편하다.
하지만 3줄이 넘어가야 한다면, 에디터 코드를 만들어서 보기 좋게 하는 편이 좋다.

2017년 3월 21일 화요일

Unity3D WebCamTexture 를 ByteArray(Color32) 로 가져오기

처음에는 별거 아닌 줄 알았다.
(해보니까 헬게이트가. ㅠ_ㅠ)
이것 때문에 몇 일 야근하면서 삽질했었기에 기록을 남긴다.

----------

Unity3D 에서 웹캠텍스쳐를 만들어 초기화 할 때,
Request 한 해상도에 근접한 해상도를 리턴한다.
웹캠 장치 몇개를 테스트 했더니 의외로 640x480 이 지원 안되는 캠이 있더라.
(PC는 캠도 다양하고 그 캠의 스펙도 다양하다라는건 뻔히 알고 있었으나 막상 당하니 낭패... )

거기다가 문제는 WebCamTexture.GetPixels32() 요게 되다가 안되다가 한다.
구글 선생님한테 물어보아 찾아봐도 별달리 해결책은 없었는데..

Unity3D WebCamTexture.GetPixels32() 참고 문서
https://docs.unity3d.com/ScriptReference/WebCamTexture.GetPixels32.html


어떤 식으로 잘 안되는가 하니,
리턴된 Color32 Array를 확인해보면 무조건 RGBA(0,0,0,255) 가 출력되고 있다.

전부 문제가 있는 것은 아니고 웹캠마다 다르고, 그 웹캠의 지원해상도 마다 다르다.
(의외로 XspliteBroadCaster 의 가상 카메라는 다 잘되더라.)

여러개로 시험해본 결과 모델과 해상도 조합을 맞춰야 값을 받아올 수 있는 희한한 상태였다.
이대로는 문제가 있기에 확실하게 사용할 수 있는 해결 방법이 뭐가 있을까 알아봤는데...

결국 내가 선택한 해결 방법은 아래와 같다.
encode2png 를 이용하는 방법이다.


// 사용법 ConvertPNGBytesToBGRABytes(_texture2D.encode2Png());

    private byte[] ConvertPNGBytesToBGRABytes(byte[] data)
    {
        if (data == null || data.Length < 1)
            return null;

        byte[] buffer = new byte[_webcamTexture.width * _webcamTexture.height * 4];

        using (System.IO.MemoryStream ms = new System.IO.MemoryStream(data))
        {
            Bitmap bmp = new Bitmap(ms);
            Rectangle rcBitmap = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData rData = bmp.LockBits(rcBitmap, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Marshal.Copy(rData.Scan0, buffer, 0, buffer.Length);
            bmp.UnlockBits(rData);
        }

        return buffer;
    }


이 방법은 부담이 좀 되긴 하는데, 문제없이 잘 출력되고 있다.
프로젝트 완료까지 시간이 없어서 다음에 좀 더 고민해서 개선하는 것으로 -.,-;;

2017년 3월 17일 금요일

이번에 볼 책들 2017.03


이번에 필요에 의해서 볼 책들...
업무적으로도 개인 프로젝트로도...

2017년 3월 16일 목요일

Unity Remote 5 iOS 연결하기

유니티 리모트라는 앱은 알고 있기는 오래 됐는데,
생각보다 잘 동작하지 않는 느낌에 그다지 활용하고 있지 않았다.

우연히 유니티 리모트를 이용한 터치이벤트 확인에 관한 글을 보다가 (https://eastfever.blogspot.kr/2017/02/unity3d-unity-remote.html)

유니티 리모트 버전 5가 나왔었음을 깨닫고 한번 테스트 해보았다.

와우...!
일단 디자인이 예전보다 훨씬 볼만해졌다.
유니티5로 통일된 깔끔한 디자인!
뭔가 좋아보인다.

사용법도 더(?) 간단해졌는데,
Edit > Project Settings > Editor 에 들어가서 Device를 세팅하면 끝이다.

기본적으로는 내 아이폰이 보이지 않는다.
유선으로 연결하면 풀다운 리스트에 나타난다.
내 경우는 굳이 유니티를 재시작하지 않아도 표시되었다.


복잡한 설정 없이 케이블만 연결하고 바로 쓸 수 있는 점은 좋지만,
아무래도 압축된 화면이라 그래픽이 깨져보이거나, 
터치했을 때 폰에서 보이는 반응이 늦는 것은 어쩔 수 없다.

터치 이벤트만 받고 유니티에서 돌아가는 것을 보는 방식으로 사용하거나,
빌드 시간을 아껴서 초기기동 문제 확인 하는 정도로 사용하면 좋을 듯 하다.

MacBook Pro, iPhone 6s+ 에서 확인

2017년 3월 15일 수요일

if (Debug.isDebugBuild) - Unity3D 사소한 팁

오늘은 정말 사소한 팁
개발 하던 도중에 디버그로그를 많이 찍어놨을 때,
여러가지 방법으로 빌드 할 때 제외하거나 할 수 있지만,

빌드 결과물에만 출력되지 않게 미리 조치하려면 아래와 같이 간단한 방법이 있다.



using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    void Example() {
        if (Debug.isDebugBuild)
            Debug.Log("This is a debug build!");
        
    }
}


참고 링크 : https://docs.unity3d.com/ScriptReference/Debug-isDebugBuild.html

물론 if 를 한번 타게 되기 때문에 비용은 조금 늘겠지만,
편하고 빠르게 만들자라는 컨셉에서는 쓸만한 팁인듯.
이런걸 지저분하고 빠른 방법이라고 부르면 될 것 같다.



2017년 3월 11일 토요일

Synology Raid Calculator 시놀로지 레이드 계산기 - 용량 계산 할 때 편리!

기존에는 수동으로 NAS의 RAID 와 사용 용량을 관리했었는데,
개인용 스토리지다 보니 비용상 관리상 문제로 업무용 스토리지처럼 딱딱 투자하기가 어렵다.

과거에는 무척 열심히 관리했었는데 지금은 용량도 커지고 여러모로 무리.
그래서 증오하던(?) SHR (시놀로지 하이브리드 레이드)로 변경하려고 결심
당장은 힘들고, 일단 임시 하드로 새로 구성하려고 계산기를 두들겨 보았다.


계산에 도움을 주는 웹사이트가 있어서 북마크.

https://www.synology.com/en-us/support/RAID_calculator



필요한 하드를 선택해서 장착하면, 각종 레이드를 적용했을 때 실 가용 용량과 디스크 복구에 사용되는 용량을 보여준다.

SHR1의 장점은 서로 다른 용량의 디스크로 레이드를 시도해도 대체적으로 가능한 한 큰 용량을 사용할 수 있게 해주는 점이다.

거기다가 유지보수에도 용이 한데
추후 하드를 업그레이드 해야 할 일이 있어도 별도의 추가 스토리지 머신 없이
디스크를 작은 용량 부터 한장 빼고 교체 후 복구 하는 방식으로 모든 디스크를 교체 하면
더 큰 용량의 새 디스크로 교체할 수 있게 된다.
(사실 이부분은 Raid5랑 같다 ^^;; )

초보자 or 귀찮은 사람에게는 대부분 유리한 SHR 이지만,
큰 주의사항이 몇개 있으니... 그것은...

[1] 새 디스크를 추가하려고 빈 디스크를 넣으면 자동으로 멋대로 하나의 스토리지로 엮어버린다.
물어보지도 않고 진행한다... <- 이 부분이 위험..

[2]
디스크 2개를 연결하면 무조건 Raid1로 시작한다.
전체 용량의 50% 를 복구용으로 사용해버리니 개인 사용자에게 타격이 크다.

2017년 3월 6일 월요일

Blender 2.77 테스트


무료로 3D 작업을 할 수 있는 Blender 가 많이 좋아졌는데,
기존의 Maya 쓰던 습관 때문에 쉽게 접근하지 못했다.

최근에 Grease Pencil 데모를 보다가 다시 한번 도전하기로 결정.

Maya 2017 의 복잡한 UI를 보다가,
Blender를 보니 이건 오히려 정갈한 것 같다.

그런데 사용법을 모르겠는
창의적인(?) UI 가 조금 있어서 어렵긴 한데...
막상 해보니 대충 감이 오긴 온다.

테스트로 Shape Keys 를 해봤는데, (마야의 BlendShape)
생각보다 더 간단하게 되서 당황...
(왜 더 편한 느낌이지... )

작업 편의성이 걱정이었지만...
자주 쓰는 숏컷 qwer 은 Maya 의 프리셋에 맞출 수 있어서 다행이다.
(의외로 이런 사소한게 불편해서 문제다. ㅠㅠ)

앞으로 3D 모델 작업 진행 방법은
 건물이나 구조물은 스케치업으로 제작
캐릭터는 블렌더로 제작
그 외 오브젝트 류는 일단 블렌더로 먼저 손을 대보고 판단하는 것으로..

 ^^;

언제 다 익혀서 언제 써먹나 싶지만.
도전할 것이 있는 것은 좋다.




2017년 3월 5일 일요일

Macbook Pro 15 2016 Late 부트캠프 AMD Fluid Motion 적용 가능

작년 12월에 구입해서 부트캠프를 설치하고,
영상 재생을 위해 플루이드 모션 옵션을 사용하고 싶어서 제어판을 열었는데

AMD 제어판에서 플루이드 모션 옵션을 찾을 수가 없었다.

그 때는 해킹 드라이버를 덧 씌워서 해결했었는데...
이번에 Xsplit Broadcaster 문제를 확인하기 위해
윈도우 운영체제를 재설치 했더니

제어판에서 바로 확인할 수 있게 바뀌어 있었다.
굳이 불안한 해킹드라이버 같은 것 설치하지 않아도 되서 다행이다.

Xsplit Broadcaster 로 RTMP 송출할 때 오디오 문제

Macbook Pro 15 2016 Late 에 Bootcamp 가 설치된 환경
OBS 로 계속 설정을 바꿔가며 테스트 해보다가,

마침 윈도우니 Xsplit Broadcaster 로 RTMP 를 송출해봤더니
내가 설정한 오디오 품질과는 무관하게 계속 듣기 힘들정도로 열화된 오디오가 출력됐다.

GPU 를 이용한 인코딩을 하고 있었는데 (RX460 개조 드라이버)
혹시 하는 맘에, X.264 로 바꿔보니, 제대로 되는 것 같더라.

GPU 를 이용하여 처리하면 소리가 이상해지던지,
아니면 개조드라이버의 품질 문제인 것인지 모르겠지만...

그리고 Xsplit 이 뭔가 음장을 따로 거는 것인지
설정을 샅샅히 뒤져도 딱히 안보이는데...
OBS로 송출 할 때 보다 다소 먹먹한 느낌이 든다.

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

1. 맥북프로도 부트캠프 환경일 때 OBS가 정상 동작한다.
2. Xsplit 으로 들어가면 심지어 외장 그래픽카드도 사용할 수 있다.
3. Xsplit에서 외장 그래픽카드를 사용하면 오디오 품질이 나빠지지만, 개조드라이버 탓일 수도 있다. <- 부트캠프 재설치해보고 재확인 필요
4. Xsplit 으로 송출하면 오디오 품질과 무관하게 음장이 걸린듯하게 좀 더 굵고 탓하고 울리는 소리가 난다. <- 이건 추후로도 리서치 필요.


2017년 3월 4일 토요일

MAC에서 RMTP 송출 테스트 (OBS)

윈도우에서는 여러가지 부가기능이 지원되는 Xsplit BroadCaster를 권하는데,
맥에서는 RMTP 로 방송용 영상 송출을 할 방법이 없을까 알아보다가
의외로 OBS (Open Broadcaster Software) 가 맥버전을 릴리즈 하고 있었다.

약간의 기대감을 가지고,
현역 맥북프로 중에서는 최고 사양인 내 맥에서 돌려봤다.
맥 -> OBS -> 커스텀 RMTP 서버 설정으로 아프리카TV 로 테스트

약간 삽질이 있었는데, 결론 부터 말하면 사용은 가능하다.

되긴 되는데 큰 문제가 몇개 있다.

---------------
1. 애플 VT H.264 인코더 동작이 이상함

영상 출력할 때 인코더를 "애플 VT H.264 하드웨어 인코더"로 했었는데,
애플 VT H.264는 하드/소프트 둘다 잘 안된다.

실행은 됐으나, 접속이 끊기거나 끊겼을 때 재접속 불가.
한참을 헤매다가...

X.264 로 CPU 부담을 지워 인코딩을 하니 별 문제 없이 잘 된다.
연결도 안 끊기고, 일부러 끊어도 재접속이 잘 된다.

문제는 이 경우 CPU 점유율이 상당한데다가,
기껏 외장 그래픽 카드가 있는 모델이지만 전혀 활용을 못한다.

---------------
2. 인코딩 된 프레임이 이상하다. 반토막

60으로 설정하든 30으로 설정하든 인코딩 프레임은 10~15정도에서 맴돈다.
CPU 점유율이 높던 낮던 마찬가진걸로 보아 버그로 보인다.

* 추가 :
Bootcamp 로 윈도우 부팅한 후 테스트 해보니 정상적으로 동작한다.
관련 글 링크
http://blog.kpaper.com/2017/03/xsplit-broadcaster-rtmp.html

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

테스트 결과만 말하면 기대를 전혀 충족시켜주지 못했다.
오히려 되줘서 고맙다고 감사해야하는 수준 ㅜㅜ...

참고로 같은 설정을 내 데스크탑 (하스웰 i3)으로 테스트 해보니 별 문제없이 60프레임으로 잘 출력이 되더라... (...)

인터넷 방송하려는 분들은 절대로 윈도우 시스템을 구축해야 합니다.

2017년 2월 24일 금요일

Unity3D 외부 리소스 가져오기

유니티로 빌드하면 에셋이 묶여서 엑세스가 불가하게 된다.
대량의 에셋을 추가하려면 에셋 번들을 이용하면 되는데,
이런 경우 말고 직접 리소스를 추가하고 싶은 경우가 있다.

최근 프로젝트에서 필요해서 하는김에 간단히 정리해봤다.
처음 하는 사람들에게 도움이 되길 -_-*

# Resource.Load 사용하기

private void ResourceLoadSample(){

  Texture2D texture = new Texture2D(0, 0); 
  string PATH = "Texture/image.jpg";    // 이미지 파일 패스를 써준다. 
  //중요한 것은 유니티 프로젝트 Assets/Resource/ 폴더 이후의 경로를 써주는 것이다. 이 폴더는 맘대로 바꿀 수가 없다.
  texture = Resources.Load(PATH,typeof(Texture2D)) as Texture2D;  // 이미지 로드
  targetObject.mainTexture = texture;  // 타겟 오브젝트에 메인 텍스쳐를 넣어준다.

}

# System.File.IO로 직접 가져오기
Resource 폴더가 아니라 다른 폴더 특히 StreamingAssets에서 가져오려면

Resource.Load 함수를 쓰지 말고 직접 System.File.IO 로 가져와야 한다.
byte[] 로 가져온 다음에 Texture2D.LoadImage()를 사용하여 텍스쳐2D로 읽어오면 된다.



private void SystemIOFileLoad(){

byte[] byteTexture = System.IO.File.ReadAllBytes(Path); 
    if (byteTexture.Length > 0) 
    { 
        texture = new Texture2D(0, 0); 
        texture.LoadImage(byteTexture); 
    } 
}


# 원하는 경로/파일에 엑세스 하기

# StreamingAssets 폴더의 하위 폴더/파일에 접근해본다.
Path = System.IO.Path.Combine(Application.streamingAssetsPath, path); // path = 하위폴더 "하위폴더1/하위폴더2/file.png";


2017년 2월 22일 수요일

블로그 소스코드에 하일라이트 적용

귀찮아서 코드를 적당히 올렸는데,
눈에 거슬려서 오늘 그냥 달았다.

아주 잘 준비가 되어있어서 그냥 하면 되는데 귀찮음이 뭔지..

아래는 highlightjs 사이트 링크 (사용법을 꼭 읽어보자.)

https://highlightjs.org/usage/


cdnjs 로 블로그 스킨 템플릿을 열어서 html 편집을 한다.
아래의 코드 추가

<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/default.min.css" rel="stylesheet">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js">
<script>hljs.initHighlightingOnLoad();

사용 법은

<pre><code>코드</code></pre>

이것으로 끝!
간단!
귀찮다고 미루지 말고 진작할걸...
하일라이트 스타일은 나중에 짬이 날 때 바꾸는 것으로 -_-;

Unity3D에서 uGUI Button 을 동적으로 생성할 때, 클릭 이벤트 추가 하는 방법

uGUI 로 동적 버튼을 생성할 때 코드로 클릭 이벤트를 추가하려면,
아래와 같은 방법으로 onClick 이벤트를 추가한다.


_spawnedButton.GetComponent<Button>().onClick.AddListener(delegate() { 게임오브젝트.GetComponent<컴포넌트 클래스 이름>().실행할 함수(); });

2017년 2월 21일 화요일

Unity3D 용 Json Parser - JsonUtility(Unity3D 5.3 Later), JsonObject

Unity3D로 Json 파일을 좀 사용할 일이 있어서 알아보았다.

그 동안 기획일 하면서 데이터만 만들었지,
직접 뭔가를 해볼일은 없었는데 이참에 해보는 것으로...

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

Unity3d Json Parser를 검색해보면

- JsonFX (가장 편하다는 평인데, 사이트 접속 불가. DLL 은 구했지만 스킵.)
- LitJson (iOS 이슈 게시물이 상당히 많다.. 위험)
- MiniJson (EastFever 님의 추천!!)
- JsonObject (직접 테스트 해본 것. 문제 없음)

등이 나오는데

일단은 JsonObject 를 사용해봤다.
이유는 Unity3D Asset Store에 등록되어있는데다가 무료고,
다들 잘 사용하고 있는 것 같아서 선택했다.

다운로드 및 레퍼런스 위키는 아래 주소에서 확인 가능하다.
http://wiki.unity3d.com/index.php/JSONObject#Download

나는 간단하게 읽고 쓰기만 할 생각이라서 뭐 다른건 지원된다고 해도 그러려니 상태였다.!
당연히 유니티 5.5에서도 문제 없었기에 이걸로 써야지~ 하고 결정!!!


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


그.. 그런데... 두둥!
조금 더 알아보다 보니,

유니티 5.3 부터 JsonUtility 라는 내장 API 가 생긴 것이다. 두두둥..!!

(몰랐다니, 아니 대수롭지 않게 보고 흘려서 까먹은듯,
릴리즈 블로그 읽기를 소홀히 한 제 탓입니다. T_T)

그래서 바로 쓱쓱 테스트 !!!

일단 레퍼런스 문서를 보자.
https://docs.unity3d.com/ScriptReference/JsonUtility.html


# ToJson 사용 방법 (코드 예제)


using UnityEngine;

[System.Serializable]
public class MyJsonClass
{
    // 사용할 Json Key 를 정의
    public int level;
    public float timeElapsed;
    public string playerName;

}

public class JsonUtilityTest : MonoBehaviour {

    private void WriteJSon() {
        MyJsonClass myObject = new MyJsonClass();
        myObject.level = 5;
        myObject.timeElapsed = 14.75f;
        myObject.playerName = "Kpaper ToJson Test";

        string json = JsonUtility.ToJson(myObject);
        Debug.Log(json);
    }
}

# FromJson 사용 방법. (더 자세한 내용은 위의 레퍼런스 사이트보면 잘 나와 있다.)


JsonUtility.FromJson<MyJsonClass>(json);

------

딱 내가 원하는 것만 간단하게 쓸 수 있어서 좋았다.
손쉽게 시리얼라이즈!

아무래도 엔진에 종속되서 개발을 하다 보니,
외부 에셋을 쓰기 보다는 내장된게 좋을 것 같아서 방향 선회!를 하는 것으로 결론...

끝!

P.S : 교훈. 멀리서 찾지 말자 -_-;;;

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

[내용 업데이트]

으헉!!
JsonUtility는 Json 타입 중 Property Type 에는 사용할 수 있는데, Dictionary Type 은 사용할 수 없다.

구글 선생님한테 물어봐도 고통, 포럼 유저들도 다 같이 고통 중이었다.
(언젠간 업데이트 되지 않을까 하고 헛된 희망을 가져봤다.)

하지만 계속 구글링 해본 결과, 다행히 구글 선생님은 일본 블로그 하나를 추천해주셨다.
http://kou-yeung.hatenablog.com/entry/2015/12/31/014611
(杏仁さん、ありがとうございます。 T_Td)

ISerializationCallbackReceiver 를 이용하는 방법이다.

이걸로 거의 해결! (왜 거의인지는 나중에 다시 포스팅 하겠다. ㅜㅜ)

P.S 2 : 그냥 평범하게 선구자분들에게 추천 받은 것으로 할 걸, 왜 그랬을까. ㅠ_ㅠ...

<끝>

2017년 2월 17일 금요일

MS Office for Mac (Office 365 구독) 드디어 MacBook Pro TouchBar 지원 업데이트 배포

드디어 맥용 오피스에서 터치바를 지원한다.

터치바를 지원하는 것을 애타게 기다렸던 것은 아닌데...
(적어도 MS의 생산성 제품을 이용할 때는 터치바가 너무도 불편하여... ㅠㅠ 펑션키 돌려줘!)

그래도 MS가 이에 대해서 개선을 해준다면 그래도 좋아지지 않을까 하여,
업데이트 예정 기사를 보고 나름 기다리고 있었는데...

드디어 오늘(어제?) 일반에도 릴리즈되었다. (미국시간으로 2/16)


<오피스 제품중 하나를 실행해서 업데이트 확인을 눌러준다.>

현재 설치 중이라서, 설치하고 소감을 간단히 업데이트 해보면,


두근두근





소감.

서식 관련 기능들이 추가되고 눈에 잘 띄게 되었다.

엑셀 F2와 F4를 엄청 사용하는데, 이건 아예 사라져버렸다.

엑셀보다는 파워포인트 쪽이 더 쓸만한 것 같다. 리본메뉴의 일부가 터치바에도 클로닝되어 보여지는 느낌.

터치바 맞춤 설정이 가능할 것 같은데, 메뉴를 찾을 수 없다. 추후 업데이트 될려나? ㅜㅜ

뭔가 기대를 많이 했던것은 아닌데, 당장 쓰는데는 아직 별 차이가 없다.

맥용 오피스는 윈도우에 비해 단축키가 적다는 느낌이었는데, 터치바가 그 자리를 대신할 수 있을지는 아직도 모르겠다.

MS 제품군은 역시 일반 키보드 연결해서 쓰는 편이 나을지도 모르겠다.

작업 편의상 맥에서 MS 오피스를 쓰고 있긴 한데, 역시 오피스는 윈도우에서 써야겠다.

일단 맞춤 설정기능을 쓸 수 있게 되면 내가 쓰기 편하게 고쳐놓고 다시 평가를 하는 것으로 마무리.



참고 링크 : http://appleinsider.com/articles/17/02/16/microsoft-rolls-out-macbook-pro-touch-bar-support-to-all-office-for-mac-suite-users

2017년 2월 6일 월요일

Wacom CTH-470 windows 10 Pro 에 설치하기

이번에도 드라이버 문제 발생!

최신 드라이버를 설치하면 장치를 찾을 수 없다고 한다.

경험을 살려 예전 드라이버를 설치하니 정상 작동 했다.

윈 10 프로에서

펜태블릿 드라이버 5.3.5-3 에서 동작 확인


http://cdn.wacom.com/u/productsupport/drivers/win/consumer/pentablet_5.3.5-3.exe

2017년 2월 1일 수요일

SNFaceCrop 자동 얼굴 크롭 툴 추천 (Auto Face Crop Tool)

자동으로 얼굴 잘라주는 툴 추천



http://deteksiwajah.blogspot.kr/2011/11/snfacecrop-14-is-released.html

OpenCV 를 이용하는 것 같은데,  윈도우 바이너리만 배포 중인게 조금 아쉽다.

얼굴 학습 데이터 정리할 때 사용하면 유용하다.



아래와 같이 입력하면 배치로도 작업 가능

SNFaceCrop -d c:\myphotos -f *.bmp -ex 50 -ey 50

myphotos 를 나의 작업 원본이 있는 경로 *.bmp 나 png나 jpg 로 하면 되고

-ex 와 -ey 는 확대할 퍼센티지


Croped 폴더 결과물을 보면서 제대로 잘렸는지 확인을 해줄 필요는 있다.
3~5% 정도 오인식 결과물이 있는 듯.

BossSensor - 얼굴 화상 인식을 이용한 월급 루팡 프로그램을 직접 실행해보았다. (수정내용 첨부)


점심시간이 끝나고 지루한 오후...

우리 팀에서 제일 재밌는 분이 팀 단체 쪽지를 보냈다.

쪽지 : 케이! 케이!! 이것 좀 만들어줘!!!"

나 : ㅋㅋㅋㅋ

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

오늘의 유머 사이트
제목 : 월급 루팡을 하려는 프로그래머

내용을 보았다.






최근에 업무차 OpenCV와 딥러닝을 공부하고 있던 입장에서 흥미로운 내용이었다.

내용은 단순하게 보면 Face Recognize 샘플인데 가까운데,
저런 재밌는 아이디어를 생각만으로 끝내지 않고, 실제로 만들어서 실행했다는게 큰 차이.

잉여력 방출은 언제나 재밌고 즐겁다.

원문 블로그는 여기
http://ahogrammer.com/2016/11/15/deep-learning-enables-you-to-hide-screen-when-your-boss-is-approaching/

(블로그 주소 이름이 무려 아호그래머다;;; あほ=멍청이,
똑똑하게 삽질하는 멋진 블로그인듯... >_<! 이런 것 너무 좋다.)

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

처음부터 만들까 하다가 원작자가 소스를 오픈해 둔 터라
시간 절약 + 재미로 바로 실행해볼 요량으로 달려들었다.

원문 블로그에 공개한 보스 센서 오픈소스 GitHub


최근까지도 수정되고 있는 소스지만..
당연히 그대로 실행될리가 없지.

에러 메시지를 하나씩 확인하며 해결해 나가기 시작했다.

필요한 라이브러리나 그 외 환경 세팅하는 시간이 오히려 꽤 걸리기 시작하면서

그렇게 야근이 시작되었다. ㅋㅋㅋㅋ

누군가 해보고 싶은 사람에게 도움이 되도록 결과 자료를 남긴다.



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

# 실행한 환경

- 맥북프로 2016 15 Late
- iSight MacBook 내장 웹캠
- macOS Sierra 10.12
- Anaconda (Miniconda3)
- OpenCV3

IDE 는 Pycharm

※ 검증해보지는 않았지만, Windows 에서도 동작하지 않을까?

# 설치된 Python Library Version
직접 검증한 최신 버전의 라이브러리들

h5py (2.6.0)
Keras (1.2.1)
mock (2.0.0)
numpy (1.12.0)
pbr (1.10.0)
pip (9.0.1)
protobuf (3.2.0)
PyYAML (3.12)
scikit-learn (0.18.1)
scipy (0.18.1)
six (1.10.0)
sklearn (0.0)
tensorflow (0.12.1)
Theano (0.8.2)

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

# 문제 해결 1-2-3

1. PyQt4 설치가 안된다. (macOS Sierra)
brew install pyqt4 가 안된다!!!
구글링 해도 답이 없어 찾아보니 os 버전이 최신이라서 그런듯...

어디서 사용하나 코드를 보니 굳이 PyQt4일 필요는 없더라.
 PyQt5를 설치하고, 스크린 관련 코드를 4에서 5로 새로 옮겨준다.
이 작업은 조금 귀찮은 정도. 다른 이를 위하여 내 GitHub 포크에 업로드 해두었다.

덤. PyQt5 를 아나콘다로 설치하기
사용할 환경으로 소스를 바꾼 뒤
> conda install pyqt

2. requirements.txt 에 필요한 라이브러리가 설치가 안된다.
파이썬 라이브러리 목록과 버전이 잘 정리되어 있긴 한데,  해당 버전으로 설치할 수 없는 라이브러리 패키지가 있다.

예를 들면 tensor flow 0.10.0...
이 때문인지 keras도 조금 문제가 생기는데, 이것도 최신 버전으로 설치하자.
예전 버전 그대로 두면 사진 트레이닝 할 때 트러블이 있다.
requirements.txt 도 수정해서 내 GitHub 포크에 업로드 해두었다.

3. model 데이터를 저장할 경로를 미리 만들어줘야 한다. 
하위 경로로 미리 ./store/ 폴더를 만들어두면 오류가 없다.
내 GitHub 포크에는 미리 생성해두어 해결했다.

4. 모델데이터를 새로 생성할 때는 기존 모델 파일을 삭제할 것
boss_train.py를 이용하여 모델데이터를 학습하면 ./store/model.h5 가 생성되는데,
새로 학습시킬때 이 파일을 생성하기 전에 미리 지워줄 것 (덮어쓰기 오류 남)
덮어쓰게 수정 하려다가 이건 귀찮아서 패스...

5. 얼굴 인식률이 떨어진다.
다양한 각도로 약 500 - 1200 장 정도 학습을 시켜야 한다.

# GitHub Fork Repository

GitHub Fork 해서 수정한 내용 커밋해두었다.
혹시 오리지널 GitHub 출처에서 실행이 어려운 분이나
내가 수정한 내용이 필요하신 분은 아래의 경로에서 다운을...

https://github.com/prscu24/BossSensorPyQt5


# 실행화면 영상
내 얼굴을 학습 시킨 후, 비상 이미지는 실행되지 않게 하여 실행.
카메라 근처를 어슬렁거려보았다.




# 마무리

학습 데이터가 부족해서 인식률은 떨어지지만
원래 목적인 경고의 의미로는 나쁘지 않은 동작을 보인다.
 - 인식률이 나쁘면 보스가 출몰하지 않았는데도 나왔다고 오인식을 해버리는 문제가;;;
그리고 사장님 얼굴을 양해하지 않고 그렇게나 많이 모을 수 있을까?
이것은 고양이 목에 방울을 다는 상황이 생각난다.

거기다가 실행 비용도 커서 항상 실행해두기는 좀 부담되는 정도 ^^;; (CPU 사용률이...)

학습용으로 토이용도로 재밌게 사용해보면 될 것 같다.

<오늘의 삽질 !>

2017년 1월 31일 화요일

Anaconda 설치 하기

파이썬 환경 관리를 위해 필요해졌다.

급하게 세팅한 후 나중에 내가 다시 볼 메모로 쓰려고 글을 남긴다.



아래의 미니콘다를 퀵가이드에 따라 설치하자.

https://conda.io/miniconda.html



설치가 완료 되면 MacOS 터미널을 닫고 다시 터미널을 열자.

아래의 명령어로 환경을 만들고 없앨 수 있다.



설치 확인

conda info --envs
새 환경 만들기

conda create --name kpaper
환경 활성화

source activate kpaper
환경 비활성화

source deactivate

환경 지우기

conda remove --name kpaper --all

환경 클로닝 하기
conda create --name kpaper --clone anotherenv

설치 가능한 패키지 확인하기
conda search --full-name python
--full-name 은 완전히 패키지 이름이 일치할 때에만 표시한다.


파이썬2 설치하기
conda create --name kpaper python=2
아래와 같이 입력해서 파이썬 버전을 확인할 수 있다.
source activate kpaper
python --version

파이썬3 설치하기
conda create --name kpaper python=3

모든 환경 목록 보기

conda info --envs

새로운 패키지를 어떤 환경에 설치하기

conda install --name kpaper beautifulsoup4
------------------

사용 소감 :

완전 좋다! 편리하다!;;;
진작 알았으면 좋았을걸!!
아니 예전에는 알았어도 체감을 못했을 것 같긴하다 ^^;