7/14 ~ 7/20
*해당 프로젝트에 기여한 날만 작성했습니다., 또한 해당 일지 작성 관련한 것은 기여로 판단하지 않았습니다.
이번 주가 굉장히 많은 일을 빠르게 한 주인 것 같은데요...
다이얼로그 시스템을 완벽히(?) 수정했고, 마찬가지로 대화 중 아이템을 얻거나 잃는 게 가능하도록 했습니다.
드디어 (9) 개발 일지 작성도 완료했습니다. 중간 점검을 통해 잊고 있던 일감과 새로운 일감을 얻었습니다. (후술)
새 일감인 종이 배 레이스를 완성하고, 모세의 기적 기믹도 만들었습니다. (중력 파편 능력 수정)
UI 카메라를 만들어서 중력 파편 능력 때 사용하는 버튼이 가려지지 않도록 하였습니다.
중력 파편 능력도 월드 중심으로 단순한 오른쪽 왼쪽이 아닌 오브젝트를 중심으로 오른쪽 왼쪽으로 능력을 적용하도록 했습니다.
셰이더 그래프를 이용해 미니맵을 만들었습니다. ( + 미니맵 제대로 작동하도록 수정)
마무리로 마지막날 회의를 했습니다.
7/14
자잘한 다이얼로그 시스템 오류를 수정하고 드디어 원활하게 대화 중 아이템을 얻거나 잃는 것이 가능하게 만들었습니다.(9) 개발 일지 작성도 드디어 끝냈습니다. 동아리 때 얻은 종이배 레이스 기믹과 중간 점검 때 잊고 있던 모세의 기적 기믹을 맡아서 일단 급한 종이배 레이스 기믹을 제작 중입니다.
오 이전 개발 일지를 보니까 이전의 제가 귀찮았는지 오늘의 스크립트를 7/12에 작성 했더군요...
더 덧붙여서 보자면

Item에서 상호작용 할 아이템, ItemCount는 상호작용할 개수, Get는 얻거나 잃는 것에 대한 bool입니다.

manager는 인벤토리 매니저를 의미하며 이 스크립트는 제가 아닌 다른 팀원이 작성하였습니다. AddItem 메서드는 인벤토리에 개수만큼 아이템을 넣어주는데, 이때 개수를 정하지 않는다면 자동으로 1로 치환됩니다. 마찬가지로 UseItem는 아이템을 사용하는(잃는) 것을 말합니다. 저 같은 경우 일단 임시로 사용할 아이템이 없으면 "oh no"를 출력하게 두었습니다. 사실 이런 상황이 없어야 하는 게 맞죠. 그러나 일단 작성하였습니다.
다이얼로그 시스템도 전체적으로 많이 바꿨는데요, 이 역시도 어느 정도 7/13에 작성해 두었더라고요. 그래서 간단히

