01
04

https://youtu.be/Wh0xuvLOYKg


https://youtu.be/QDjcYHbZtF0


본 프로젝트는 반려동물이 없는 예비 반려동물 주인이나, 뷰니멀들에게 반려묘 육성을 체
험해볼 수 있는 콘텐츠 제작과정을 설명하는 논문이다. 닌텐독스의 기기와 안드로이드 기
기의 큰 차이점은 안드로이드 기기는 스마트폰으로써 다양한 모듈이 탑재되어 있다는 점이
다. 

예를 들어 고화질 카메라는 증강현실 구현에 있어서 영상 합성 기술을 적용할 수 있게
하였다. 증강현실에는 대표적으로 마카 인식 기술과 영상 합성 기술이 있는데, 마카 인식은
높은 정확성을 가지지만 마커가 없으면 활용할 수 없다는 단점이 있다. 고화질 카메라로
이를 보완하게 되었다. 

아래 사진은 각 각 영상합성 기술을 사용하여 AR시연 모습,

근거리 유저 간 블루투스 통신 플레이의 시연 모습이다.

 

1) AR 기능
AR 기술에는 대표적으로 마카인식 기술과 영상합성 기술이 있다. 마커 인식은 높은 정확성을 가지지
만 마커가 없으면 활용할 수 없는 단점이 있다. 이를 보완하기 위해 영상합성 기술을 채택했다. Google의
AR Foundation 프레임워크를 활용해 AR을 구현하였다. 장신구를 착용, 다양한 모션들로 고양이와 사진
을 찍어 추억을 남기는 콘텐츠로 제작하였다.
AR Foundation에서 제공하는 AR RAY CAST로 바닥 플레인을 탐지해서 해당 레이케스트가 닿는 부
분에 물체를 소환한다. 스크립트에서는 해당 레이케스트가 닿은 위치에 소환하고 물체는 카메라 방향을
볼 수 있게 했다. 이미 물체가 소환된 경우에는 자리 이동만 할 수 있게 스크립트를 구성했다.

private void placeObjectByTouch()
{
	if (Input.touchCount > 0 && hold == false
		&& !IsPointerOverUIObject(Input.mousePosition))
	{
		if (EventSystem.current.IsPointerOverGameObject(
			Input.GetTouch(0).fingerId))
			return;
		else
		{
			Touch touch = Input.GetTouch(0);
			List<ARRaycastHit> hits = new
				List<ARRaycastHit>();
			if
				(arRaycaster.Raycast(touch.position, hits,
					TrackableType.Planes))
			{
				Pose hitPose = hits[0].pose;
				if (!spawnObject)
				{
					spawnObject =
						Instantiate(placeObject, hitPose.position,
							hitPose.rotation);
					scan_status.text = "고양이 소환";
					Vector3 lookAtPosition =
						spawnObject.transform.position;
					lookAtPosition.x
						= transform.position.x;
					lookAtPosition.z
						= transform.position.z;
					transform.LookAt(lookAtPosition);
					slider.SetActive(true);
					catAnime.SetActive(true);
				}
				else
				{
					spawnObject.transform.position = hitPose.position;
					spawnObject.transform.rotation = hitPose.rotation;
					Vector3 lookAtPosition =
						spawnObject.transform.position;
					lookAtPosition.x
						= transform.position.x;
					lookAtPosition.z
						= transform.position.z;
					spawnObject.transform.LookAt(lookAtPosition);
				} 터치한 곳에 고양이 오브젝트를
			}//
			소환, 이미 소환된 상태면 자리 이동만 함
		}
	}
}

 

2) 블루투스 기능
증강현실을 탑재한 포켓몬고는 집 안이나 PC방에서 하던 기존 게임과는 달리 실외로 나가서 가상의 야
생에 있는 포켓몬을 잡기 위해 실제 밖으로 나가야 하고 움직여야 , 한다는 특징이 있다. 이러한 설정에 영
감받아 폰캣은 본인의 고양이를 친구의 고양이와 만나기 위해서 실제로 만나야 한다. 이를 위해 근거리
통신인 블루투스를 사용한다.
스마트폰의 블루투스는 유니티에서 직접 접근하지 못하고 안드로이드 기반 언어는 JAVA를 사용해야 되
기 때문에 안드로이드 스튜디오에서 미리 제작된 Android 라이브러리를 통해 접근 할 수 있다. 표2에서
는 라이브러리를 인스턴스로 받아와서 사용하는 스크립트다. 해당 스크립트로 토스트 메시지도 활용할
수 있었다.

