![[1인개발 프로젝트] 하늘소 프로젝트 1주차](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAZZrE%2FbtsDBvBXrdr%2FKyg31lCdsIIbnNaayKyi0K%2Fimg.png)

대학교 1학년이 얼렁뚱땅 넘어가버린 지금, 팀 프로젝트를 위해 군대를 미룬 김에 남는 시간에 1인 개발을 해보기로 결심했다. 아직 모르는 것도 엄청 많고 잘 하지 못하는 것도 많지만 일단 무작정 해보려고 한다.
그렇게 1주일 전부터 시작한 프로젝트가 "하늘소 프로젝트" 이다.
사실 이 프로젝트를 구상하게 된 것은 작년 4월부터이다. 알바를 가던 중, 버스를 놓쳐 어쩔 수 없이 택시를 타야했는데, 그 때 택시 창 밖으로 두 줄의 하얀 선이 보였다.

비행기 두대가 거의 동시에 양옆으로 지나간 흔적이었다. 나는 그것을 보자마자, '어, 저거 철도같은데?' 라는 생각이 들었다. 그렇게 알바 가는동안, 알바 하는 중에 혼자 상상에 잠겨 알바가 끝난 후 생각해냈던 것이 이 프로젝트이다.
이사람 N 100임.
우선, 게임 개발 프로젝트이기에 기획을 했다. 기획을 간단히 요약하자면 하늘을 누비는 거대한 열차 [하늘소 호] 가 7개의 지역을 다니며 이 열차의 차장이 겪는 에피소드를 그린 힐링 / 판타지 시뮬레이션 게임이다.
게임의 컨셉은 판타지이지만, 현실과 비슷한 요소들이 많기 때문에 친숙하면서도 신비한 느낌을 상상하며 기획했다.
이틀간 기획만 하고, 3일째 되던 날 본격적으로 시작했다.
개발 준비
1. Unity 프로젝트 Github와 연결
게임 제작 툴로 Unity를 선택했다. 아무래도 전에 해본적이 있던 툴이라 아직까지는 제일 쉬운 것 같다.
먼저 깃허브 레포지토리를 만들었다. 어디 한번 볼까?
Github Desktop을 이용해 만들었는데, 이 경우 Private로 레포지토리가 생성된다.
그래서 여기에 커밋과 푸시를 하려면 SSH키가 필요하여 이를 설정해주었다.
- git bash에 아래 명령어를 적기
$ ssh-keygen -t rsa -C "own email"
own email 자리에 자신의 이메일을 적으면 된다.
Enter file in which to save~~ 하는 문구가 나왔다면 성공이다.
- 패스워드 설정하기
위의 명령어를 친 후 문구가 나온 후 진행이 안될 때 엔터를 누르면 패스워드를 설정하라는 문구가 나온다. 여기서 패스워드를 설정해주면 된다. 입력할 때 입력되는것이 보이지 않으니 주의.
- public key 복사하기
패스워드까지 입력했다면 key가 있는 경로를 알려준다.
Your public key has been saved in /c/Users/... /.ssh/id_rsa.pub.
위 경로대로 따라가서 .pub 파일을 메모장으로 연 후 내용을 전부 복사한다.
- 깃허브에 설정하기
깃허브에 가면, settings 에 SSH and GPG keys 라는 페이지가 있다. 거기로 이동하여 New SSH key 를 눌러 하고싶은 타이틀과 복사했던 내용을 붙여넣으면 private 레포지토리 설정이 끝났다!
2. Git lfs 설정
Git lfs는, 100MB 이상이라 올릴 수 없는 파일을 여러개로 쪼개 분할 업로드 해주는 시스템이다. Unity를 다룰 때에는 이것이 필수이기에, (아무래도 .dylib 파일이 용량이 좀 큰 듯 하다.) 바로 설정해주었다.
파일 탐색기에서 생성했던 레포지토리 파일을 찾아 거기에 git bash를 연 후, 아래 명령어들을 순서대로 입력하면 lfs가 프로젝트에 적용된다.
$ git lfs install
$ git lfs track "추적할 파일의 확장자"
$ git add .gitattributes
잠깐! 거기에 git bash는 어떻게 열어요?
git bash를 열어서 일일이 cd ~~ 해서 들어가도 되지만,

