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/
만든 정규식으로 샘플 스트링으로 즉시 확인해볼 수 있다.
(예전부터 많이 사용하던 사이트 ^^;; )

2018년 1월 10일 수요일

웹캠 선택 관련 참고 글 (Logitech, MS LifeCam 등 게임 방송용 웹캠 선택하기)


웹캠 (화상캠, PC용 USB 카메라) 개발을 하면서 사용해본 캠들의 느낀 점을 대충 정리했다.
누군가 작업용, 방송용, 취미용으로 웹캠을 구매할 때 참고가 되시길..

-------------------------------
[Logitech 편]

C310 (씨삼일공)
보급형, 화면이 나온다. ㅋ
720 30프레임 지원

C920 (씨구이공)
가장 많이 팔린 스탠다드 웹캠, 이 모델을 기준으로 다양한 변종이 있다.
720 60프레임 1080 30프레임 지원

C922X Pro Stream Webcam (씨구이이엑스 프로 스트림 웹캠)
1080 MJPG 60프레임이 지원되는게 특징적으로 다르다.
생긴건 C920 과 동일
미니삼각대가 서비스로 들어있다.
크로마키천 없이 소프트웨어로 크로마키 해주는 기능이 있다고 하는데
사실 Chroma Cam 이라는 번들 소프트웨어 (심지어 체험판)를 껴주는 것이다.
이 소프트웨어를 이용하면 C920등 다른 캠에서도 가능..
C920 보다 10% 비싼 가격.

C930e (씨구삼공이)
SKYPE 화상회의용으로 개발됨
DirectShow 대응 드라이버로 개발이 되어 있으며,
방송용으로 쓰기에는 C920 보다 성능과 호환성이 떨어지는 느낌이다.
아니 잘라말해서 이걸 굳이 왜사야 하는지 모르겠다.
사지마세요. 숫자 높다고 좋은 모델 아닙니다.

BRIO 4K Pro (브리오 사케이 프로)
사용해보고 놀랬다.
동작 속도가 빠르고, 다양한 해상도 지원한다.
1080 MJPG 60프레임 지원해서 꽤 영상 딜레이도 적고 화질도 좋다.
1080 을 초과하는 해상도에서는 최대 30프레임이다.
얻어진 영상의 색감도 괜찮은 편, 윈도우 Hello 도 지원.
문제는 아직 비싼 가격 (정품 30만원 대, 리퍼 품 20만원 초반 대, 해외 직구 20만원 대)

-----------------------------
[Microsoft 편]

LifeCam HD-3000 (라이프캠 에이치디-삼천)
보급형, 화면이 나온다. ㅋ

LifeCam Studio (라이프캠 스튜디오)
720 1080 30프레임 이상 지원
저렴하고 화질 좋다.
DirectShow 대응 장비로 대체적으로 호환이 잘 된다.
Legacy 방식의 드라이버를 지원하지 않아서 윈7에서 사용이 어렵다. (구버전 빨간박스는 가능)
DirectShow 방식을 사용하면 윈7에서도 동작을 하긴 하는거 같은데... 음.
출시 당시에는 혁신적인 화질이었다고 하는데..
비용을 조금 더 보태서 C920 쪽을 더 추천하고 싶다.


[총평]
웹캠 중에서는 Logitech Brio 4K Pro 가 최고다. 성능도 가격도.

추천 순서 : 왼쪽이 좋은 순
Brio 4K Pro > C922 > C920 > LifeCam Studio > 미만 기타

자주 교체하는 장비가 아니니
한번에 끝판왕을 선택하는 편이 추가 비용이 들지 않아 좋을 것 같다.
내가 산다면 Brio, 그 외에는 사지 않겠다. 선물한다면 C922 무난하게 될거 다된다.
(C922 나 C920 은 사실 대동소이하다. -_-...)
게임에 PIP 로 조그맣게 얼굴을 넣어 방송 하고 싶으면 C920 사도 별로 차이 없을 것 같다.
하지만 미니삼각대 껴주니까 (소매 단가 5천원쯤하려나 이건...) C922!.

그나저나 세상이 좋아져서, 어지간한 보급형도 HD화질 (720) 이상을 지원하네 이젠..


<끝>

2018년 1월 9일 화요일

오늘 시각으로 파일 압축하여 네트워크 경로에 복사하는 배치파일 예제

말이 좋아서 예제지 내가 필요해서 하나 만든 것..
블로그에 올릴 수 있을 정도로만 대충 정리했으므로 가져가서 사용하실 분은 적당히 고쳐서 사용하시길..

# 동작 내용
FROMFOLDER 에서 파일을 TEMPFOLDER 로 복사하고, 이걸 TARGETFOLDER 로 오늘 날짜_시간.zip 파일 압축을 해서 복사해주는 배치파일