CSVReader 스크립트를 <string, object>를 어차피 다 string 처럼 사용하고 있었으니 <string, string>로 바꾸고 이에 맞게 다른 스크립트 모두 수정해 주었습니다.
완료한 개발 일지는 길어서 골치였던 지옥의 개발 일지(9)를드디어 완료했습니다.
종이배 레이스 관해서는 완료한 7/15에 서술하겠습니다.
7/15
종이 배 레이스를 완성 짓고, 모세의 기적 기믹을 위해 터레인을 복사하였습니다.
종이 배 레이스 기믹은 언더테일의 달팽이 경주를 모티브 삼은 기믹입니다.
*종이배 레이스 기믹 설명
언더테일 달팽이 경주는 3마리의 달팽이 중 노란색이 플레이어가 응원하는 달팽이가 됩니다.
Z 키를 눌러 달팽이를 응원하는 게 가능하며 응원할수록 달팽이의 속도가 빨라집니다.
다만 너무 응원을 과하게 한다면 달팽이는 부담을 갖고 뒤집어지며 불이 타게 됩니다.
반대로 응원을 하지 않는다면 당연히 지게 됩니다.
이런 언더테일의 기믹을 본떠 저희 종이배 레이스 기믹을 기획했습니다.
일단 임시 키인 좌클릭을 하면 플레이어의 배가 움직이게 됩니다.
좌클릭 할수록 배의 움직이는 속도가 점점 빨라집니다.
이때 최대 속도는 매 게임마다 랜덤으로 정해지게 됩니다. (5 ~ 10)
상대 배 역시 최대 속도는 플레이어와 같습니다.
상대 배는 코드 상에서 랜덤 시간마다 속도를 증가하게 되며 최대 속도를 넘지 않으나
플레이어가 최대 속도를 넘게 된다면 배는 침몰되게 됩니다.
(최대 속도에 근접하면 배는 흔들리며 경고를 줍니다.)
언더테일에서는 달팽이에게 응원한 수가 게임 동안 기록되어서 증가 밖에 못하지만
저희 게임에서는 일정 시간이 지나면 상대 배도, 플레이어의 배도 속도가 1씩 감소하도록 합니다.
이렇기에 몇 번 누르고 손을 뗀 체 넋 놓고 게임만 바라봐야 하는 것이 아닌 상대 배를 의식하면서 결승선에 도달할 때까지 긴박감을 유지하도록 했습니다.
재미요소로 플레이어의 상대는 종이배 레이스의 고수인 어느 꼬마인데
꼬마가 플레이어에게 종이 배 레이스를 하자며 이 레이스가 시작됩니다.
꼬마는 고수이기에 처음 3초 동안 운행하지 않고 플레이어가 먼저 출발하도록 양보합니다.
3초가 지나면 이제야 꼬마가 출발하지만 별로 안 가서 플레이어를 따라잡게 됩니다.
코드는 크게 배 매니저, 배 이동과 배 흔들림(+ 침몰)로 이루어져 있습니다.

배 매니저는 별거 없습니다. 단지 레이스를 시작하느냐만 알려주는 용도입니다.
현재 임시키는 J로, 시작 시 OnRace 액션을 실행합니다.

BoatMovement는 모든 종이배의 부모입니다.


여기서 Limit는 최대 속도를 의미합니다. 이 최대 속도는 맨 처음에 랜덤으로 정하게 되는데 최대 속도가 static이기 때문에 모든 종이배가 같은 값을 공유하게 됩니다.
그리고 클릭 수와 재는 시간을 초기화해줍니다. 클릭 수는 간단히 현재 속도의 단계를 말하며 재는 시간은 속도를 감소하기 위해 재는 시간입니다. limitTime에 도달할 때마다 속도가 1 감소하게 됩니다.


레이스가 시작 전이면 멈춰있고, 시작하면 앞으로 기본 속도 * 현재 속도(단계)의 속도로 이동하게 됩니다.

업데이트에서는 늘 결승선 도착 여부를 확인하고 있습니다.

이 메서드는 자식에서 실행하고 있고, 정해둔 시간이 지나면 속도를 자동으로 1 감소시켜주게 됩니다.

이 메서드 역시 자식에서 실행하고 있고 클릭할 때마다 실행되며 (적은 랜덤 시간마다) 속도가 오르며 속도가 최대속도를 넘게 되면 레이스가 패배로 종료됩니다. 이 액션 실행 시 지거나 이긴 경우를 알려주는데 정확한 것은 후술 하겠습니다.

플레이어 배에 대해 설명하고 싶으나 그전에 먼저 이 스크립트에 대한 설명을 하고 넘어가야겠습니다.
BoatShake는 간단히 승리 & 패배를 할 때 이를 알려주는 스크립트이며 이름에서 그렇듯 배를 흔들어주는 (+ 가라앉는) 스크립트입니다.
시작을 하면 ConstantForce를 받아줍니다. 조금 생소할 수도 있다고 생각합니다만(저는 그랬어서...)