우클릭 하면 Git bash Here 이라는 것이 있다. 이걸 누르면 여기서 열린다.
그리고, 만약 무슨 파일이 크기가 커서 안올라가는지 모른다면, lfs를 적용시키지 말고 커밋을 한번 해보면 된다. 오류가 나면서 무슨 파일이 큰지 알려준다.
이제, 개발할 준비가 끝났다!
스플래시 씬 애니메이션 구현
우선, 2D 모바일 게임을 목표하고있기에 애니메이션을 쉽게 만들어주는 DOTween 플러그인을 설치했다.
무료 버전과 유료 버전이 있는데 유료버전이 50% 세일중이길래 눈 딱 감고 유료 결제했다.
무료 버전은 코드 안에서만 애니메이션 코드를 짤 수 있는데, 유료 버전은 무려 인스펙터 창에서 컴포넌트로 애니메이션을 짤 수 있게 해준다...!
그래서, 간단하게 화면 입장 애니메이션을 구현했다.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
public class EnterManager : MonoBehaviour
{
private bool Entered = false;
private bool firstAnim = false;
public Image Logo;
public TextMeshProUGUI TouchToStart;
public Image temp;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonUp(0) && !Entered && firstAnim)
{
Logo.DOFade(0.0f, 1.0f);
TouchToStart.DOFade(0.0f, 1.0f);
Entered = true;
temp.rectTransform.DOMoveY(1716f, 0.5f).SetDelay(1.5f).SetEase(Ease.InOutSine);
}
}
public void firstAnimBool()
{
firstAnim = true;
}
}
클릭을 하면 애니메이션이 한번 실행되고, 이후 클릭에서는 실행되지 않는 코드이다.
그리고, 좀 더 나아가 라이브 배경화면처럼 무한히 움직이는 화면을 구현하였다. DOTween을 쓰려고 했지만, 생각대로 잘 적용이 되지 않아서 결국 FixedUpdate의 힘을 빌렸다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class CloudMoving : MonoBehaviour
{
private RectTransform rt;
private Vector3 returnPos = new Vector3(1620f, 960f, 0f);
private Vector3 endPos = new Vector3(-1610f, 0f, 0f);
private Vector3 firstFloorSpeed = new Vector3(3f, 0f, 0f);
private Vector3 secondFloorSpeed = new Vector3(2.2f, 0f, 0f);
private Vector3 thirdFloorSpeed = new Vector3(1.7f, 0f, 0f);
private Vector3 fourthFloorSpeed = new Vector3(1.2f, 0f, 0f);
private Vector3 fifthFloorSpeed = new Vector3(0.7f, 0f, 0f);
private Vector3 sixthFloorSpeed = new Vector3(0.15f, 0f, 0f);
public int n;
// Start is called before the first frame update
void Start()
{
rt = GetComponent<RectTransform>();
}
// Update is called once per frame
void FixedUpdate()
{
if (rt.position.x <= endPos.x)
{
rt.position = returnPos;
}
else if(n == 1)
{
rt.position -= firstFloorSpeed;
}
else if (n == 2)
{
rt.position -= secondFloorSpeed;
}
else if (n == 3)
{
rt.position -= thirdFloorSpeed;
}
else if (n == 4)
{
rt.position -= fourthFloorSpeed;
}
else if (n == 5)
{
rt.position -= fifthFloorSpeed;
}
else if (n == 6)
{
rt.position -= sixthFloorSpeed;
}
}
}
구름들의 움직임을 나타낸 코드이다. 층별로 나누어 속도를 다르게 해 원근감이 있게 구현하였다.
그 후, 터치했을 때 씬이 넘어가며 그 효과를 주는 애니메이션을 구현했다. 단순히 구름이 오른쪽에서 왼쪽으로 넘어가는 애니메이션이지만, 원근감과 화면을 덮는 연출을 넣어 실제로 구름에 가려져 화면이 전환되는 듯 한 효과를 주었다.
void Update()
{
if (Input.GetMouseButtonUp(0) && !Entered && firstAnim)
{
Entered = true;
for(int i = 0; i < trainContainer.Count; i++)
{
trainContainer[i].rectTransform.DOMoveX(trainContainer[i].rectTransform.position.x + 3000f, 1.5f).SetEase(Ease.InCirc);
}
semiWhite.rectTransform.DOMoveX(-1080f, 0.75f).SetEase(Ease.InSine);
semiWhite_2.rectTransform.DOMoveX(-1080f, 1f).SetEase(Ease.InSine);
white.rectTransform.DOMoveX(-1080f, 1f).SetEase(Ease.InSine).SetDelay(0.5f);
realWhite.rectTransform.DOMoveX(540f, 1f).SetEase(Ease.InSine).SetDelay(0.5f).OnComplete(toMain);
}
}
사실 위에 있던 코드를 조금 수정한 것이다.
이것을 끝으로 스플래시 씬의 애니메이션은 생각한대로 잘 나와주었다.