# 사용 방법
스크립트 안의 아래의 경로와 ID / PW 를 변경해서 실행하면 된다.

set TEMPFOLDER=C:\TEMP\

set FROMFOLDER=C:\CONTENTS
set TARGETFOLDER=C:\OUTPUT

set NETFOLDER=\\192.168.0.1\
set NETACCOUNT=아이디
set NETPASSWORD=비밀번호


:: 특정 폴더를 압축해서 시각 파일 이름으로 저장하기

@echo off
setlocal

:: 날짜 문자열을 년월일로 분해
set WEEK=%date:~0,1%
set YEAR=%date:~0,4%
set MONTH=%date:~5,2%
set DAY=%date:~8,2%

:: 시간 문자열을 시분초로 분리
set HOUR=%time:~0,2%
set MINUTE=%time:~3,2%
set SECOND=%time:~6,2%

echo. 현재 빌드 시간 확인, 이 시간을 파일명 뒤에 붙입니다. YYYYMMDD_HHMMSS 의 포맷으로 붙인다. 1자리수의 HOUR 는 0이 아니라 공백으로 오기 때문에 띄어쓰기가 없도록 0으로 매꿔준다.
set TIMETEMP=%YEAR%%MONTH%%DAY%_%HOUR%%MINUTE%%SECOND%
set TIMERESULT=%TIMETEMP: =0%
echo. %TIMERESULT%

:: 머징용 임시 폴더 제작
echo. 작업을 준비하는 중

:: 임시 작업 폴더 설정
set TEMPFOLDER=C:\TEMP\

if exist %TEMPFOLDER% (
        echo 임시 파일 폴더가 이미 작성되어 있습니다.
) else (
        echo 임시 파일 폴더를 생성합니다..
  MKDIR %TEMPFOLDER%
)

:: 파일 폴더에 복사해서 정리하기
set FROMFOLDER=C:\CONTENTS
set TARGETFOLDER=C:\OUTPUT

echo. 폴더 확인 중

if exist %FROMFOLDER% (
        echo 원본 폴더가 있습니다.
  
  if exist %TARGETFOLDER% (
  echo 대상폴더가 이미 있습니다.
  ) else (
   echo 대상폴더가 없어서 새로 만듭니다.
   MKDIR %TARGETFOLDER%
  )
) else (
        echo 원본 폴더가 없습니다. 작업을 중지합니다.
  goto ERROREND
)

pause

echo. 임시 경로로 파일 복사하는 중
Xcopy %FROMFOLDER% %TEMPFOLDER%

:: 출력될 파일 이름 설정 및 압축

echo. 임시 폴더로 부터 파일을 압축하는 중...

set OUTPUTFILENAME=%TIMERESULT%.zip
:: 반디집
"%programfiles%\Bandizip\Bandizip.exe" c -y %TARGETFOLDER%%OUTPUTFILENAME% %TEMPFOLDER%
:: 7집
::"%programfiles%\7-zip\7z.exe" a -y %TARGETFOLDER%%OUTPUTFILENAME% %TEMPFOLDER%

:: 네트워크 폴더에 복사
echo. 네트워크 폴더에 복사하는 중...
set NETFOLDER=\\192.168.0.1\
set NETACCOUNT=아이디
set NETPASSWORD=비밀번호

net use %NETFOLDER% NETPASSWORD /user:NETACCOUNT /persistent:no
copy %TARGETFOLDER%%OUTPUTFILENAME% %NETFOLDER%
if exist %NETFOLDER%%OUTPUTFILENAME% echo %OUTPUTFILENAME% 파일이 잘 복사된 것 같습니다.

echo. 네트워크 폴더 사용 목록을 제거 시도...
net use %NETFOLDER% /delete

:: 임시 폴더 삭제
echo. 임시 파일 삭제 중...
rmdir /s /q %TEMPFOLDER%

echo. 작업 완료! 오케이~
goto QUIT

:ERROREND
echo. 오류가 발생해서 작업을 종료합니다.
goto QUIT

:QUIT

endlocal
귀찮은 일은 컴퓨터에게 맡깁시다.

2018년 1월 4일 목요일

배치파일에 네트워크 엑세스 추가하기

아래와 같이 사용하면 된다.

net use \\네트워크경로 패스워드 /user:아이디 /persistent:no

persistent 는 네트워크 증명을 기록할 것인지 여부이다.

아래와 같은 예시 상황을 작성해본다.
네트워크 경로가 192.168.0.1\exam
아이디 Kpaper
패스워드 KpaperPassword

net use \\192.168.0.1\exam KpaperPassword /user:Kpaper /persistent:no

삭제 하고 싶은 경우에는 아래와 같다.

net use \\네트워크경로 /delete 

위의 예제라면

net use \\192.168.0.1\exam /delete

네트워크 파일 복사 등 귀찮은 작업이 반복될 경우 잘 활용해보자.

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