Chapter 8-4. 모닥불 : 불에 고기 익히기(퀵슬롯 자동 장착)
카테고리: Unity Lesson 3
태그: Unity Game Engine
인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
불에 고기 익히기
🚘 익힌 고기, 탄 고기 아이템 만들기
Prefab
기존에 있던 생고기 프리팹의 Material 만 바꿔서 익힌 고기, 탄 고기 프리팹을 만들어주었다.
- Meat_Cooked
- Meat_Burnt
Item
익힌 고기, 탄 고기 Item
도 만들고 위에서 만든 프리팹도 할당해주었다. 프리팹들의 📜ItemPickUp.cs 컴포넌트에도 마찬가지로 이 아이템들을 각각 할당.
🚘 고기 굽기
📜FoodOnFire.cs
이 스크립트를 구울 수 있는 생고기, 익힌고기 프리팹에 붙여준다. (탄고기는 구울 수 없으므로 X)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FoodOnFire : MonoBehaviour
/* 익힌 고기와 탄 고기가 이 스크립트를 공유할 것이다. */
{
[SerializeField]
private float time; // 익히거나 타는데 걸리는 시간
private float currentTime; // 업데이트해 나갈 시간. time 에 도달시킬 것.
private bool done; // 끝났으면 더 이상 불에 있어도 계산 무시할 수 있게끔
[SerializeField]
private GameObject go_CookedItem_Prefab; // 익혀진 혹은 탄 고기 아이템 교체
private void OnTriggerStay(Collider other)
{
if(other.transform.tag == "Fire" && !done)
{
currentTime += Time.deltaTime;
if (currentTime >= time)
{
done = true;
Instantiate(go_CookedItem_Prefab, transform.position, Quaternion.Euler(transform.eulerAngles));
Destroy(gameObject); // 날고기인 자기 자신은 파괴
}
}
}
}
- 익힌 고기, 생 고기 두 프리팹에 위 스크립트를 붙여준다.
- 두 고기 모두 5 초 뒤에 [생 고기👉익힌 고기], [익힌 고기 👉 탄고기]가 되도록 할 것이다.
- 5초가 지나면 자기 자신은 파괴하고
go_CookedItem_Prefab
에 할당된 다음 단계의 고기 프리팹을 생성
- 5초가 지나면 자기 자신은 파괴하고
- 익힌 고기 불에서 안빼면 알아서 또 다시 5초 후에 탄 고기가 된다. 즉, 생고기 넣고 10초동안 안빼면 탄 고기가 됨.
- 생고기의 📜FoodOnFire 👉 5 초 후에 익힌 고기 오브젝트 생성 (익힌 고기의 📜FoodOnFire 새롭게 호출)
- 익힌 고기의 📜FoodOnFire 👉 5 초 후에 탄 고기 오브젝트 생성
- 두 고기 모두 5 초 뒤에 [생 고기👉익힌 고기], [익힌 고기 👉 탄고기]가 되도록 할 것이다.
- 생 고기의
go_CookedItem_Prefab
에는 익힌 고기 프리팹을, 익힌 고기의go_CookedItem_Prefab
에는 탄 고기 프리팹을 할당.
불 설정
빨간 불 파티클 시스템인 Flame
오브젝트의 태그와 레이어를 “Fire”로 설정해준다. 레이어까지 설정해주는 이유는 밑에 📜ActionController 에서 플레이어(메인카메라)가 불을 바라보면(레이캐스팅 필요) 불에 고기를 익힐 수 있다는 메세지를 띄울 것이라서! 📢주의할 점 👉 “Fire” 레이어를 붙여줬으면 Main Camera
의 Culling Mask 에도 “Fire” 레이어를 추가로 설정해주어야 렌더링 되게 된다.
불에 고기를 던져 구울 때 고기가 불에 파묻히면 보이지 않으므로 불의 윗부분에 고기를 구울 수 있도록 Sphere Collider
를 하나 더 깔아주었다. Is Trigger
가 체크 해제 되어야 충돌 처리되어 Sphere Collider
에 관통되지 않고 위에 있을 수 있게 된다.
🚘 고기 굽는 메세지 및 고기 아이템 처리
플레이어가 고기를 직접 불에 떨구려면 불에 들어가야 해서 데미지를 입으므로 불에 가까이 가서 불을 바라보면 자동으로 메세지를 띄우고 특정 키를 누르면 자동으로 고기가 불에 들어가 구워지게끔 할 것이다.
- 📜ActionController.cs
- 레이어(1인칭 메인카메라)가 불을 가까이서 불을 바라 보면 불에 고기를 구울 수 있다는 메세지 출력
- 불 굽기 입력 처리
- 실제 불을 굽는 처리
- 퀵슬롯에 있던 고기 아이템은 제거 (구워졌으니)
📜Fire.cs
public bool GetIsFire()
{
return isFire;
}
- 불이 활성화 되있는 상태에서만 고기를 구울 수 있으므로 불의 활성화 상태를 가져오는 접근 함수를 만들었다.
isFire
가 private 이라서.
📜QuickSlotController.cs
public Slot GetSelectedSlot()
{
return quickSlots[selectedSlot];
}
public void DecreaseSelectedItem()
- 마찬가지로 현재 활성화된 슬롯이 어떤건지도 알 수 있도록 이를 리턴하는 접근 함수를 만들었다.
- 기존 EatItem() 함수를 DecreaseSelectedItem()로 이름 변경.
📜Inventory.cs
[SerializeField]
private QuickSlotController theQuickSlotController;
private int slotNumber;
public void AcquireItem(Item _item, int _count = 1)
{
PutSlot(quickSlots, _item, _count);
if (!isNotPut) /// 🧡🧡🧡 이거 추가
theQuickSlotController.IsActivatedQuickSlot(slotNumber);
if (isNotPut)
PutSlot(slots, _item, _count);
if (isNotPut)
{
isFull = true;
StartCoroutine(theActionController.WhenInventoryIsFull());
}
}
private void PutSlot(Slot[] _slots, Item _item, int _count)
{
if (Item.ItemType.Equipment != _item.itemType)
{
for (int i = 0; i < _slots.Length; i++)
{
if (_slots[i].item != null)
{
if (_slots[i].item.itemName == _item.itemName)
{
slotNumber = i; /// 🧡🧡🧡 이거 추가
_slots[i].SetSlotCount(_count);
isNotPut = false;
return;
}
}
}
}
for (int i = 0; i < _slots.Length; i++)
{
if (_slots[i].item == null)
{
_slots[i].AddItem(_item, _count);
isNotPut = false;
return;
}
}
isNotPut = true;
}
- 변수 추가
slotNumber
👉 방금 아이템 넣는데 성공한, 아이템 넣은 그 슬롯의 넘버 저장theQuickSlotController
👉 에디터에서 📜QuickSlotController 할당
- 퀵슬롯에 아이템을 넣었다면 그 슬롯을 활성화 퀵슬롯으로 한다.
PutSlot(quickSlots, _item, _count)
을 통해 퀵슬롯에 성공적으로 아이템을 넣었다면isNotPut
는 False 상태가 된다. 또한PutSlot
함수를 실행하면서 아이템 넣은 퀵슬롯 넘버인slotNumber
에 저장하기 때문에slotNumber
를 📜QuickSlotController의IsActivatedQuickSlot
함수에 넘겨 활성화 퀵슬롯으로 지정하고 이에 대해 실행한다.(손에 들고 있게 한다던지 Excute()를 실행함)PutSlot(quickSlots, _item, _count); if (!isNotPut) /// 🧡🧡🧡 이거 추가 theQuickSlotController.IsActivatedQuickSlot(slotNumber);
📜ActionController.cs
private bool firedLookActivated = false; // 불에 접근해서 불을 바라볼 시 True
[SerializeField]
private QuickSlotController theQuickSlotController; // 📜QuickSlotController.cs
private void TryAction()
{
if(Input.GetKeyDown(KeyCode.E))
{
CheckAction();
CanPickUp();
CanMeat();
CanDropFire();
}
}
private void CheckAction()
{
if (Physics.Raycast(transform.position, transform.forward, out hitInfo, range, layerMask))
{
if (hitInfo.transform.tag == "Item")
ItemInfoAppear();
else if (hitInfo.transform.tag == "Weak_Animal")
MeatInfoAppear();
else if (hitInfo.transform.tag == "Fire")
FireInfoAppear();
else
InfoDisappear();
}
else
InfoDisappear();
}
private void Reset()
{
pickupActivated = false;
dissolveActivated = false;
firedLookActivated = false;
}
private void ItemInfoAppear()
{
Reset();
pickupActivated = true;
actionText.gameObject.SetActive(true);
actionText.text = hitInfo.transform.GetComponent<ItemPickUp>().item.itemName + " 획득 " + "<color=yellow>" + "(E)" + "</color>";
}
private void MeatInfoAppear()
{
// 📜Animal.cs의 animalName, isDead 을 public 으로 바꿨다.
if (hitInfo.transform.GetComponent<Animal>().isDead) // 죽은 돼지를 바라봤을 경우에만 (카메라에서 쏜 Raycast가 죽은 돼지와 충돌)
{
Reset();
dissolveActivated = true;
actionText.gameObject.SetActive(true);
actionText.text = hitInfo.transform.GetComponent<Animal>().animalName + " 해체하기 " + "<color=yellow>" + "(E)" + "</color>";
}
}
private void FireInfoAppear()
{
Reset();
firedLookActivated = true;
if (hitInfo.transform.GetComponent<Fire>().GetIsFire())
{
actionText.gameObject.SetActive(true);
actionText.text = "선택된 아이템 불에 넣기" + "<color=yellow>" + "(E)" + "</color>";
}
}
private void InfoDisappear()
{
pickupActivated = false;
dissolveActivated = false;
firedLookActivated = false;
actionText.gameObject.SetActive(false);
}
private void CanDropFire()
{
if (firedLookActivated)
{
if (hitInfo.transform.tag == "Fire" && hitInfo.transform.GetComponent<Fire>().GetIsFire())
{
// 손에 들고 있는 아이템을 불에 넣음 <- 선택된 퀵슬롯의 아이템을 넣음 (Null 빈슬롯일 수도 있음. 판별이 필요)
Slot _selectedSlot = theQuickSlotController.GetSelectedSlot();
if (_selectedSlot.item != null)
DropAnItem(_selectedSlot);
}
}
}
private void DropAnItem(Slot _selectedSlot)
{
switch(_selectedSlot.item.itemType)
{
case Item.ItemType.Used:
if (_selectedSlot.item.itemName.Contains("고기"))
{
Instantiate(_selectedSlot.item.itemPrefab, hitInfo.transform.position + Vector3.up, Quaternion.identity);
theQuickSlotController.DecreaseSelectedItem();
}
break;
case Item.ItemType.Ingredient:
break;
}
}
- 1️⃣ 고기 바라볼 시 메세지 띄우기
- 매 프레임마다 실행되는 CheckAction() 에서 이 스크립트가 붙어있는 메인카메라(플레이어의 시점)에서 레이캐스팅을 할 때 충돌되는 레이어가 “Fire”라면 👉 즉 플레이어가
rnage
사정거리 내에 바라보고 있는게 불이라면- FireInfoAppear() 👉 고기 구울 수 있다는 액션 텍스트 띄우기
- Reset() : 해당 작업이 이제 가능하다는 flag 변수들을 모두
false
로 초기화 한다.- Reset() 은 InfoDisappear() 에서 액션 텍스트를 비활성화 하는 작업만 빠져있는 형태다. flag 변수들만 초기화 함.
- 이 초기화 작업이 필요한 이유는, 불에 굽고 있는 고기 아이템을 바라보면
pickupActivated
인 상태가 될 수도 있고 동시에firedLookActivated
인 상태가 될 수도 있기 때문이다. 이렇게 되면CanPickUp()
,CanDropFire()
두 함수 모두 다 실행할 수 있는 상태가 되므로 이 상태에서E
를 누르면 두 함수가 실행되어 충돌이 일어난다. 아이템을 불에 버려야하는데 아이템을 주우라니 충돌이 일어날 수 밖에 없다. 그래서 런타임 에러가 발생한다. 따라서 Reset() 함수를 만들어 초기화 하는 작업을 먼저 함. 두 flag 변수가 동시에true
가 되는 일 없고 하나만 작업될 수 있도록. - 다른 ItemInfoAppear(), MeatInfoAppear() 함수에 대해서도 똑같이 작업전 Reset()을 실행하도록 하였다.
firedLookActivated
를 True로 하여E
키 입력이 들어오면CanDropFire()
함수가 실행될 수 있는 상태로 만들어주준다.- 불이 활활 타고 있는 상태라면 액션텍스트를 활성화한다. “선택된 아이템 불에 넣기”
- Reset() : 해당 작업이 이제 가능하다는 flag 변수들을 모두
- FireInfoAppear() 👉 고기 구울 수 있다는 액션 텍스트 띄우기
- 매 프레임마다 실행되는 CheckAction() 에서 이 스크립트가 붙어있는 메인카메라(플레이어의 시점)에서 레이캐스팅을 할 때 충돌되는 레이어가 “Fire”라면 👉 즉 플레이어가
- 2️⃣ 고기 굽는 처리
- TryAction()
E
키 입력을 받으면 CanDropFire() 함수 실행
- CanDropFire()
- 플레이어가 고기를 가까이서 바라보아서
firedLookActivated
를 True로 갱신된 상태라면 다음과 같이 고기를 불에 드롭하는 처리를 해준다.- 손에 들고 있는(활성화 퀵슬롯) 아이템을 불에 넣는다. DropAnItem(_selectedSlot) 다만 빈슬롯이 아닐 때만!!
- DropAnItem(Slot _selectedSlot)
- 활성화 퀵슬롯 아이템이(즉 손에 들고 있는 아이템이) 고기 종류의 소모(Used) 아이템이라면 (아이템 이름에 “고기”가 들어감) 해당 아이템을 불 위에 생성한다.
- 그리고 DecreaseSelectedItem 함수를 호출하여 해당 아이템은 퀵슬롯에서 감소 혹은 제거한다.
- DropAnItem(Slot _selectedSlot)
- 손에 들고 있는(활성화 퀵슬롯) 아이템을 불에 넣는다. DropAnItem(_selectedSlot) 다만 빈슬롯이 아닐 때만!!
- 플레이어가 고기를 가까이서 바라보아서
- TryAction()
layerMask
에 “Fire” 레이어를 추가한다.- 📜QuickSlotController 할당
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기