public class AndroidPlugin : MonoBehaviour
{
	블루투스 // 기능은 안드로이드 네이티브 기
		능으로서 안드로이드 스튜디오의
		AAR 라이브러리를 불러와서 사용해야한
		다.
		private AndroidJavaObject UnityActivity;
	private AndroidJavaObject UnityInstance;
	void Start()
	{
		AndroidJavaClass ajc = new
			AndroidJavaClass("com.unity3d.player.UnityPl
				ayer");
				UnityActivity =
				ajc.GetStatic<AndroidJavaObject>("currentActi
					vity");
					AndroidJavaClass ajc2 = new
					AndroidJavaClass("com.nsu.forunity.Myplugin")
					;
		UnityInstance =
			ajc2.CallStatic<AndroidJavaObject>("instance")
			;
		UnityInstance.Call("setContext",
			UnityActivity);
	}
	// 토스트 메시지
	public void ShowToast(string msg, bool
		isLong)
	{
		UnityActivity.Call("runOnUiThread",
			new AndroidJavaRunnable(() = >
		{
			if (isLong == false)
			{
				UnityInstance.Call("ShowToast", msg, 0);
			}
			else
			{
				UnityInstance.Call("ShowToast", msg, 1);
			}
		}
		));
	}

 

3) JSON 데이터를 이용한 상점 시스템
상점은 따로 DB를 구축해 JSON으로 각 아이템 번호, 이름, 가격, 구매 유무를 관리했다. 향후 아이템
을 추가하거나 제거할 때 편리하도록 구현했다.
유니티에서 기본적으로 제공하는 JsonUtility.ToJson를 사용했다.

제너릭 클래스(유사 탬플릿 클래스)를 사용해 List에 담아서 사용했다.

DB 구축하기 위해서 txt파일을 파일 입출력으로 File.ReadAllText(filePath) 불러온다. 다음에는 JsonUtility로 Json화 한다.
PC와 다르게 모바일 환경은 저장위치가 다르게 대응하기 때문에 Application.persistentDataPath앱
의 저장되는 위치를 받아와서 사용하면 모바일 저장 위치를 확인 할 수 있다.

[System.Serializable]
public class Serialization<T>
{
	public Serialization(List<T> _target) = > target =
		_target;
	public List<T> target;
}
public class DataManager : MonoBehaviour
{
	public TextAsset ItemDatabase;
	public List<Item> AllItemList;
	string filePath;
	private void Start()
	{
		// Load();
		//txt 파일을 읽어옴. 엑셀 파일로 작성되었음
		text 에셋으로 한줄 한줄 잘라냄
			string[] line =
			I t e m D a t a b a s e.t e x t.S u b s t r i n g(0,
				ItemDatabase.text.Length - 1).Split('\n');
		for (int i = 0; i < line.Length; i++)
		{
			line[i] = line[i].Trim(); //이거 추가
			string[] row = line[i].Split('\t');
			AllItemList.Add(new Item(row[0],
				row[1], row[2], row[3]));
		}
		filePath = Application.persistentDataPath +
			"/allitemdata.txt";
	}
	void Save()
	{
		string jdata = JsonUtility.ToJson(new
			Serialization<Item>(AllItemList));
		File.WriteAllText(filePath, jdata);
	}
	void Load()
	{
		//if(!File.Exists(filePath)) {ResetItemClick();
		return;
	}
	string jdata = File.ReadAllText(filePath);
	AllItemList = JsonUtility.FromJson<Serialization<Item
		>>(jdata).target;
}
}

 

4) 랜덤으로 작동하는 고양이의 행동
유니티의 코루틴 함수를 사용해 Random.Range로 랜덤한 행동을 구현했다. 각 애니메이션은 랜덤한 시
간으로 유지된다.
실제로 살아있는 듯한 느낌을 주기 위해 모든 행동은 랜덤으로 결정하게 구현했다. 코루틴 함수를 사용한
것은 Coroutine은 기존의 Thread를 좀 더 작은 단위로 쪼개어 사용할 수 있는 개념이기에 Thread에서
복수의 이 실행될 경우 각 가 가지는 메모리 Coroutine Thread Stack 영역도 하나가 되어 메모리 절약이
된다.

  IEnumerator Wander()
    {
        int rotTime =Random.Range(1,2);
        int rotateWait=Random.Range(1,3);
        int rotateLorR=Random.Range(0,7);
        int walkWait = Random.Range(1,3);
        int walkTime = Random.Range(4,10);
        int idletime = Random.Range(2,8);
        int sitdowntime = Random.Range(6,10);

        isWandering=true;

        yield return new WaitForSeconds(walkWait);
             if (!audioSource.isPlaying)
                Meow();
        isWalking = true;
        //WalkSound();
        yield return new WaitForSeconds(walkTime);
        isWalking = false;
        //애니메이션 끄기
        animator.SetBool("ismove", false);
        //
        yield return new WaitForSeconds(rotateWait);

        if(rotateLorR==1){
            isRotationRight=true;
            //WalkSound();
            yield return new WaitForSeconds(rotTime);
             animator.SetBool("ismove", false);
            isRotationRight=false;
        }
        .
        .
        .생략

 

5) Head up UI 스크립트
블루투스 통신에서 고양이 정보가 고양이의 머리위에 계속해서 띄워져 있어야 한다. playerpref로 저장
되어 있던 정보를 불러와서 해당 오브젝트의 위치를 업데이트 구문에서 받아와 띄워준다. playerpfref는
보안에 취약하므로 간단한 정보만 저장했다. 예를 들어, 고양이의 위치는 매 10분마다 저장이 되어 다음
에 앱을 실행해도 그 위치를 기억하는 로직도 구현했다. 그밖에 시간을 이용한 로직은 배고픔이나 심심함
에도 적용이 되었다.

