미로스 - 2. 캐릭터와 npc(몬스터)또는 무생물형 오브젝트(상자 등)에 대한 상호작용 포함
- 100 powerun
- 2024년 11월 27일
- 2분 분량
최종 수정일: 2월 20일
NPC 오브젝트 접촉

플레이어와 NPC와의 상호작용은 근접 후 상호작용을 하는 것이 아닌 접촉 시 바로 활성화됩니다.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player" && !haveQuest)
{
textBox.SetActive(true);
q = qm.GetQuest(npcNum);
textBox.GetComponentInChildren<TextMeshProUGUI>().text = q.questTitle + "\n\n" + q.texts;
textBox.transform.GetChild(0).GetComponent<Image>().sprite = this.GetComponent<SpriteRenderer>().sprite;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player" && !haveQuest)
{
Refuse();
}
}
Enter에서는 플레이어 접촉 시 또는 퀘스트를 수락하지 않았다면 즉시 퀘스트 창을 바로 화면에 띄워줍니다. 여기에서 거절 시 퀘스트 창을 닫고 다시 NPC와 접촉에서 벗어난 뒤 다시 접촉하면 퀘스트 창을 다시 띄울 수 있습니다.
이 게임에서 퀘스트는 수락 시 더 이상 대화창을 띄우지 않는 이유는, 플레이어가 같은 내용의 여러 퀘스트를 수락한 뒤 모든 보상을 한꺼번에 받는 걸 방지하기 위해서입니다.
public void Accept()
{
Debug.Log(q);
haveQuest = true;
q.QuestStart();
qm.questWindow.GetComponent<CurrentQuestWindow>().AddQuest(q);
if (q.type == Quest.Type.Arrive)
{
ArriveQuest aQuest = (ArriveQuest)q;
StartCoroutine(aQuest.ArriveCheck());
}
textBox.SetActive(false);
}
public void Refuse()
{
textBox.SetActive(false);
q = null;
}
퀘스트를 수락하게 되면 해당 NPC의 퀘스트를 가지고 있다고 알려줘 위의 NPC와의 상호작용을 더 이상 할 수 없게 만들고, 캔버스의 오른쪽 퀘스트 진행도를 띄웁니다. 만약 특정 장소로 이동해야 하는 퀘스트의 경우는 ArriveCheck 코루틴을 실행시켜 플레이어가 지정된 위치에 이동하는지 계속해서 판단하게 됩니다.
만약 거절했을 때는 textBox를 끄고 퀘스트를 받지 않은 상태로 끝내게 됩니다.
무생물형 오브젝트 접촉

private void OnTriggerEnter2D(Collider2D collision) {
if (collision.CompareTag("Player") == true) {
isInteractable = true;
_animator.SetBool(nameof(isInteractable), isInteractable);
return;
}
}
private void OnTriggerExit2D(Collider2D collision) {
if (collision.CompareTag("Player") == true) {
isInteractable = false;
_animator.SetBool(nameof(isInteractable), isInteractable);
return;
}
}
플레이어가 다가올 때 상호작용이 가능하게 만들고 상호작용이 가능한지 플레이어에게 확인시켜 주는 애니메이션을 실행하게 합니다. 애니메이션은 말풍선이 나오고 말풍선 내에서 "..."이라는 문구가 계속해서 출력되는 애니메이션입니다.
void Update()
{
if (isInteractable == false) {
return;
}
if (Input.GetKeyDown(KeyCode.F)) {
Debug.Log("상호작용");
InventoryManager.Instance.ObtainItem(item, amount);
CompleteInteract();
}
}
플레이어가 다가오고 f키를 눌렀다면 상자는 열리게 되고 ObtainItem함수에 설정된 보상을 얻게 됩니다.
public void CompleteInteract() {
GetComponent<SpriteRenderer>().sprite = openedImage;
// 상호작용 상태 저장
PlayerPrefs.SetInt(uid, 1);
// 애니메이션 정지 (말풍선)
isInteractable = false;
_animator.SetBool(nameof(isInteractable), isInteractable);
Destroy(transform.GetChild(0).gameObject);
// 추가 상호작용 방지를 위하여 collider 및 스크립트 비 활성화
_collider2D.enabled = false;
this.enabled = false;
}
위의 코드는 상자와 상호작용 시 실행되는 코드의 마지막 부분에 있던 함수로 만약 상자와 상호작용을 했다면 애니메이션을 정지시키고 콜라이더를 비활성화시켜 한번 열었던 상자를 연속으로 열지 못하게 막아줍니다.
맨 위에 상호작용 상태는 상자를 열었다면 상호작용 정보를 가지고 저장한 뒤 마을로 갔다 다시 던전으로 이동하여 무한으로 상자를 여는 것을 방지하는 장치입니다.
// Prefab 생성 파괴 방식
int hashkey = 1;
for(int i = 0; i < 3; i++) {
hashkey ^= transform.position[i].GetHashCode();
}
uid = hashkey.ToString();
if (PlayerPrefs.HasKey(uid) == false) {
GetComponent<SpriteRenderer>().sprite = closedImage;
isInteractable = false; // 상호작용 가능 여부 초기화
}
else {
GetComponent<SpriteRenderer>().sprite = openedImage;
CompleteInteract();
}
uid는 일반적인 변수가 아닌 hashkey를 가져와 저장하는 형태로 테스트를 종료해도 정보를 저장하고 있게 됩니다.
public static extern bool HasKey(string key);
위는 플레이어 프리팹 내에 해시코드를 파악하는 코드입니다. 만약 이 코드가 true를 반환한다면 상자는 상호작용이 가능한 상태가 되고, 만약 아닐 경우 sprite로만 존재하는 방식으로 모습을 바꾸어 상호작용이 가능한 상태와 불가능한 상태를 바꿔줍니다.
Comments