Force는 해당 방향으로 중력을 주게 됩니다. Relative Force도 마찬가지인데, Force는 월드, Relative Force는 로컬 좌표라는 점이 다릅니다.
마찬가지로 Torque는 월드 좌표로 해당 방향으로 회전을 주며 Relative Torque는 로컬 좌표로 회전을 주게 됩니다.
이를 알게 된 계기는 사실 중력을 쓰기 굉장히 애매해서 찾아보다가 알게 되었습니다. 덕분에 삶이 윤택해진 기분입니다.
덕분에 중력 파편 능력의 골머리도 이를 이용해 해결했습니다. (리지드 바디의 중력을 사용 안 함)
아무튼 그러하고 앞전에 후술 하겠다던 isRaceEnd 액션을 사용하는 메서드가 벌써 나왔는데요.

패배라고 하긴 했으나 true면 승리, false는 패배를 의미합니다. 패배하게 되면 배가 침몰됩니다.
이 메서드 자체는 오직 플레이어만을 위한 것인데 이게 무슨 말이냐면 '플레이어'가 결승선에 도달하거나 '플레이어'의 속도가 최대 속도를 넘겼을 때 실행하게 됩니다. (그래서 패배 시 배가 침몰하게 됩니다.)
적에 대한 것은 적 배에 모두 서술되어있습니다. ( BoatShake 경우 오직 플레이어 배를 위한 스크립트라서 승리 여부도 플레이어를 위한 것입니다.)

외의 메서드로 간단히 좌우로 흔들도록 지정하는 메서드입니다.
이는 플레이어 배에서 요긴하게 반복하여 사용됩니다.

업데이트에서 아까 바꾼 값에 따라 배를 흔들게 됩니다. isRight에 따라 오른쪽 회전(+) 인지 왼쪽 회전 (-)인지를 정합니다.
if(curRotate> rotate)의 경우는 아까 배가 침몰되었을 때를 의미합니다. (흔들 때는 더 적게 움직입니다.)
애초에 90 이상 회전하면 물에 완전히 젖기 때문에 이후는 그냥 전복시키고 ConstantForce를 삭제하여 더 가라앉지도, 혹시라도 다시 실행도 불가능하도록 만들었습니다.

드디어 플레이어 배입니다. 당연하게도? BoatMovement의 자식입니다.
isShake는 배를 흔들고 있는지를 확인하는 용도입니다. (흔들기를 중복하지 않으려고)
IsMy로 플레이어 배임을 구분합니다. 그랬는데...

쓰지도 않았는데 왜 지우지도 않았는지... 이거 쓰면서 지웠습니다.

레이스 시작이고 결승선에 들어왔다면 레이스 승리함을 알려줍니다. 또한 레이스를 종료시킵니다.
아직 흔드는 중이 아니고 현재 속도 + 1 이 최대 속도에 도달하면 경고로 배를 흔들도록 합니다.
반대로 흔드는 중인데 이제 속도가 늦춰져서 + 1이 되더라도 최대 속도가 아니라면 배를 흔드는 것을 멈추게 됩니다.
음... if(! isRace) return; 을 맨 처음에 붙이는 게 나을 것 같은데 왜 저랬는지 모르겠습니다. 일단 수정했습니다.
임시 키로 마우스 좌클릭을 하면 배의 속도를 올리도록 했습니다. (위의 Move 참고)
마찬가지로 늘 시간을 재서 일정 시간마다 속도가 감소하도록 했습니다. (속도는 늘 1 이상)
꽤 간단한 스크립트입니다.

마지막인 적 배입니다.
(IsMy 같은 경우 지웠기에 아까와 달리 없습니다.)
myRaceTime은 봐주는 시간을 재게 됩니다. 레이스 시작 후 limitMyRaceTime정도 지나면 이제야 출발하게 되는 셈입니다.
play가 붙은 변수는 단지 플레이어는 직접 좌클릭마다 속도가 느는데 적 배는 경우가 랜덤 시간마다 자동이므로 playTime은 시간을 재고 limitPlayTime은 매마다 랜덤 시간을 정하는 용도입니다.

레이스가 시작할 때 기다려 주겠다고 합니다.

레이스 중이며 결승선에 도달하면 적이 승리하게 되며 레이스는 종료됩니다.
isDelay가 true 즉 아직 기다려주는 중이면 시간을 재고, 시간에 도달하면 출발을 하겠다고 합니다.