그 밖에 UI위에 파티클 시스템을 적용하고, dotween 애니메이션 도구를 사용했다. 

void Update()
{
	playerinfoUI.transform.position =
		headUpPos.transform.position;
	UITextput();
}
void UITextput()
{
	if (isMine == true)
	{
		string myname =
			PlayerPrefs.GetString("name");
		int	mylevel = PlayerPrefs.GetInt("statValue");
		levelname_text.text = "LV. " +
			Mathf.Floor(mylevel / 6f).ToString() + "\n" + myname;
	}

 

6) 현실 시간 반영한 배경(창문 밖)과 고양이의 상태
DateTime 구조체를 사용해 현재의 시간을 불러와, 마지막으로 사료를 투여한 시간, 마지막으로 놀아준
시간을 계산, 또한 현재의 시간에 따라 창 밖에 모습이 아침, 낮, 밤으로 다르게 표현하여 현재의 시간이
어떤지 유저에게 알려주게 구현했다.

public string nowTime()
{
	//스트링 값으로 현재 시간을 보내드립니다.
	DateTime now;
	now = DateTime.Now;
	string st = now.ToString("yyyy-MM-dd
		HH:mm:ss");
		return st;
}

 

7) GOF 디자인 패턴의 활용
하나의 오브젝트만 필요한 기능은 디자인 패턴인 싱글톤 디자인을 사용했다. 싱글톤 디자인은 고정된 메
모리 영역을 얻으면서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 방지할 수 있다.
또한, 싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들
이 데이터를 공유하기 쉽다는 큰 장점이 있다. 하지만 모든 곳에서 접근이 가능하므로 싱글톤 객체의 변
경 시점, 변경 주체, 호출 시점을 모두 알기가 어렵기 때문에 주의가 필요하다.

고양이 상태도 상태패턴을 적용하여, 일반 제어문을 쓰지않고 관리했다면 좋았을텐데, 아쉬움이 남았다.