로딩 씬 구현
로딩 씬이라고는 했지만 생각보다 구현할게 많지는 않았다.
하단에 로딩 바가 움직이고, 중간에 로딩되는 동안 게임에 대한 TMI를 터치하며 넘겨볼 수 있는 Anti-지루함 장치를 마련했다.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Loading : MonoBehaviour
{
public static string nextScene;
[SerializeField] Image progressBar;
[SerializeField] TextMeshProUGUI tipText;
private int randInt = -1;
private string[] tipTexts = {"하늘소 호는 가로 길이가 무려 300미터입니다!\n정말 거대하지 않나요?",
"하늘소 호의 카페에서 파는 구름 라떼는\n헤이즐넛 맛이 난답니다.",
"교환권으로 유료 재화들을 교환할 수 있습니다!",
"카베르나는 1960년에 의문의 폭발로 인해\n생긴 도시입니다.",
"스티머에서 증기기관이 처음 발명되었습니다.",
"한울의 어원은 순우리말 \"한울\"로,\n우주의 순우리말입니다.",
"플라미아에 있는 '꺼지지 않는 불꽃'은 \n 200년 넘게 타오르고 있습니다!"};
void Start()
{
randInt = Random.Range(0, tipTexts.Length);
tipText.text = tipTexts[randInt];
StartCoroutine(LoadScene());
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonUp(0))
{
int curRand = Random.Range(0, tipTexts.Length);
while (curRand == randInt)
{
curRand = Random.Range(0, tipTexts.Length);
}
tipText.text = tipTexts[curRand];
randInt = curRand;
}
}
public static void LoadScene(string sceneName)
{
nextScene = sceneName;
SceneManager.LoadScene("Loading");
}
IEnumerator LoadScene()
{
yield return null;
AsyncOperation op = SceneManager.LoadSceneAsync(nextScene);
op.allowSceneActivation = false;
float timer = 0.0f;
while (!op.isDone)
{
yield return new WaitForSeconds(0.1f);
Debug.Log(progressBar.fillAmount);
timer += Time.deltaTime;
if (op.progress <0.9f)
{
progressBar.fillAmount = Mathf.Lerp(progressBar.fillAmount, op.progress, timer);
if (progressBar.fillAmount >= op.progress )
{
timer = 0f;
}
}
else
{
progressBar.fillAmount = Mathf.Lerp(progressBar.fillAmount, 1f, timer);
if (progressBar.fillAmount == 1.0f)
{
op.allowSceneActivation = true;
yield break;
}
}
}
}
}
여기서 Async라는 키워드를 쓰는데, 솔직히 아직도 이해하지 못했다. 조금 더 공부해보아야 할 듯 하다.
sceneName 변수를 static 키워드를 써 파라미터로 받기 때문에, 이씬 저씬 넘어다닐 수 있는 유동적인 작동이 가능하다.
그리고 TMI를 방출할 문자열들을 배열에 넣어놓고 터치할 때 마다 랜덤을 돌려 변하게 만들었다.
로딩이 간단하지만 전보다 제법 게임같아지게 만들어주었다.
메인 씬 입장 애니메이션 구현
스플래시 씬에서 씬이 넘어가는 애니메이션을 구현한 것을 적절히 바꿔서 반대로 씬이 넘어온 것 같은 연출을 하였다.
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class mainStart : MonoBehaviour
{
public Image semiWhite;
public Image semiWhite_2;
public Image white;
public Image realWhite;
// Start is called before the first frame update
void Start()
{
white.rectTransform.DOMoveX(-1080f, 1f).SetEase(Ease.OutSine);
realWhite.rectTransform.DOMoveX(-1620f, 1f).SetEase(Ease.OutSine);
semiWhite.rectTransform.DOMoveX(-1080f, 0.75f).SetEase(Ease.OutSine).SetDelay(0.5f);
semiWhite_2.rectTransform.DOMoveX(-1080f, 1f).SetEase(Ease.OutSine).SetDelay(0.5f);
}
// Update is called once per frame
void Update()
{
}
}
메인 씬이 말 그대로 메인이기 때문에, 다음 주차에는 메인 씬에 매달릴 것 같다.
에셋 제작
1인 개발이기도 하고, 전부터 모든 것을 혼자 다 하는 개발을 해보고 싶었어서 에셋도 직접 그렸다.
사용한 툴은 메디방 페인트와 일러스트레이터, 포토샵을 활용하였다.
아래는 스플래시 씬에 넣은 예시 에셋이다.