*CountTime
다음은 시간에 랜덤 시간에 따라 속도를 올리게 됩니다.
그 밑은 플레이어 때와 같은데요, 시간을 재고 속도를 감소시키며 1 이상을 유지하게 됩니다.

기존 배에서는 isRace만 확인하면 되었지만 적 같은 경우 isDelay도 신경 써야 하기 때문에 부모의 FixedUpdate는 따르지 않도록 했습니다.
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
보다시피 잘 되는 것을 확인할 수 있습니다.
7/16
중력 파편 능력 관련해서 스크립트를 살짝 수정했습니다.
URP를 수정하여 UI 카메라를 제작했습니다.
오브젝트 방향에 따라 중력 방향이 바뀌도록 했습니다. (월드 좌표 -> 로컬 좌표)


간단히 obj.transform.rotation * GravityDirection을 사용해 구현했습니다. 스위치 문을 스위치 식으로 변경한 것은 더 이후의 일이나 쓴 김에 간단히 서술하자면 받은 string을 ToLower을 통해 전부 소문자로 바꾸고 그 값에 따라 벡터 방향을 전달했습니다.
스위치 문 때는 뭔갈 더 넣을 생각에 일부러 스위치 문을 썼으나 수정을 하고 보니 더 추가할 것이 전혀 존재하지 않다고 판단하여 그냥 스위치 식으로 변경했습니다.
UI카메라가 시간을 정말 많이 잡아먹었습니다... 찾아봐도 죄다 유니티 6 이전 버전에다가 gpt까지 동원해서 찾아 찾아 겨우 설정에 성공했습니다.
갑자기 잘 쓰다가 왜 UI 카메라를 만드냐? 싶으실 수 있는데 이는 이전에는 능력 사용 UI를 오브젝트 외곽선에 두었습니다.
그러나 이번에는 오브젝트 크기가 엄청 클 때 UI가 외곽선에 둔다면 UI가 카메라 밖에 나오기 때문에 사실 능력이 무용지물이 됩니다.
그래서 UI를 특정 크기만큼? 몰리도록 하였는데 이때 문제는 UI가 오브젝트에 가려져 보이지 않는다는 것입니다.
그래서 UI 카메라를 만들어 UI가 가려지지 않도록 만들어봤습니다. 정확히는 설정을 건들었습니다.

메인 카메라 자식으로 UI 카메라를 만듭니다.

UI 카메라의 Culling Mask를 UI만 택하고 반대로 Main 카메라에서는 UI만 껐습니다.


그리고 UI 카메라를 오버레이 하면 끝입니다만... 우습게도 저에게 허락되지 않았습니다. (위 사진은 해결했기에 가능한 장면입니다.)

원인을 찾으러 여정을 떠났고 그 결과 해당 경로로 들어가면 됨을 알게 되었습니다.
저대로 해서 못했고


정말 뻘짓을 열심히 하고 있었는데 뒤져보다가 우연히 발견했습니다. 그리고 Forward+를 체크해 주시면 이제 오버레이를 하실 수 있습니다.

7/17
미니맵을 작동가능하게 수정하고 셰이더 그래프로 미니맵 셰이더를 만들었습니다.

미니맵의 생김새를 추구한 것과 가장 비슷한 것은 원신에서의 미니맵과 가장 흡사했습니다.
둥글고 테두리에 얇은 선이 있으며 그 안에서는 불투명하게 되어있는 것을 원했습니다.
예전에 수업 때 셰이더를 배우긴 했으나 안타깝게도 기억나는 것은 Sample Texture 2D, Add, Multiply, Transform, Color 정도밖에 없었습니다. 따라서 많은 시행착오를 겪으며 대략 5시간 반정도를 소모했습니다.
그래서 꼴이 매우 처참하긴 하나 그래도 원하던 바를 이루어내긴 했습니다.
일단 두 가지 버전이 있습니다.
첫 번째는 한 셰이더에 모든 것을 구현 한 버전, 두 번째는 테두리 셰이더, 미니 맵 셰이더로 나눈 것입니다.
먼저 첫 번째 버전의 셰이더는