public class BGM_START : MonoBehaviour
{
	private static BGM_START instance = null;
	public static BGM_START Instance
	{
	get { return instance; }
	}
		void Start()
	{
		if (instance != null)
		{
			Destroy(this.gameObject);
			return;
		}
		else
		{
			instance = this;
		}
		DontDestroyOnLoad(this.gameObject);
	}
}

다시 구현한다면, 싱글톤을 만드는 로직을 제너릭으로 만들어서 여러 객체에 적용하고 싶다.

 

8) 시네머신과 터치의 활용
유니티에서는 클릭과 모바일의 터치가 객체가 따로 있다. Touch에는 다양한 객체의 상태가 있기 때문에
클릭이 아닌 터치로 구현하는 것이 좋다. Touch Phase는 가장 최근의 프레임에 손가락이 취한 동작을
나타내는데, Touch Phase의 열거형 값을 비교해 현재 터치 상태를 확인할 수 있다. 1. Began 2. Moved
3. Stationary 4. Ended 5. Canceled가 그것이다. 위 표 8에서는 Ended, 화면 위를 벗어나 터치가 끝난
상태를 받아오는 스크립트이다.
시네머신은 유니티 엔진에서 제공하는 카메라 연출 패키지이다. 시네머신에도 애니메이터를 만들어서 4
번 터치했을 경우 고양이를 집중적으로 렌더링하는 카메라를 활성화할 수 있다.

 

void Update()
{
	//터치 량이 0보다 클때
	if (Input.touchCount > 0)
	{
		Vector2 pos =
			Input.GetTouch(0).position; // 터치한 위치
		Vector3 theTouch = new Vector3(pos.x,
			pos.y, 0.0f); // 변환 안하고 바로 Vector3로
		Ray ray =
			Camera.main.ScreenPointToRay(theTouch); // 터치
		한 좌표 레이로 바꿈
			RaycastHit hit; // 정보 저장할 구조체
		만들고
			if (Physics.Raycast(ray, out hit,
				Mathf.Infinity))
			{
				// 캣이라는 태그를 가진 콜라이더에 닿
				은 레이캐스트
					if (hit.collider.CompareTag("cat"))
					{
						// 한 4번 터치 하면 이쪽 보게함
						if (Input.GetTouch(0).phase ==
							TouchPhase.Ended)
						{
							cattouchcount++;
						}
						if (cattouchcount > 4)
						{
							CamTrigger();
							cattouchcount = 0;
							....중략
	
    //시네머신
	public void CamTrigger()
	{
		if (!cam.GetBool("iszoom"))
			cam.SetBool("iszoom", true);
		else
			cam.SetBool("iszoom", false);
	}

 

본 프로젝트는 안드로이드 기기로 고양이를 육성하고 인터렉션이 가능한 증강현실 속에서 누구나 쉽게
플레이할 수 있는 안드로이드 기반 고양이 육성 게임으로, 블루투스 통신을 이용하여 근거리 유저 간의
고양이와 같은 공간에서 놀이를 할 수 있고, 성별이 다르다면 교배를 통해 새끼를 낳을 수 있다. AR 기술
을 통해 고양이를 실제 배경에 배치하여 볼 수 있다. 핸드폰 안에 있는 고양이와 놀아주기, 먹이 주기 활
동으로 친밀감을 느끼게 할 수 있고, 스킨과 인테리어 변경을 통해 플레이어의 개성을 표현할 수 있다. 반
려동물을 기르지 못해 대리만족을 느끼고 싶은 사람들에게 시뮬레이션 콘텐츠를 제공하였다. 

 

https://github.com/jiwonchoidd/PhoneCat

 

GitHub - jiwonchoidd/PhoneCat: Unity - AR, 블루투스, 상점 DB가 구현된 고양이 육성 시뮬레이션

Unity - AR, 블루투스, 상점 DB가 구현된 고양이 육성 시뮬레이션. Contribute to jiwonchoidd/PhoneCat development by creating an account on GitHub.

github.com

 

COMMENT