사실 개발보다 에셋 그리는게 시간이 더 많이 걸렸다.
BGM 작곡
에셋과 똑같은 이유로 작곡도 했다. 그림이야 중학교 때부터 그렸기 때문에 술술 그렸지만, 작곡은 이번이 처음이라 처음엔 많이 헤맸다. 하지만 그림 그릴 때처럼 영감이 떠오르면 술술 되는 건 똑같았다. 그리고 무엇보다, 너무 만족스러웠다.
아이 이뻐 내새끼
사용 툴은 온라인 무료 툴인 Bandlab을 사용했다. Studio One도 깔려는 있지만 데모 기간이 끝나 어쩔 수 없었다.
1주차는 프로젝트를 생성하고, 설정하고, 에셋도 그리느라 설렘 반 걱정 반으로 프로젝트를 진행한 것 같다. 다음 주차에도 이럴 것 같긴 하지만, 그래도 설계도가 어느정도 그려진 것 같아 수월할 것 같다.

'1인 개발 > 하늘소 프로젝트' 카테고리의 다른 글
[1인개발 프로젝트] 하늘소 프로젝트 6주차 (0) | 2024.02.25 |
---|---|
[1인개발 프로젝트] 하늘소 프로젝트 5주차 (1) | 2024.02.15 |
[1인개발 프로젝트] 하늘소 프로젝트 4주차 (1) | 2024.02.09 |
[1인개발 프로젝트] 하늘소 프로젝트 3주차 (2) | 2024.02.02 |
[1인개발 프로젝트] 하늘소 프로젝트 2주차 (1) | 2024.01.19 |
안녕하세요! 코드 짜는 농부입니다! 경희대학교 소프트웨어융합학과 23학번 재학중입니다. 문의 : dsblue_jun@khu.ac.kr
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!