일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- C/C++
- 골드메탈
- 7월
- 게임 엔진 공부
- 2024년
- 유니티 심화과정
- 수학
- 2025년
- 2022년
- 코딩 테스트
- 개인 프로젝트
- 기초
- 다이나믹 프로그래밍
- 프로그래머스
- 코딩 기초 트레이닝
- 5월
- 2023년
- 4월
- c++
- 자료 구조
- 2월
- 입문
- 1월
- 단계별로 풀어보기
- 백준
- 유니티
- 개인 프로젝트 - 런앤건
- todolist
- 3월
- 10월
- Today
- Total
기록 보관소
[Unity/유니티] 기초-탑다운 2D RPG: 대화 애니메이션 느낌있게 만들기[B25] 본문
개요
유니티 입문과 독학을 위해서 아래 링크의 골드메탈님의 영상들을 보며 진행 상황 사진 또는 캡처를 올리고 배웠던 점을 요약해서 적는다.
현재는 영상들을 보고 따라하고 배우는 것에 집중할 것이며, 영상을 모두 보고 따라한 후에는 개인 프로젝트를 설계하고 직접 만드는 것이 목표다.
https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
유니티 강좌 기초 채널 Basic
유니티 개발을 처음 시작하시는 입문자 분들을 위한 기초 채널. [ 프로젝트 ] B00 ~ B12 (BE1) : 유니티 필수 기초 B13 ~ B19 (BE2) : 2D 플랫포머 B20 ~ B26 (BE3) : 2D 탑다운 대화형 RPG B27 ~ B37 (BE4) : 2D 종스크롤
www.youtube.com
탑다운 2D RPG: 대화 애니메이션 느낌있게 만들기[B25]
1. 대화창 이펙트
- isShow 매개변수는 애니메이션 이름에서 예상되는 것처럼 설정했다.
- Empty->TalkShow : isShow true
- TalkShow->TalkHide : isShow false
- TalkHide->TalkShow : isShow true
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour {
public TalkManager talkManager;
public QuestManager questManager;
public Animator talkPanel; //Object에서 Animator로 변경.
public Image portraitImg;
public Text talkText;
public GameObject scanObject;
public bool isAction; //대화창 활성화 여부 체크
public int talkIndex;
void Start() {
Debug.Log(questManager.CheckQuest());
}
public void Action (GameObject scanObj) {
scanObject = scanObj;
ObjData objData = scanObject.GetComponent<ObjData>();
Talk(objData.id, objData.isNPC);
//대화창 활성화, 비활성화
talkPanel.SetBool("isShow", isAction);
}
void Talk(int id, bool isNPC) {
//대화 데이터 불러오기
int questTalkIndex = questManager.GetQuestTalkIndex(id);
string talkData = talkManager.GetTalk(id + questTalkIndex, talkIndex);
//대화가 끝나면 멈추기
if (talkData == null) {
isAction = false;
talkIndex = 0;
Debug.Log(questManager.CheckQuest(id));
return;
}
//대화 전 체크하기
if (isNPC) { //NPC라면
talkText.text = talkData.Split(':')[0];
portraitImg.sprite = talkManager.GetPortrait(id, int.Parse(talkData.Split(':')[1]));
portraitImg.color = new Color(1, 1, 1, 1); //초상화 보이기
}
else { //NPC가 아니라면
talkText.text = talkData;
portraitImg.color = new Color(1, 1, 1, 0); //초상화 투명화
}
//대화창 띄우기 및 대화 인덱스 증가
isAction = true;
talkIndex++;
}
}
2. 초상화 이펙트
- PortraitEffect->Empty는 이전과 다르게 Has Exit Time을 체크하고, 매개변수 또한 넣지 않는다. 굳이 매개변수를 넣지 않더라도 PortraitEffect 애니메이션이 발동한 후, 자동으로 Empty로 빠져나오게 된다.
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour {
public TalkManager talkManager;
public QuestManager questManager;
public Animator talkPanel;
public Image portraitImg;
public Animator portraitAnim;
public Sprite prevPortrait;
public Text talkText;
public GameObject scanObject;
public bool isAction; //대화창 활성화 여부 체크
public int talkIndex;
void Start() {
Debug.Log(questManager.CheckQuest());
}
public void Action (GameObject scanObj) {
scanObject = scanObj;
ObjData objData = scanObject.GetComponent<ObjData>();
Talk(objData.id, objData.isNPC);
//대화창 활성화, 비활성화
talkPanel.SetBool("isShow", isAction);
}
void Talk(int id, bool isNPC) {
//대화 데이터 불러오기
int questTalkIndex = questManager.GetQuestTalkIndex(id);
string talkData = talkManager.GetTalk(id + questTalkIndex, talkIndex);
//대화가 끝나면 멈추기
if (talkData == null) {
isAction = false;
talkIndex = 0;
Debug.Log(questManager.CheckQuest(id));
return;
}
//대화 전 체크하기
if (isNPC) { //NPC라면
talkText.text = talkData.Split(':')[0];
//초상화 보이기
portraitImg.sprite = talkManager.GetPortrait(id, int.Parse(talkData.Split(':')[1]));
portraitImg.color = new Color(1, 1, 1, 1);
//초상화 애니메이션
if (prevPortrait != portraitImg.sprite) {
portraitAnim.SetTrigger("doEffect");
prevPortrait = portraitImg.sprite;
}
}
else { //NPC가 아니라면
talkText.text = talkData;
portraitImg.color = new Color(1, 1, 1, 0); //초상화 투명화
}
//대화창 띄우기 및 대화 인덱스 증가
isAction = true;
talkIndex++;
}
}
3. 타이핑 이펙트
//TypeEffect 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TypeEffect : MonoBehaviour {
public GameObject EndCursor; //대화창 끝 화살표
Text msgText; //대화 텍스트
public int CharPerSeconds; //글자 재생 속도 변수
string targetMsg; //표시할 대화 문자열 변수
int index; //문자열 인덱스
float interval; //CPS 보조 변수
void Awake() {
msgText = GetComponent<Text>();
}
public void SetMsg(string msg) {
targetMsg = msg;
EffectStart();
}
void EffectStart () {
msgText.text = ""; //시작시 공백 처리
index = 0;
EndCursor.SetActive(false);
interval = 1.0f / CharPerSeconds; // 1 / CharPerSeconds : 1글자가 나오는 딜레이
Invoke("Effecting", interval);
}
void Effecting() {
if (msgText.text == targetMsg) {
EffectEnd();
return;
}
msgText.text += targetMsg[index]; //string도 배열처럼 인덱스로 char 값에 접근 가능
index++;
Invoke("Effecting", interval);
}
void EffectEnd() {
EndCursor.SetActive(true);
}
}
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour {
public TalkManager talkManager;
public QuestManager questManager;
public Animator talkPanel;
public Image portraitImg;
public Animator portraitAnim;
public Sprite prevPortrait;
public TypeEffect talk;
public GameObject scanObject;
public bool isAction; //대화창 활성화 여부 체크
public int talkIndex;
void Start() {
Debug.Log(questManager.CheckQuest());
}
public void Action (GameObject scanObj) {
scanObject = scanObj;
ObjData objData = scanObject.GetComponent<ObjData>();
Talk(objData.id, objData.isNPC);
//대화창 활성화, 비활성화
talkPanel.SetBool("isShow", isAction);
}
void Talk(int id, bool isNPC) {
//대화 데이터 불러오기
int questTalkIndex = questManager.GetQuestTalkIndex(id);
string talkData = talkManager.GetTalk(id + questTalkIndex, talkIndex);
//대화가 끝나면 멈추기
if (talkData == null) {
isAction = false;
talkIndex = 0;
Debug.Log(questManager.CheckQuest(id));
return;
}
//대화 전 체크하기
if (isNPC) { //NPC라면
talk.SetMsg(talkData.Split(':')[0]);
//초상화 보이기
portraitImg.sprite = talkManager.GetPortrait(id, int.Parse(talkData.Split(':')[1]));
portraitImg.color = new Color(1, 1, 1, 1);
//초상화 애니메이션
if (prevPortrait != portraitImg.sprite) {
portraitAnim.SetTrigger("doEffect");
prevPortrait = portraitImg.sprite;
}
}
else { //NPC가 아니라면
talk.SetMsg(talkData);
portraitImg.color = new Color(1, 1, 1, 0); //초상화 투명화
}
//대화창 띄우기 및 대화 인덱스 증가
isAction = true;
talkIndex++;
}
}
- 참고로 대화창의 글자가 한글자씩 나오므로 모든 글자가 출력된 뒤, EndCursor(대화창 끝에 있는 화살표)를 보이도록 하기위해서 End Cursor 스프라이트의 체크를 빼서 비활성화 상태로 둬야한다. 이제 사운드를 추가할 차례다.
using UnityEngine.UI;
public class TypeEffect : MonoBehaviour {
public GameObject EndCursor; //대화창 끝 화살표
Text msgText; //대화 텍스트
AudioSource audioSource; //사운드
public int CharPerSeconds; //글자 재생 속도 변수
string targetMsg; //표시할 대화 문자열 변수
int index; //문자열 인덱스
float interval; //CPS 보조 변수
void Awake() {
msgText = GetComponent<Text>();
audioSource = GetComponent<AudioSource>();
}
public void SetMsg(string msg) {
targetMsg = msg;
EffectStart();
}
void EffectStart () {
msgText.text = "";
index = 0;
EndCursor.SetActive(false);
//이펙트 시작
interval = 1.0f / CharPerSeconds;
Invoke("Effecting", interval);
}
void Effecting() {
//이펙트 끝내기
if (msgText.text == targetMsg) {
EffectEnd();
return;
}
msgText.text += targetMsg[index];
//사운드 출력
if (targetMsg[index] != ' ' || targetMsg[index] != '.')
audioSource.Play();
index++;
//재귀
Invoke("Effecting", interval);
}
void EffectEnd() {
EndCursor.SetActive(true);
}
}
- 대사 중 공백과 마침표가 출력될때는 사운드가 출력되지 않도록 설정해두었다.
- 다만 대사가 출력되는 중 스페이스바를 누르면 바로 다음 대사로 넘어가는 문제가 있다. 다음 대사로 넘어가는 것 대신, 남은 대사가 완전히 출력되게 하도록 수정할 것이다.
//TypeEffect 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TypeEffect : MonoBehaviour {
public GameObject EndCursor; //대화창 끝 화살표
Text msgText; //대화 텍스트
AudioSource audioSource; //사운드
public int CharPerSeconds; //글자 재생 속도 변수
public bool isAnim; //애니메이션 실행 판단
string targetMsg; //표시할 대화 문자열 변수
int index; //문자열 인덱스
float interval; //CPS 보조 변수
void Awake() {
msgText = GetComponent<Text>();
audioSource = GetComponent<AudioSource>();
}
public void SetMsg(string msg) {
if (isAnim) { //애니메이션 실행 중일때. 즉, 대사 중에 스페이스바를 눌렀을 때
msgText.text = targetMsg; //대사 문자열 전부 출력
CancelInvoke();
EffectEnd();
}
else {
targetMsg = msg;
EffectStart();
}
}
void EffectStart () {
msgText.text = "";
index = 0;
EndCursor.SetActive(false);
//이펙트 시작
isAnim = true;
interval = 1.0f / CharPerSeconds;
Invoke("Effecting", interval);
}
void Effecting() {
//이펙트 끝내기
if (msgText.text == targetMsg) {
EffectEnd();
return;
}
msgText.text += targetMsg[index];
//사운드 출력
if (targetMsg[index] != ' ' || targetMsg[index] != '.')
audioSource.Play();
index++;
//재귀
Invoke("Effecting", interval);
}
void EffectEnd() {
isAnim = false;
EndCursor.SetActive(true);
}
}
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour {
public TalkManager talkManager;
public QuestManager questManager;
public Animator talkPanel;
public Image portraitImg;
public Animator portraitAnim;
public Sprite prevPortrait;
public TypeEffect talk;
public GameObject scanObject;
public bool isAction; //대화창 활성화 여부 체크
public int talkIndex;
void Start() {
Debug.Log(questManager.CheckQuest());
}
public void Action (GameObject scanObj) {
scanObject = scanObj;
ObjData objData = scanObject.GetComponent<ObjData>();
Talk(objData.id, objData.isNPC);
//대화창 활성화, 비활성화
talkPanel.SetBool("isShow", isAction);
}
void Talk(int id, bool isNPC) {
int questTalkIndex = 0;
string talkData = "";
//대화 데이터 불러오기
if (talk.isAnim) { //대사 출력 중일때
talk.SetMsg("");
return;
}
else {
questTalkIndex = questManager.GetQuestTalkIndex(id);
talkData = talkManager.GetTalk(id + questTalkIndex, talkIndex);
}
//대화가 끝나면 멈추기
if (talkData == null) {
isAction = false;
talkIndex = 0;
Debug.Log(questManager.CheckQuest(id));
return;
}
//대화 전 체크하기
if (isNPC) { //NPC라면
talk.SetMsg(talkData.Split(':')[0]);
//초상화 보이기
portraitImg.sprite = talkManager.GetPortrait(id, int.Parse(talkData.Split(':')[1]));
portraitImg.color = new Color(1, 1, 1, 1);
//초상화 애니메이션
if (prevPortrait != portraitImg.sprite) {
portraitAnim.SetTrigger("doEffect");
prevPortrait = portraitImg.sprite;
}
}
else { //NPC가 아니라면
talk.SetMsg(talkData);
portraitImg.color = new Color(1, 1, 1, 0); //초상화 투명화
}
//대화창 띄우기 및 대화 인덱스 증가
isAction = true;
talkIndex++;
}
}
'유니티 프로젝트 > 탑다운 2D RPG' 카테고리의 다른 글
[Unity/유니티] 기초-탑다운 2D RPG: 모바일 UI & 안드로이드 빌드[BE3] (0) | 2022.02.26 |
---|---|
[Unity/유니티] 기초-탑다운 2D RPG: 서브메뉴와 저장기능 만들기[B26] (0) | 2022.02.22 |
[Unity/유니티] 기초-탑다운 2D RPG: 퀘스트 시스템 구현하기[B24] (0) | 2022.02.20 |
[Unity/유니티] 기초-탑다운 2D RPG: 대화 시스템 구현하기[B23] (0) | 2022.02.19 |
[Unity/유니티] 기초-탑다운 2D RPG: 대화창 UI 구축하기[B22] (0) | 2022.02.18 |