일반적으로 서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식. 클라이언트가 사용하는 언어에 관계없이 통일된 데이터를 주고 받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 저장, 표시할 수 있음. XML의 대안으로 사용되고 있음.
현재 진행중인 졸업 프로젝트에서 사용할 학과 데이터, 강의 데이터, 건물 데이터가 필요한데 데이터들이 좀 많아서 유니티 내부에서 스크립트에 정의하지 말고 구글 스프레드 시트에 데이터를 다 입력한 다음 그 데이터를 JSON으로 변환해 프로젝트에서 보관해서 게임이 시작될 때 그 데이터들을 다 로딩하고 써먹기로 했다.
먼저 CSV 파일로 데이터를 작성한 다음 JSON으로 변환해주는 과정을 거쳤는데 이 때 내가 사용한 사이트는
원래 겨울방학동안 있었던, 했던 일들을 겨울방학에 정리하려 했는데 어찌어찌 지금 쓰게 됐네 ㅎㅎ,,
3학년 2학기
우선, 힘들었던 3학년 2학기 내 인생 최대 학점 달성!(물론 부전공 1학년 과목 때문이지만 어쨌든)
가장 도움이 됐던 강의는 가상현실이라고 말할려 했지만 모바일프로그래밍으로 정정
그 이유는 강의의 질보다는 이 강의에서 얻어간 것 때문이다. 팀프로젝트로 안드로이드 스튜디오로 만든 단순 클리커 게임을 만들어 봤는데 여기서 배운 경험이 유니티를 쓸 때 도움이 됐던 것 같아서다.
그리고 같은 학과의 게임 개발을 같이 공부하는 형을 만나서 큰 도움이 된 것 같다.
겨울 방학
우선 겨울 방학동안 처음 생각했던 것들은 우선 졸업을 위한 토익 800 달성, 책보면서 게임 엔진 공부, 그리고 연합 게임 동아리를 들어가기 위한 준비였다.
버닝 비버
아 그리고 가장 인상깊었던 경험은 처음으로 인디게임 페스티벌을 갔는데 '버닝 비버 페스티벌'을 갔었다.
기대안하고 갔는데 여러 게임을 즐겨보니까 오히려 덜 즐긴것 같아 후회가 됐다. 여기서 본 게임 중 가장 인상깊었던 건 IRA와 산나비였다. IRA는 줄이 길어서 해보진 못했는데 재밌어보여서 다른 사람들이 하는거 계속 봤고, 산나비는 튜토리얼에서 신박함을 느껴 재밌게 했었다.
냐한 남자 팀 가입
전혀 뜻하지 않게 팀에 가입하게 됐는데, 친구의 추천으로 들어가게 된 팀이다. 처음 제안받았을때는 유니티도 써보지 않은 뉴비가 이미 출시한 게임의 클라이언트 팀에 들어가면 민폐만 되는게 아닌가 해서 거절할려했는데 이미 출시한 게임을 유지보수한다는 것만 해도 내게 있어 큰 도움이 될 것 같아 들어가게 되었다.
어찌어찌 유니티 책을 여러 권 보면서 C#과 유니티 기능들을 익혔고 처음 대면 만남을 가지고 지금까지 계속 팀원분들의 요구를 받아 코드를 분석하면서 공부 중 이다!
연합 동아리 'Bridge' 가입
게임 개발을 공부하면서 언젠가는 동아리에 들어가서 여러 직군과 함께 게임을 만들어 보고 싶다고 꿈꿔서 이번 겨울 방학에 간단한 포트폴리오를 만들고 프로그래밍으로 지원하게 됐다. 결과는 운좋게 합격했다. 그 후 비록 지금은 팀선택도 못해 찬밥 신세가 됐지만 열심히 공부해서 선택받는 플머가 돼야지 ㅠㅠ
이번 3학년 2학기에 모바일 프로그래밍 강의를 수강했는데 중간고사는 실습이었고 이번 기말고사로 팀프로젝트로 어플을 만들고 발표하는 시간을 가졌다.
사실 이 강의 담당 교수님이 맡은 건 거의 팀플이 있어서 팀플할 때 주제를 뭘로 할지 정하고 들어갔었다.
바로 게임을 만들고 싶었는데 사실 모바일 게임은 거의 유니티 엔진을 사용해서 만들기 때문에 안드로이드 스튜디오로도 만들 수 있을까 해서 시도해 본 것이다.
게임 장르는 안드로이드 스튜디오로 구현하기 쉬울 것 같은 클릭 위주의 타이쿤을 하기로 했다. 팀이 구성되고 주제를 설명해주니까 감사하게도 제안을 승낙해주셨고 곧바로 개발을 시작했다.
협업용으로 깃헙을 썼고, 위젯이나 배경화면에 쓸 디자인은 피그마를 사용했고 그리고 로그인, 회원가입에 쓸 데이터베이스는 retrofit을 썼다. 뒤에 두 가지는 선배님이 맡아주셔서 편하게 클라이언트 개발만 하면 됐다.
코드는 나 혼자 짠게 아니라 여기 올리진 못할 것 같고 플레이 영상을 올려두겠다
게임 설명을 하자면
제목과 같이 토스트를 만들어 파는 게임이다. 각기 다른 손님이 들어와 각기 다른 주문을 하고 사람마다 인내심이 다르다는 점을 이용해서 테이블마다 다른 시간이 독립적으로 흘러가게 했다.
그래서 주문받은 음식을 주방으로 돌아가 레시피를 확인하여 만들고 재료를 얼마나 정확하게 넣었느냐에 따라 음식 퀄리티가 주어진다(0~60). 그래서 음식을 만들면 홀에 있는 완성된 음식 리스트에 들어가고 이 리스트 아이템을 클릭하면 커스텀 대화상자가 떠 그곳에서 테이블에 맞게 서빙을 한다. 서빙에 성공하면 음식의 퀄리티가 점수에 더해지고 음식의 퀄리티에 따라(0 ~ 20: 하, 30 ~ 40: 중, 50~ 60 : 상) 별점을 올리거나 유지하거나 내린다. 별점은 게임의 목숨으로 이해하면 된다.
그래서 게임 시간으로 15시가 되면 마감하고 하루가 끝나며 정산 화면이 나온다. 계속을 누르면 다음 스테이지로 가고 Day가 늘어날수록 손님의 인내심 시간이 더 떨어진다. 이렇게 Day 3까지 클리어 해서 정산 후 계속을 누르고 랭킹을 보면 나의 랭킹이 제대로 들어간 것을 확인할 수 있다.
나중에 시간이 되면 더 자세하게 리뷰하고 싶다.
<느낀 점>
이번 프로젝트를 통해 처음으로 모바일 프로그래밍을 해보면서 휴대폰의 어플에서 이런 부분은 이런 기능을 썼겠구나 유추할 수 있는 능력을 키울 수 있었고, 이번에 깃허브로 처음 제대로 협업을 해봤는데 괜히 깃허브를 쓰는 게 아니라는 것을 알았다. 안드로이드 스튜디오를 이용해 게임을 만들어보면서 나중에 유니티로도 이런 게임을 만들 때 배경지식으로 쓸 수 있겠다고 생각이 되고, 기회가 된다면 이 게임을 유니티로 옮겨 혼자서 제대로 넣고 싶은 기능 추가해보고 그러고 싶다.
주방에서 만들어진 토스트가 홀에 있는 서빙 목록으로 들어가 차례대로 쌓이는 마치 리스트처럼 구현하고 싶었다.
그래서 방법을 찾던 중 ListView 레이아웃이 가장 적합할 것 같아 써보았다.
대부분 구글링을 통해 참고해서 구현했기 때문에 참고한 블로그들을 적어놓겠다
리스트 뷰를 쓰기 위해 어댑터를 만들어 토스트를 넣을 리스트와 class로 만든 어댑터를 연결시킴
ArrayList<Food> items;
...
items = new ArrayList<>();
final GameAdapter adapter = new GameAdapter(this, items);
listView.setAdapter(adapter);
Food 자료형은 토스트를 나타내기 위해 만든 클래스인데 이름, 음식의 만족도를 나타내는 quality가 있고 간단히 생성자만 구현해놨다.
// 만들어진 토스트의 정보
class Food
{
String name; // 무슨 토스트인지
float quality; // 토스트의 음식 완성도
Food(String name, float quality)
{
this.name = name;
this.quality = quality;
}
}
그리고 GameAdapter를 만들었다. getView 함수는 리스트 뷰에 있는 각 아이템에 적용될 xml 파일을 적용해서 그 xml 파일에 있는 버튼을 꾸며준다?
public class GameAdapter extends BaseAdapter {
Context mContext = null;
LayoutInflater mLayoutInflater = null;
ArrayList<Food> items;
public GameAdapter(Context context, ArrayList<Food> items)
{
mContext = context;
this.items = items;
mLayoutInflater = LayoutInflater.from(mContext);
}
public View getView(int position, View convertView, ViewGroup parent)
{
View view = mLayoutInflater.inflate(R.layout.listview_item, null);
Button btn = (Button) view.findViewById(R.id.serve_list);
btn.setText(items.get(position).name);
return view;
}
@Override
public Food getItem(int i) {
return items.get(i);
}
@Override
public int getCount() {
return items.size();
}
@Override
public long getItemId(int i) {
return i;
}
리스트 뷰에서 각 아이템을 클릭하면 커스텀으로 만든 대화상자가 떠서 테이블로 서빙할 지 고를 수 있게 하는데 이를 위해 리스트 뷰의 ItemClick 리스너를 통해 구현한다. 근데 여기서 30분 정도 헤맨 게 있는데 리스트 뷰에 있는 아이템들의 xml 컴포넌트가 클릭할 수 있는 버튼이나 이미지 버튼 같은 경우 클릭할 수 있는 그런걸 꺼줘야 리스너가 잘 작동했었다.
언리얼 엔진을 어느정도 익힌 후 이때까지 배운 내용들을 복습하는 김에 조그마한 게임을 하나 만들어보고 싶어서 간단하게 개인 프로젝트를 만들어보려고 한다. 원래는 노션에서 작성하려고 했는데 동영상 올리기가 어려워서(용량 문제) 다시 티스토리를 이용하게 되었다.
만드려고 하는 게임은 언리얼의 블루프린트를 이용할 것이다. 아무래도 처음 만드는 거니까 C++로 하기에는 어려울 것 같아서 블루프린트로 만든 후 만든 기능들을 C++로 바꿔보면서 C++로 작성했을 시의 이점을 느껴보려 한다.
제목에도 나와있듯이 게임 이름은 '기사는 처음이라' 이고 3인칭 방식, 그리고 캐릭터의 움직임 등 대부분은 로스트아크와 비슷하게 구현해보려 한다. (내가 많이 하는 게임이라서) 게임 장르는 솔직히 아직 결정하지는 못했다. 그냥 RPG만 넣기에는 밋밋해서 시뮬레이션 느낌을 좀 첨가해보려고 한다.
자세한 스토리를 말하자면 흔한 설정으로 집에서 놀고있던 취준생이 갑자기 이세계에 소환되고 그 세계에서 기사 훈련을 받아 보스를 처치하러 가는 스토리이다.
보스를 처치하러 가는 구간은 흔한 RPG에서 나오는 방식으로 구현하고 기사 훈련을 받는 건 일본에서 유명한 게임인 우마무스메에서 영감을 받아 기사를 키우는 방식으로 공격력, 방어력, 체력, 스킬 등을 시뮬레이션 방식으로 배울 수 있게 만드려고 한다.
우리의 주인공
캐릭터 애셋은 믹사모에 있는 것을 무료로 다운받아왔다. 어도비 최고
캐릭터 이동
캐릭터는 마우스 우클릭으로 가고자 하는 곳을 찍으면 캐릭터가 이동한다. 캐릭터를 바라보는 카메라는 고정이고 캐릭터는 클릭한 방향으로 바라본 후 이동한다.
캐릭터 이동
캐릭터(폰)를 움직임이려면 캐릭터를 조종하는 컨트롤러가 있어야 한다. 그래서 캐릭터 블루프린트, 캐릭터 조종할 컨트롤러 블루프린트, 이 게임에서 쓸 게임모드 블루프린트가 있어야 하고 프로젝트 세팅에서 게임모드를 설정하고 쓸 캐릭터, 컨트롤러를 지정해주자
이제 움직임을 구현해보자. 구현하기 위해 우선 마우스 우클릭에 액션을 매핑해줘야 우클릭 시 이벤트가 발생해 캐릭터의 이동을 구현할 수 있을 것이다.
프로젝트 세팅 > 입력 > 액션 매핑
이제 아까 만든 컨트롤러 블루프린트로 가자. 노드 네트워크를 먼저 보여주고 설명하겠다
컨트롤러 블루프린트 > 이벤트 그래프컨트롤러 블루프린트 > Move To Hit Location 함수
Tick 이벤트에서 우클릭 입력 여부를 받아 게임이 진행되는 동안 계속해서 받는다.
Gate 노드를 이용해 우클릭 누름(Open) ~ 우클릭 뗄 동안(Close) Exit에 연결된 출력 핀이 실행되고, Move to Hit Location 함수가 실행된다(그 전에 if 노드들은 다음에 설명할 공격하는 동안, 구르는 동안 못 움직이게 설정해놓은것)
Move to Hit Location 함수를 설명하면 일단 매개 변수가 있는데 이는 Hit 구조체 타입의 매개변수임.
이는 Get Hit Result Under Cursor by Channel 노드에 있는 Hit Result인데 나는 클릭한 곳의 정보를 담고 있는 구조체라고 이해했다. 그래서 함수로 다시 들어가보면 Hit 구조체를 Break한 Break Hit Result 노드에 있는 Location을 이용한걸 볼 수 있다. 이는 클릭한 곳의 위치 정보로 보면 된다.
현재 캐릭터의 위치와 클릭한 곳의 위치 사이의 거리가 지역 변수인 Min Click Distance 보다 작으면 움직이지 않고 크거나 같으면 위치정보만 주면 그 위치로 이동시키는 Simple Move to Location을 써서 이동을 시켰다.
-> 언리얼의 탑다운 템플릿을 거의 참조했다
이 상태에서 실행하면 그냥 캐릭터는 앞만 바라보고 이동만 할 것임. 그래서 우클릭한 방향으로 캐릭터를 회전시켜야 한다. 회전을 설정해주기 위해 캐릭터 블루프린트에서 작업을 한다.
캐릭터의 컴포넌트들을 살펴보면
여기서 카메라가 아니라 스프링암임 ㅈㅅ
우리는 여기서 네모 박스친 세 개의 컴포넌트를 약간 조절할 것임
1. 셀프를 클릭하고 우측에 있는 디테일 > 폰 항목을 보자
여기서 Use Controller Rotation Yaw를 체크를 풀어줬다.
언리얼에서 설명을 보면
음, 설명만 봐서는 정확히 이해가 안간다. 체크하면 폰의 Yaw와 컨트롤러의 Yaw가 연동된다 -> 체크를 해제하면 독립적으로 움직인다. 이는 이따가 살펴볼 어떤 기능 때문에 해제한것같은데 그 기능은
2. 캐릭터 무브먼트 컴포넌트에 있는 캐릭터 무브먼트(회전세팅)
위에 있는 Use Controller Desired Rotation은 설명을 보면 부드럽게 회전한다인데 끄나 키나 상관은 없는 것 같다.
중요한건 Orient Rotation to Movement인데
이게 캐릭터의 움직임 방향으로 캐릭터(폰)를 회전시켜주는 기능인 것 같다. 이걸 끄고 실행을 돌려보자
캐릭터가 앞만 보고 움직인다. 그래서 움직일 방향으로 회전시키려면 이 기능을 키자. 그런데 이걸 키고 아까 셀프에 있는
Use Controller Rotation Yaw를 True로 하면?
얘도 회전을 안한다. 그래서 Use Controller Rotation Yaw도 꺼줘야 정상적으로 클릭한 방향으로의 회전이 가능하다.
3. 스프링 암 컴포넌트에 있는 카메라 세팅
Use Pawn Control Rotation이 구글링해서 찾아보면 카메라가 폰의 회전에 고정된 상태를 유지하도록 하는 것으로 설명하는 사람들이 많은데 내 프로젝트에선 이걸 키나 끄나 똑같이 동작한다. 근데 GTA에서 캐릭터를 움직일 때 처럼 마우스로 보고 싶은 방향을 보면 폰이 그 방향으로 회전하고 카메라도 같이 회전할 때 이런 경우에 쓰는 걸로 알고 있다. 그래서 내 프로젝트에서는 크게 중요하지 않은 것 같으니 일단 패스
이렇게 회전까지 마쳤다.
줌 인 / 줌 아웃
로스트아크에서 마우스 휠을 움직여보면 캐릭터를 확대, 축소해서 볼 수 있는데 이와 유사하게 만들어보자
캐릭터 블루프린트에서 줌 인 상태를 나타내는 IsZoom 부울 변수를 만들고 프로젝트 세팅 > 입력에서
Zoom-In, Zoom-Out 액션을 만들자.
휠을 위로 올리면 ZoomIn 이벤트가 실행, 아래로 내리면 ZoomOut 이벤트가 발생, 각 이벤트가 발생하면 IsZoom 부울 변수의 값을 바꾼다.
캐릭터 블루프린트
이제 이 부울 변수의 값에 따라 카메라의 위치를 조정해주자. 게임이 진행되는 동안 변수의 값을 계속 관찰해야 하기에 Tick 이벤트에서 구현했다.(더 좋은 방법이 있지 않을까 싶다)
캐릭터 블루프린트
IsZoom 값에 따라 다른 매개변수를 입력 받는 View Change 함수가 실행됨. 줌 인/아웃 상태에서 스프링암의 Length, 회전 값인 Rotator가 매개변수이다. View Change 함수를 보자
캐릭터 블루프린트 > View Change 함수
복잡해 보이지만 별 거 없다. 스프링 암 길이,회전 값을 조정하는데 여기서 그냥 바로 조정해버리면 바로 보이는 뷰가 달라져서 좀 딱딱한 느낌을 준다. 그래서 이럴 때 쓰는 언리얼에서 제공하는 Interp 함수를 쓰는데 부드럽게 보간한다?고 보면 된다. Float형을 보간할때는 F를 붙이고, Rotator를 보간할 때는 R을 붙임, V(Vector)도 있음.
Current에는 현재 값, Target은 목표 값, Delta Time은 Tick 이벤트에서 나오는 Delta time을 넣으면 되고, Interp Speed는 그냥 개발자 마음대로 넣어주면 된다. 이제 결과를 보면
부드럽게 줌 인, 줌 아웃이 되는 걸 볼 수 있다
캐릭터 애니메이션
캐릭터 공격, 구르기를 설명하기 전에 애니메이션부터 말하겠다. 캐릭터가 이동하지 않을 때는 Idle 상태, 캐릭터가 공격중일때는 Attack 상태, 구르기 중일때는 Roll 상태, 이동할 때는 Walk 상태로 나눴다. 그래서 캐릭터 블루프린트에 부울 변수로 상태 카테고리에 이렇게 생성해놈
눈 켜논건 디버그 용으로 해놨었는데 상관X
이 상태들을 애니메이션 블루프린트와 연동시키기 위해 애니메이션 블루프린트에 있는 이벤트 그래프 노드를 설정
애니메이션 블루프린트에 있는 변수애니메이션 블루프린트 이벤트그래프
Blueprint Update Animation 이벤트는 일단 Tick으로 이해했다. Speed는 캐릭터의 현재 속력이고 다른 건 다 알거라고 생각. 이렇게 변수들을 연동시키고 애님 그래프로 넘어가자
맨 처음에는 가만히 있는 Idle 상태. 이 상태에서 마우스 우클릭해 이동하면 Speed가 0보다 커져 Walk 상태로 트랜지션 한다.
Idle -> Walk 트랜지션
그리고 Idle이나 Walk 상태에서 마우스 좌클릭을 누르면 Attack 상태로 트랜지션한다. 스페이스바를 누르면 Roll 상태로 트랜지션
Idle 상태로 들어가보면
Idle 애니메이션 4개가 있어서 4개 중에 1개가 랜덤으로 보여짐
Walk로 가면
따로 설정 없이 하면 처음엔 끊겨서 보인다. 왜냐하면 Walk 애니메이션이 한 방향으로 이동하기 때문(애니메이션 따라서)
이를 제대로 수정하려면 Walk 애니메이션이 제자리에서 걷게 만들면 되지 않을까? 그래서 해당 애니메이션 시퀀스에서
루트 모션을 수정해주자.
Force Root Lock을 체크하면 Walk가 제대로 작동하는걸로 볼 수 있다. 언리얼 공식문서에서 루트 모션에 대해 살펴보면 잘 이해가 갈 수 있다
로스트아크에서 좌클릭을 누르고 있으면 공격 모션이 쭉 이어진다. 이를 언리얼에서 구현하기 위해 몽타주를 사용했다.
몽타주는 음 애니메이션을 여러 개 배치해서 한 애니메이션으로 볼 수 있게 하는 기능이다. 자세한 설명은 공식문서 참고
섹션이 3개가 있어 좌클릭을 누르고 있으면 3개의 애니메이션이 순차적으로 나올 것이다. 그런데 현재 영상에서 우측 하단에 프리뷰 보면 Attack1->2->3 <- 이렇게 되어있는데 원래 이렇게 안돼있고 1->2->3 만 되어 있을건데 그렇게 하면 좌클릭을 계속 눌러도 공격 모션이 계속 나오지 않는다. 수정하고 돌려보면
공격하고 그냥 T포즈로 돌아간다. 그래서 Attack3 다음에 링크를 Attack1으로 바꿔주자.
위에 몽타주를 보면 노티파이를 쓴 걸 볼 수 있는데 이는 나중에 시선 방향 바꿀 때 쓸 것이므로 나중에 설명하겠다.
이 몽타주는 이제 볼 게 없고 Attack 구현한 걸 보자.
프로젝트 세팅 > 입력에서 좌클릭 입력에 Attack을 매핑하자
그리고 캐릭터 블루프린트로 가서 Attack 이벤트를 구현해보면
캐릭터 블루프린트 > Attack 이벤트
좌클릭을 누르면 먼저 구르기 여부를 체크한다. 구르는 중이라면 공격을 못하니까, 그리고 Is Attacking을 true로 설정해주고, Look At 함수를 실행해 캐릭터가 클릭한 방향을 보게 하고 Stop Active Movement 노드로 이동을 멈추고 아까 만든 몽타주를 플레이하게 만든다. Look At 함수를 먼저 보면, 로스트아크에서 좌클릭을 누르는 위치마다 캐릭터가 그 방향을 바라보고 공격 모션을 취한다. 그걸 구현하기 위해 만든 함수임
캐릭터 블루프린트 > Look At 함수
현재 액터의 위치와 클릭한 곳의 위치를 이용해 Find Look at Rotation 노드를 사용한다
그럼 벡터가 나오는데 거기서 Yaw 회전만 하면 되니까 Z값만 따로 빼서 SetActorRotation을 사용해 액터의 회전 값을 바꾼다.
캐릭터가 움직이다 공격하면 멈춰야 하기 때문에 멈추는 노드를 했고 Play Anim Montage로 몽타주를 재생시켰다.
근데 이 것만으로 몽타주를 실행이 안돼서 애니메이션 블루프린트로 넘어가 Attack 상태를 좀 건들여야 한다.
애니메이션 블루프린트 > Attack 스테이트
DefaultSlot 슬롯의 출력 값을 설정해줘야 몽타주가 정상적으로 실행된다. 이것도 찾아보면 자세히 설명해주는 곳이 있다
이 상태로 하면 잘되긴하는데 처음 공격 섹션인 Attack1때만 마우스 방향을 바라보고 2,3일땐 바꿔도 보지 않는다. 그래서 아까 말한 노티파이를 이용해 그 노티파이가 실행돼도 LookAt 함수가 실행되게 만들어준다.
애니메이션 블루프린트 > 이벤트 그래프
아, 그리고 아까 캐릭터 블루프린트에서 Attack 이벤트에서 좌클릭 뗄 때 IsAttacking False로 바꾸고 몽타주를 멈추게 했는데 왜그렇게 했냐면 그냥 실행해보니까 어택을 안하는 상태에서도 몽타주가 계속 실행되는 걸로 돼서 LookAt 함수가 계속 돌아가 마우스 위치를 바꾸기만 해도 그 방향으로 바라본다. 몽타주를 안 멈추면 이렇게 된다.
이렇게 되니까 그냥 몽타주를 직접 멈추게 하자
이렇게 캐릭터 공격을 구현했다.
아쉬운 점은 캐릭터가 연속으로 공격하면 세번째 애니메이션 이후 그 자리에 있게 하고 싶은데 원 위치로 돌아간다. 그렇다고 루트 모션을 잠그면 공격 모션이 이상하게 나온다.. 나중에 언리얼 잘하는 사람한테 상담받고 싶다 ㅠㅠ
캐릭터 구르기
로스트아크에서 스페이스바를 누르면 캐릭터가 순간적으로 이동하거나 구르는 모션이 실행된다. 비슷하게 구현해보자
프로젝트 세팅 > 입력에서 스페이스바를 누르면 Roll 이벤트가 실행되게 매핑하자
구르는 애니메이션도 몽타주로 구현했는데 시퀀스로도 될지는 잘 모르겠다
구르긴데 왜 저런 모션으로 보일까? 루트 모션을 잠궜기 때문, 그래서 굴러도 그 자리를 그대로 유지하게 한다
여기도 애니메이션 끝에 노티파이를 넣어논걸 참고
캐릭터 블루프린트 > Roll 이벤트
스페이스바를 누르면 실행된다. 먼저 구르기 상태인데 또 구르면 이상하니까 조건문을 줬고 Is Rolling을 true로 설정
구르기도 똑같이 LookAt 함수를 해서 그 방향으로 구르게 만들어줬고 Attack 처럼 Play Montage를 사용. 그리고 구른 다음에 이동 멈추게 Stop Active Movement로 해줬다. 근데 게임 플레이할때 멀리 우클릭을 해 이동 할 때 구르면 원래 입력받아 이동하는걸 멈춰야 하는데 구르고 그 위치로 다시 Walk한다. 이걸 막기 위해 플레이어 컨트롤러 블루프린트에 있는
이 분기문으로 구르기 중이고, 공격 중이면 이동을 못하게 막았다
구르기가 끝나서 IsRolling을 False로 만들기 위해 아까 만든 노티파이로
애니메이션 블루프린트 > 이벤트 그래프
노티파이가 실행되면 캐릭터 블루프린트에 있는 On Anim End Rolling이라는 이벤트를 실행하게 함, 이게 캐릭터 블루프린트에 있는
이 이벤트가 실행되어 부울 변수를 바꿔줌
실행 영상
캐릭터 죽음
원래는 적이 캐릭터를 많이 공격하면 죽어야 되는데 테스트를 위해 K를 누르면 캐릭터가 죽고 리스폰하게 만들자
K 입력 이벤트를 매핑해주고 캐릭터 블루프린트에서 작업
K누르면 IsDeath를 true로 설정해주고(지금은 딱히 필요없음), 죽는 애니메이션을 실행하게 한 후 못 움직이게 Movement를 Disable 시켰다. 그리고 마우스 입력 같은 입력을 못받게 Disable Input을 해놨고 죽고 5초 뒤에 리스폰되게 Destory Actor가 실행되어 액터의 OnDestory 이벤트가 실행될 것임.
여기서 게임 모드 블루프린트로 갈 건데
게임 모드 블루프린트
BeginPlay 이벤트와 Respawn 이벤트를 캐릭터의 OnDestory에 바인딩 시켜 캐릭터가 Destory가 되면 리스폰하는 OnDestroyed)_Event_0이 실행된다. -> 이는 델리게이트를 쓰는 것 같은데 좀 이해가 필요한 영역
그래서 캐릭터의 리스폰 지점인 Spawn Transform을 이용해 그곳에 캐릭터를 리스폰하고 플레이어 컨트롤러가 원래 조종하던 폰이 디스트로이 되어 사라져 조종할게 없었는데 새로 리스폰된 캐릭터를 조종하게 하는 Possess를 사용한다. 그리고 Respawn을 호출해 또 죽어도 다시 리스폰할 수 있게 했다.
근데 여기서 Spawn Transform은 어디서 설정했을까? 바로 캐릭터 블루프린트의 BeginPlay에서 했다
간단하니까 설명은 생략
이렇게 캐릭터에 관한걸 구현해봤다
좀 구현하는데 오류가 많이 생겼었는데 여기까지 해낸게 그래도 자랑스럽다,,, 아직 더 캐릭터에 대해 만지고 싶은건 많은데 요새 시간이 잘 안나 못하고 있다 ㅠㅠ 다음엔 캐릭터 스킬이나 적을 공격하는걸 구현해보려고 한다