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