17.회복 아이템
using UnityEngine;
using UnityEngine.UI;
public class StatusController : MonoBehaviour
{
//체력
[SerializeField]
private int hp; //최대 HP
private int currentHp; //현재 HP
//스테미나
[SerializeField]
private int sp;
private int currentSp;
//스테미나 증가량
[SerializeField]
private int spIncreaseSpeed;
//스테미나 재회복 딜레이
[SerializeField]
private int spRechargeTime;
private int currentSpRechargeTime;
//스테미나 감소 여부
private bool spUsed;
//방어력
[SerializeField]
private int dp;
private int currentDp;
//배고픔
[SerializeField]
private int hungry;
private int currentHungry;
//배고픔이 줄어드는 속도
[SerializeField]
private int hungryDecreaseTime;
private int currentHungryDecreaseTime;
//목마름이 줄어드는 속도
[SerializeField]
private int thirstyDecreaseTiem;
private int currentThirstyDecreaseTime;
//목마름
[SerializeField]
private int thirsty;
private int currentThirsty;
//만족도
[SerializeField]
private int satisfy;
private int currentSatisfy;
//필요한 이미지
[SerializeField]
private Image[] images_Gauge;
//게이지 할당
private const int HP = 0, DP = 1, SP = 2, HUNGRY = 3, THIRSTY = 4, SATISFY = 5;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
currentHp = hp;
currentSp = sp;
currentDp = dp;
currentHungry = hungry;
currentThirsty = thirsty;
currentSatisfy = satisfy;
}
// Update is called once per frame
void Update()
{
Hungry();
Thirsty();
SPRechargeTime();
SPRecover();
GaugeUpdate();
}
private void SPRechargeTime()
{
if (spUsed)
{
if (currentSpRechargeTime < spRechargeTime)
currentSpRechargeTime++;
else
spUsed = false;
}
}
private void SPRecover()
{
if(!spUsed && currentSp < sp)
{
currentSp += spIncreaseSpeed;
}
}
private void Hungry()
{
if (currentHungry > 0)
{
if (currentHungryDecreaseTime <= hungryDecreaseTime)
currentHungryDecreaseTime++;
else
{
currentHungry--;
currentHungryDecreaseTime = 0;
}
}
else
Debug.Log("배고픔 수치가 0이 되었습니다");
}
private void Thirsty()
{
if (currentThirsty > 0)
{
if (currentThirstyDecreaseTime <= thirstyDecreaseTiem)
currentThirstyDecreaseTime++;
else
{
currentThirsty--;
currentThirstyDecreaseTime = 0;
}
}
else
Debug.Log("목마름 수치가 0이 되었습니다");
}
public void IncreaseHP(int _count)
{
if (currentHp + _count < hp)
currentHp += _count;
else
currentHp = hp;
}
public void DecreaseHP(int _count)
{
if (currentDp > 0)
{
DecreaseDP(_count);
return;
}
currentHp -= _count;
if (currentHp <= 0)
Debug.Log("캐릭터의 hp가 0이 되었습니다");
}
//Sp는 KD님의 원래 강좌에는 없음
public void IncreaseSP(int _count)
{
if (currentSp + _count < sp)
currentSp += _count;
else
currentSp = sp;
}
public void DecreaseSP(int _count)
{
if (currentSp > 0)
{
DecreaseSP(_count);
return;
}
currentSp -= _count;
if (currentSp <= 0)
Debug.Log("캐릭터의 Sp가 0이 되었습니다");
}
public void IncreaseDP(int _count)
{
if (currentDp + _count < hp)
currentDp += _count;
else
currentDp = dp;
}
public void DecreaseDP(int _count)
{
currentDp -= _count;
if (currentDp <= 0)
Debug.Log("방어력이 0이 되었습니다");
}
public void IncreaseHungry(int _count)
{
if (currentHungry + _count < hungry)
currentHungry += _count;
else
currentHungry = hungry;
}
public void DecreaseHungry(int _count)
{
if (currentHungry - _count < 0)
currentHungry = 0;
else
currentHungry -= _count;
}
public void IncreaseThirsty(int _count)
{
if (currentThirsty + _count < thirsty)
currentThirsty += _count;
else
currentThirsty = thirsty;
}
public void DecreaseThirsty(int _count)
{
if (currentThirsty - _count < 0)
currentThirsty = 0;
else
currentThirsty -= _count;
}
private void GaugeUpdate()
{
images_Gauge[HP].fillAmount = (float)currentHp / hp;
images_Gauge[SP].fillAmount = (float)currentSp / sp;
images_Gauge[DP].fillAmount = (float)currentDp / dp;
images_Gauge[HUNGRY].fillAmount = (float)currentHungry / hungry;
images_Gauge[THIRSTY].fillAmount = (float)currentThirsty / thirsty;
images_Gauge[SATISFY].fillAmount = (float)currentSatisfy / satisfy;
}
//스테미너 깍기
public void DecreaseStamina(int _count)
{
spUsed = true;
currentSpRechargeTime = 0;
if(currentSp - _count > 0)
currentSp -= _count;
else
currentSp = 0;
}
public int GetCurrentSP()
{
return currentSp;
}
}
using UnityEngine;
using UnityEngine.UIElements;
using static UnityEditor.Progress;
[System.Serializable]
public class ItemEffect
{
public string itemName;//아이템 이름(키값)
[Tooltip("HP, SP, DP, HUNGRY, THIRSTY, SATISFY만 가능합니다")]
public string[] part;//부위
public int[] num;//수치
}
public class ItemEffectDatabase : MonoBehaviour
{
[SerializeField]
private ItemEffect[] itemEffects;
//필요한 컴포넌트
[SerializeField]
private StatusController thePlayerStatus;
[SerializeField]
private WeaponManager theWeaponManager;
private const string HP = "HP", SP = "SP", DP = "DP", HUNGRY = "HUNGRY", THIRSTY = "THIRSTY", SATISFY = "SATISFY";
public void UseItem(Item _item)
{
if (_item.itemType == Item.ItemType.Equipment)
{
StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(_item.weaponType, _item.itemName));
}
else if (_item.itemType == Item.ItemType.Used)
{
for (int x = 0; x < itemEffects.Length; x++)
{
if (itemEffects[x].itemName == _item.itemName)
{
for (int y = 0; y < itemEffects[x].part.Length; y++)
{
switch (itemEffects[x].part[y])
{
case "HP":
thePlayerStatus.IncreaseHP(itemEffects[x].num[y]);
break;
case "SP":
thePlayerStatus.IncreaseSP(itemEffects[x].num[y]);
break;
case "DP":
thePlayerStatus.IncreaseDP(itemEffects[x].num[y]);
break;
case "HUNGRY":
thePlayerStatus.IncreaseHungry(itemEffects[x].num[y]);
break;
case "THIRSTY":
thePlayerStatus.IncreaseThirsty(itemEffects[x].num[y]);
break;
case "SATISFY":
break;
default:
Debug.Log("잘못된 Status 부위. HP, SP, DP, HUNGRY, THIRSTY, SATISFY만 가능합니다");
break;
}
Debug.Log(_item.itemName + "을 사용했습니다");
}
return;
}
}
Debug.Log("ItemEffectDatabase에 일치하는 itmeName가 없습니다");
}
}
}
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour,IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler
{
private Vector3 originPos;
public Item item;//획득한 아이템
public int itemCount;//획득한 아이템 개수
public Image itemImage;//아이템 이미지
//필요 컴포넌트
[SerializeField]
private Text text_Count;
[SerializeField]
private GameObject go_CountImage;
private ItemEffectDatabase theItemEffectDatabase;
private WeaponManager theWeaponManager;
void Start()
{
theItemEffectDatabase = FindAnyObjectByType<ItemEffectDatabase>();
}
private void SetColor(float _alpha)//이미지 투명도 조절
{
Color color = itemImage.color;
color.a = _alpha;
itemImage.color = color;
}
public void AddItem(Item _item, int _count = 1)//아이템 획득
{
item = _item;
itemCount = _count;
itemImage.sprite = item.itemImage;
if (item.itemType != Item.ItemType.Equipment)
{
go_CountImage.SetActive(true);
text_Count.text = itemCount.ToString();
}
else
{
text_Count.text = "0";
go_CountImage.SetActive(false);
}
SetColor(1);
}
public void SetSlotCount(int _count)//아이템 개수 조정
{
itemCount += _count;
text_Count.text = itemCount.ToString();
if (itemCount <= 0)
ClearSlot();
}
private void ClearSlot()//슬롯 초기화
{
item = null;
itemCount = 0;
itemImage.sprite = null;
SetColor(0);
text_Count.text = "0";
go_CountImage.SetActive(false);
}
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Right)
{
if (item != null)
{
theItemEffectDatabase.UseItem(item);
if (item.itemType == Item.ItemType.Used)
SetSlotCount(-1);
}
}
}
public void OnBeginDrag(PointerEventData eventData)
{
if (item != null)
{
DragSlot.instance.dragSlot = this;
DragSlot.instance.DragSetImage(itemImage);
DragSlot.instance.transform.position = eventData.position;
}
}
public void OnDrag(PointerEventData eventData)
{
if (item != null)
{
DragSlot.instance.transform.position = eventData.position;
}
}
public void OnEndDrag(PointerEventData eventData)
{
DragSlot.instance.SetColor(0);
DragSlot.instance.dragSlot = null;
}
public void OnDrop(PointerEventData eventData)
{
if (DragSlot.instance.dragSlot != null)
{
ChangeSlot();
}
}
private void ChangeSlot()
{
Item _tempItem = item;
int _tempItemCount = itemCount;
AddItem(DragSlot.instance.dragSlot.item, DragSlot.instance.dragSlot.itemCount);
if(_tempItem != null)
{
DragSlot.instance.dragSlot.AddItem(_tempItem, _tempItemCount);
}
else
{
DragSlot.instance.dragSlot.ClearSlot();
}
}
}
이번시간에는 포션을 만들어서 스테미나나 배고픔 등이 회복되는 것을 구현해 보겠다
일단 케이디님의 에셋에서 포션을 찾아서 씬에 넣는다
그리고 씬에 넣은 포션을 프리팹화해서 BoxCollider과 Rigidbody,ItemPicUp를 넣어주고 체크한 수치를 입력해준다
그 뒤 Item폴더에서 Item의 정보를 만든뒤 수치를 넣어주자
이제 ItemEffectDatabase라는 스크립트를 만들어서 작성해주자
먼저 커스텀 클레스이므로 위에 ItemEffect를 작성해준다
여기서 Tooltip를 볼 수 있는데 이건 유니티엔진에서 마우스를 갔다대면 텍스트로 내용이 표시되는 기능이다
[Tooltip("쓸 내용 ")] 이렇게 기억해두자
그리고 아이템은 하나지만 하나를 사용할때 다른 게이지 회복을 줄 수도 있으므로
string[], int[] 로 작성하여 배열화 했다
이제 ItemEffectDatabase를 보자
private ItemEffect[] itemEffects;로 배열화 했다
20번, 23번 줄은 필요한 컴포넌트를 불러온 것이다
그뒤 25번은 const를 사용하여 변수를 고정하고 string로 문자열화했다
자... 이제 매우 복잡한 부분을 설명하겠다 필자도 잘 이해했는지 모르겠다...
UseItem으로 함수를 작성해주고 인수로 Item _item을 넣어주었다
29번부터 32번 줄은 웨펀메니져를 불러와서 장비 아이템을 호출해서 장착하는 효과를 넣어주었다
이제 34번부터 else if문으로 used아이템 일때로 넘어가자
36번 줄은 for문으로 int x 는 0이고 X < itemEffects.Length 만큼 반복해주자
38번 줄에 if문으로 itemEffects[x].item == _tiem.itenName 로
반복된 x만큼 아이템 이름과 같을때
40번 줄에 for문으로 y는 0이고 y는 itemEffects[x].part.Length;만큼 반복한다
그리고 그걸 42번줄에 switch문으로 조건을 itemEffects[x],part[y]로 해준다
여기서 케이디님은 SP회복을 강좌를 작성하면서 StatusController스크립트에 넣어주지 않으셨다
필자가 작성했으니 맨 위의 스크립트를 참고해서 작성하자
rmenl 44번줄부터 58번 줄까지 IncreseHP, IncreseSP, IncreseDP, IncreseHungry, IncreseThirsty를 호출해서
회복 효과를 호출해준다
우리가 언제 만들었는지 기억이 안난다?
StatusController 스크립트에서 아래 스크린샷에 나온 부분이 회복할대 호출할 함수이다
우리는 이미 만들어두었다!
다시 ItemEffectDatabase 스크립트로 넘어와서
42번의 스위치문이 끝나면 Debug.Log로 어떤 아이템을 사용했는지 콘솔을 띠울 것이고
40번의 for문은 사용한 인수를 넘겨줘야 하므로 return해준다
36번의 for문에서 해당하는 아이템이 없는 경우 일치하는 아이템이 없다고 콘솔에 띠워준다
이제 Slot 스크립트를 보자
원래는 WeaponManager 부분이 있었는
데 우리는 아래 스크린샷 처럼 ItemEffectDAtabase로 장비무기를 넘겨줬다
따라서 Slot에서 겹치는 WeaponManager부분은 지워준다
완성된 스크립트는 필자가 맨위에 복사해서 올려놨다 그거 보고 참고해도 된다
이제 테스트를 위해 필자처럼 하이러키에 DataBase라는 빈 객체를 만들어주고 여기에 ItemEffectDatabase 스크립트를 넣어주자
그리고 part에는 회복되는 부위를, Num에는 회복량을 적어주고 테스트를 하면...
왼쪽의 아래에 보면 배고픔 게이지와 목마름 게이지가 있는데 아이템을 사용하니 회복되는 것을 보인다