dot(particle) 이미지를 이용해서 마스크를 만들고자 했습니다. 그래야 미니맵이 테두리가 불투명하게 보일 테니까요.
그러나 이미지 크기가 너무 작아서 제대로 사용하기가 어려워서 위에 보시다시피 저런 과정을 통해 크기를 키웠습니다.
Add을 건너뛰면 크기가 작아지고, Multiply를 건너뛰면 갑자기 외는 어둑하고 블러질이 심화가 되고, Saturate를 건너뛰면 발광이 심해지고 솔직히 왜 되는지는 모르겠지만 운이 좋게도 여러 가지 이어보니 어떻게 되었습니다.
Add는 검은 부분에 칠을 하고 Multiply는 흰 부분에 칠을 하는 것 같습니다. (잘 모르겠어요...)

다음은 테두리 선입니다. Comparison에서 가져오는 건 둘 다 아까 마스크에서 Multiply까지 가져온 것을 이어줬습니다.
Comparison에서는 텍스쳐를 B숫자만큼 투명 정도를 (1이면 완전히 불투명, 0 전부) 가져오는 것입니다.
Greater는 가져온 것을 하얀색, 외는 검은색으로 표시하고
Less는 반대로 가져온 것을 검은색, 외는 하얀색으로 표시합니다.
미묘한 차이가 있을 수 있지만 Greater - OneMinus(반대) == Less 인 것 같습니다.
위에서는 0.1로 적당히 테두리를 가져오도록 했습니다.
0으로 하면 너무 지저분해 보여서...
아래는 0.12로 위보다는 숫자를 살짝 늘려서 테두리가 보이도록 만들었습니다. (더 작게는 아예 보이지가 않아요.)
Multiply를 사용해서 테두리 형태가 보이도록 했고, OneMinus는 사용하지 않았습니다. 삭제를 잊었나 봅니다.

다음은 테두리의 선을 칠해줍니다.
딱 테두리만큼 선을 칠해 주고 싶었는데 그러면 제대로 보이지가 않더군요...
저 외부로 이어지는 선 전부 아까 테두리에서 아래 거를 연결하고 있습니다. 그 이유는 테두리 선이니까 테두리 밖에서부터 색을 칠하면 아무런 의미가 없고, 전부 칠하면 그건 테두리 색이 아니니 테두리가 시작되는 즉, 내부의 테두리 선의 격인 아래의 것을 이은 것입니다.
아래가 원 부분이 검정, 외 부분이 하얀색이기에 Add 가 아닌 Multiply를 이용해 색을 냈습니다.? 엇... 뭔가 이상하다 싶어서 방금 막 수정했는데 전 멍청했습니다...

왜 썼나 싶어서 삭제했는데 아무런 문제가 없군요. 음 이걸로 설명하자면 일단 OneMinus로 반전시켜줍니다.
Add는 검은색에 칠하기 때문에 Color를 해도 검정색에 잘 칠해지는 것을 볼 수 있습니다.
다시 돌아가서 Image는 이미지로 미니맵을 담고 있습니다.
Add를 이용해 외 부분을 하얀색으로 만들어 방금 만든 테두리 색이랑 합체하고자 합니다.
마지막으로 Multiply를 이용해서 테두리 색에서 하얀 부분을 미니맵이 그려지도록 했습니다.
이렇게 해서 테두리 색도 완료 했습니다.

미니맵 전용이니 Canvas를 켜주었습니다.
그리고 투명도를 위해 Alpha를 켜주었습니다.

아래에는 마스크와 테두리 (색 말고)를 결합한 것입니다.
이것의 투명도를 통해 마스크가 적용이 되도록 합니다.
Base Color(3) 에는 미니맵 + 테두리 색을 연결하여 보이도록 하고, Alpha, Alpha clip Treshold(1)에는 투명도를 연결했습니다.
Alpha에 연결을 안 하면 아예 투명도가 사라지며, Alpha clip Treshold(1)에 연결을 안하면 단순히 0과 1로 보이고 안 보이고만 됩니다. 비유하자면 아까 Comparison에서 1로 되어있는 것이죠.
아무튼 이리하여 완성했습니다.


