많은 게임에는 플레이어의 캐릭터에 레벨 및 경험치 시스템이 있어 더욱 강력해지게 해 줍니다. 이번 글에서는 플레이어의 캐릭터가 적 몬스터를 처치하거나, 퀘스트를 완료할 경우 경험치가 오르고, 경험치가 모두 찼다면 레벨을 증가시키는 기능을 구현하고 정리해 보았습니다.
💬 서론
- 이 글에 포함된 게임 프로젝트에는 스탯, 적(FSM), 퀘스트 등 다른 기능이 포함되어있습니다. 하지만 글의 주제인 [레벨, 경험치]를 파악하는데는 크게 어려움이 없습니다.
💭 흐름도
- 특정 조건에 의해 경험치를 받아야한다면 경험치를 추가하는 함수를 호출합니다.
- 경험치를 계산하고 코루틴을 호출하여 점진적으로 경험치 바를 채우고, 경험치 바가 모두 찼다면 레벨업을 합니다.
✅ 구현
· ExpManager
- 경험치를 획득하고 레벨업을 하게되면, 다음 레벨까지 얻어야 할 경험치는 직전 경험치의 2배로 늘어나도록 구현하였습니다.
- 100(기본 최대치) > 200 > 400 > 800와 같이 100 * 2^n 으로 증가합니다.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using GameSave;
public class ExpManager : Singleton<ExpManager>
{
[Header("경험치 바")]
[SerializeField] private Image mExpCurrentBar;
/// <summary>
/// 플레이어의 현재 경험치
/// </summary>
public float ExpCurrent { private set; get; }
/// <summary>
/// 플레이어의 현재 최대 경험치
/// </summary>
public float ExpMax { private set; get; } = 100;
private Coroutine? mCoUpdateExpBarFill;
public void AddExp(float amount)
{
float expPrev = ExpCurrent;
ExpCurrent += amount;
if (mCoUpdateExpBarFill is not null)
StopCoroutine(mCoUpdateExpBarFill);
mCoUpdateExpBarFill = StartCoroutine(CoUpdateExpBarFill(expPrev));
}
/// <summary>
/// 세이브파일로부터 로드된경우 현재EXP와 최대EXP를 설정
/// </summary>
public void LoadFromData(PlayerGameData playerGameData)
{
this.ExpMax = playerGameData.expMax;
this.ExpCurrent = playerGameData.expCurrent;
mExpCurrentBar.fillAmount = this.ExpCurrent / this.ExpMax;
}
private IEnumerator CoUpdateExpBarFill(float expPrev)
{
float process = 0f;
while (process < 1f)
{
process += Time.deltaTime;
expPrev = Mathf.Lerp(expPrev, ExpCurrent, process);
mExpCurrentBar.fillAmount = expPrev / ExpMax;
if (expPrev / ExpMax > 1f)
{
expPrev = 0f;
process = 0f;
ExpCurrent -= ExpMax;
ExpMax *= 2.0f;
StatManager.Instance.LevelUp(); //스탯매니저 레벨업 호출
}
yield return null;
}
}
}
[Header("경험치 바")]
[SerializeField] private Image mExpCurrentBar;
- 스크립트에서 제어할 이미지 컴포넌트를 사용합니다.
- fillAmount를 이용하여 경험치 바를 채웁니다.
/// <summary>
/// 플레이어의 현재 경험치
/// </summary>
public float ExpCurrent { private set; get; }
/// <summary>
/// 플레이어의 현재 최대 경험치
/// </summary>
public float ExpMax { private set; get; } = 100;
- 플레이어의 현재 경험치 ExpCurrent와 현재 경험치를 기준으로 레벨업을 하기위한 다음 경험치 ExpMax입니다.
public void AddExp(float amount)
{
float expPrev = ExpCurrent;
ExpCurrent += amount;
if (mCoUpdateExpBarFill is not null)
StopCoroutine(mCoUpdateExpBarFill);
mCoUpdateExpBarFill = StartCoroutine(CoUpdateExpBarFill(expPrev));
}
- 외부에서 호출되며, 플레이어에게 경험치를 지급합니다.
- 현재 경험치에 amount를 더하여 경험치를 계산하고 코루틴을 호출합니다.
private IEnumerator CoUpdateExpBarFill(float expPrev)
{
float process = 0f;
while (process < 1f)
{
process += Time.deltaTime;
expPrev = Mathf.Lerp(expPrev, ExpCurrent, process);
mExpCurrentBar.fillAmount = expPrev / ExpMax;
if (expPrev / ExpMax > 1f)
{
expPrev = 0f;
process = 0f;
ExpCurrent -= ExpMax;
ExpMax *= 2.0f;
StatManager.Instance.LevelUp(); //스탯매니저 레벨업 호출
}
yield return null;
}
}
- 경험치 바를 채우고, 경험치 바가 모두 찼다면 레벨업을 하고 다시 처음부터 경험치를 채우도록 합니다.
- StatManager.Instance.LevelUp()은 스탯을 관리하는 스탯매니저로, 레벨업을 하게되면 스탯을 강화하도록 해주는 기능입니다. 추후에 다룰 예정입니다.
✅ 사용 방법
· Scene 설정
- 매니저 역할을 할 ExpManager.cs를 런타임도중 비활성화 되지 않는 오브젝트에 할당합니다.
- ExpManager.cs에 경험치 바를 사용할 이미지를 등록합니다.
- 경험치 바 이미지를 설정합니다.
- Image Type은 Filled로 설정합니다(0~1 값에 따라 채우도록)
- Fill Method 는 Horizontal(가로 방향)으로 설정합니다.
- Fill Origin은 Left(왼쪽부터 채워지도록)으로 설정합니다.
· AddExp 호출
- 특정 조건이 발생하면 AddExp를 호출하여 경험치를 지급해야합니다.
public void CompleteQuest(int questId, bool isGiveAward = true)
{
// 퀘스트 획득
QuestData quest = Quests[questId];
if(isGiveAward) // 보상 지급
{
// 경험치 지급
ExpManager.Instance.AddExp(quest.expAmount);
}
// 퀘스트 콘텐츠 매니저에서 UI 제거
QuestContentManager.Instance.CompleteQuest(quest); // 퀘스트 콘텐츠 매니저에서 컴팩트 퀘스트UI 제거
// 현재 진행중인 퀘스트 제거
mReceivedQuests.Remove(quest);
// 퀘스트를 CLEARED_PAST 상태로 변경
quest.questState = QuestState.CLEARED_PAST;
}
- 퀘스트를 클리어 한 경우 보상을 지급하는 상황인경우 경험치를 지급하도록 하였습니다.
public void DestroyEntity()
{
// 이미 파괴 대기 상태라면 리턴
if (IsWaitDead)
return;
// 아이템 드랍 시도
foreach(ItemDropInfo dropInfo in mDropItems)
{
// 확률 계산 0f ~ 1f
if(Random.value > dropInfo.DropChange)
continue;
ItemPickUp item = Instantiate(dropInfo.ItemPrefab, transform.position + Vector3.up * 2.0f, Quaternion.identity).GetComponent<ItemPickUp>();
item.ItemCount = Random.Range(dropInfo.MinDropCount, dropInfo.MaxDropCount + 1);
}
// 파괴 대기상태 활성화
IsWaitDead = true;
// 무기로 인한 충돌감지 해제
IsNoneCheckState = true;
// EnemyManager에서 자기 자신 삭제
EnemyManager.Instance.RemoveEnemy(this);
// 퀘스트에서 처치 호출
QuestManager.Instance.UpdateKillQuestCount(mID);
// 경험치 지급
ExpManager.Instance.AddExp(GiveExp);
}
- 적을 처치한경우 해당 적은 Destroy가 되는데, 이 상태에 경험치를 지급하도록 하였습니다.
✅ 결과
- 적과 전투 중 적을 처치하면 일정량의 경험치를 획득하고, 경험치바가 모두 차면 레벨업을 하여 경험치바가 다시 갱신되는것을 볼 수 있습니다.
'unity game modules' 카테고리의 다른 글
[유니티] 스탯 시스템(2) - 플레이어 스탯관리 (0) | 2023.03.24 |
---|---|
[유니티] 스탯 시스템(1) - 디자인 (0) | 2023.03.24 |
[유니티] 환경 사운드 (Ambient Area) (0) | 2023.03.23 |
[유니티] 자동 스크롤 (0) | 2023.03.22 |
[유니티] 외곽선 쉐이더 구현 및 관리 (0) | 2023.03.21 |