사실 이 셰이더는 실패이기 때문에 씬에서는 안 보여 드리고 간단히 셰이더 내에 프리뷰를 보여 드리겠습니다.
보면 테두리가 쭈글쭈글하고 블러질이 시원치 않다는 것을 느낄 수 있습니다.
그래서 실패했습니다.
이제 성공한 두 번째 방법은 간단합니다.

일단 성공 이유가 이미지가 있어서입니다. 테두리 이미지에 심지어 블러질 된 원(마스크) 조차 이미지를 얻고 시작했거든요!

Line(T2)에는 테두리 이미지가 들어있으나 왜인지 셰이더에서 투명 이미지는 검정으로 치환되는 것 같습니다.
아무튼 이를 Alpha에 연결, 원하는 색 또한 지정 가능하게 하여 Base Color(3)에 연결해서 초 간단히 테두리를 완성했습니다.
정말 허무하더군요!
이제 핵심인 미니맵입니다. 이도 마찬가지로 쉬운데요.

사실 UI내의 마스크 기능을 쓰려다가 투명도가 적용이 안돼서 급하게 만들었습니다.
저기서 Add를 연결하는 등 번거롭게 되어있는데

A(1)를 Alpha(1), Alpha Clip threshold(1)를 연결해도 되더라고요. 이미지가 검정으로 나오니 헷갈렸나 봅니다.

이렇게 해서 마스크도 완성했습니다.

아쉽게도 현재 씬에서 오류가 있는 터라 영상으로는 못 보여 드리나 일단 사진으로 보여 드리자면
테두리(원하는 색 지정 가능) 있고, 미니맵 겉에도 블러질이 잘 되어 있는 것을 확인할 수 있습니다.

참고로 미니맵 카메라는 플레이어 자식으로 잘 따라오며 플레이어가 돌 때 미니맵 UI에서도 도는 모습을 볼 수 있습니다.
미니맵 카메라 자체는 이전 미니맵을 맡은 팀원이 만들었고 이상한 스크립트 붙여 놨길래 그거 빼고 플레이어 자식으로 만든 것 밖에 안 했습니다.
(미니맵 만드는 관련 블로그는 예전에 https://neeeeding.tistory.com/3 여기에 작성했습니다.)
7/20
회의를 했습니다.
*7/18, 7/19는 진행 사항이 없습니다.
일지
이전 일지 > https://neeeeding.tistory.com/35
네오위즈 개발 일지 (10) - 개발 일지 작성 & 중력 파편 능력 7/7 ~ 7/13
7/7 ~ 7/13*해당 프로젝트에 기여한 날만 작성했습니다. 중력 파편 능력을 구현하고 티스토리에서 개발 일지를 작성하기 시작했습니다.또 다이얼로그 시스템을 살짝 수정 했습니다. 7/7 선택한 물
neeeeding.tistory.com
다음 일지 > https://neeeeding.tistory.com/37
네오위즈 개발 일지 (12) - 종이 배 레이스 & 모세의 기적 7/21 ~ 7/27
7/21 ~ 7/27*해당 프로젝트에 기여한 날만 작성했습니다., 또한 해당 일지 작성 관련한 것은 기여로 판단하지 않았습니다. 한 일 내용 7/21 바람?을 위해 중력 파편 능력을 살짝 수정했습니다.너무 살
neeeeding.tistory.com
'네오위즈' 카테고리의 다른 글
| 네오위즈 개발 일지 (13) - 게임잼 7/28 ~ 8/3 (4) | 2025.08.03 |
|---|---|
| 네오위즈 개발 일지 (12) - 공기(중력 능력) 7/21 ~ 7/27 (0) | 2025.07.21 |
| 네오위즈 개발 일지 (10) - 개발 일지 작성 & 중력 파편 능력 7/7 ~ 7/13 (1) | 2025.07.13 |
| 네오위즈 - 개발 일지 (9) - 다이얼로그 시스템(+CSVReader) 6/30 ~ 7/6 (0) | 2025.07.10 |
| 네오위즈 - 개발 일지 (8) - 진행 무 6/2 ~ 6/29 (1) | 2025.07.09 |
