게임 로고 이미지

이번 시간에는 Json 데이터를 불러와서 파싱된 데이터로 레벨업 하는 시스템을 만들어 보겠습니다. 또한 레벨 업 했을 경우 힘, 민첩, 지능, 체력 등의 스탯이 올라가는 성장 시스템 까지 만들어 보겠습니다.


[경험치 테이블 구현]

레벨업 하는 경험치 밸런스를 조절하는 방법은 두 가지가 있습니다. 공식을 통한 방법과 1레벨부터 최대 레벨까지 필요 경험치를 수동으로 작성하는 방법입니다. 저는 수동으로 작성하는 방법을 선호하기에 해당 방법으로 구현하겠습니다. 여기서 몇몇 분들은 수동이 왜 좋은 지 궁금하실 분들이 계실 겁니다. 그러므로 구현하기전에 각각의 장 단점을 알아 보겠습니다.

[공식을 통한 레벨 업 밸런스 조절]

수식으로 조절하기 때문에 최대 레벨을 확장해도 별 문제가 없습니다. 이미 레벨이 올라갈 수록 해당 수식으로 경험치 양이 정해지기 때문입니다. 하지만 게임의 밸런스를 잡기가 매우 힘들다는 단점이 있습니다. 레벨 업 을 특정 구간을 빠르게 하고, 다른 구간은 느리게 하고 싶을 경우 어느 정도 조절은 가능 하지만 수동으로 작성 하는 것 보다 의도된 밸런싱이 어렵습니다.

[수동으로 경험치 테이블을 구현]

최대 레벨이 확장 될 때마다 데이터를 추가해야 한다는 단점이 있지만 밸런스를 조절 하기가 더욱 수월 합니다.

테이블 구현 예시

{
    "1": 100,
    "2": 200,
    "3": 400,
    "4": 800,
    "5": 1600
    // 다른 레벨에 대한 경험치를 추가하세요.
}

Json으로 표현하면 위와 같은 방식입니다. 엑셀로 표현하면 왼쪽 값이 Level이 될 것이며 오른쪽 값이 Experience가 됩니다.

[경험치 테이블 파싱]

using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class ExperienceTable
{
    private Dictionary<int, int> experienceTable;

    public ExperienceTable()
    {
        experienceTable = new Dictionary<int, int>();
        LoadExperienceTable();
    }

    private void LoadExperienceTable()
    {
        string path = Path.Combine(Application.streamingAssetsPath, "experience_table.json");

        if (File.Exists(path))
        {
            string json = File.ReadAllText(path);
            experienceTable = JsonUtility.FromJson<Dictionary<int, int>>(json);
        }
        else
        {
            Debug.LogError("Experience table JSON file not found.");
        }
    }

    public int GetExperienceForLevel(int level)
    {
        if (experienceTable.ContainsKey(level))
        {
            return experienceTable[level];
        }
        return 0;
    }
}

Json파일이 저장돼 있는 경로에서 파싱하는 과정입니다. 로컬 파일 내부에서 가져온다는 가정으로 구현한 것 입니다. 만약 서버에서 받은 Json 파일을 파싱 할 경우에는 경로에서 가져오는 것이 아닌 서버에서 가져오는 방법으로 바꿔주면 됩니다.

또한 유니티에서는 JsonUtility로 손쉽게 파싱이 가능하다는 점도 기억해 두시면 좋습니다.

[캐릭터 클래스]

캐릭터 클래스는 실제로 레벨업을 하는 부분 입니다.

public class Character
{
    public int Level { get; private set; }
    public int Experience { get; private set; }
    public Stats Stats { get; private set; }
    private ExperienceTable experienceTable;

    public Character(int level, int experience, Stats stats)
    {
        Level = level;
        Experience = experience;
        Stats = stats;
        experienceTable = new ExperienceTable();
    }

    public void GainExperience(int amount)
    {
        Experience += amount;
        CheckForLevelUp();
    }

    private void CheckForLevelUp()
    {
        int requiredExperience = experienceTable.GetExperienceForLevel(Level + 1);
        if (Experience >= requiredExperience)
        {
            LevelUp();
        }
    }

    private void LevelUp()
    {
        Level++;
        Stats.IncreaseStatsForLevelUp();
    }
}

예시에서는 간단하게 구현하여 이해를 돕기 위해서 캐릭터 생성 시 experienceTable = new ExperienceTable();와 같은 방식으로 경험치 테이블을 가져 오지만 원래라면 데이터 매니저를 따로 만들어야 한다는 것을 생각하셔야 합니다.

[스탯 클래스]

public class Stats
{
    public int Strength { get; private set; }
    public int Agility { get; private set; }
    public int Intelligence { get; private set; }
    public int Stamina { get; private set; }

    public Stats(int strength, int agility, int intelligence, int stamina)
    {
        Strength = strength;
        Agility = agility;
        Intelligence = intelligence;
        Stamina = stamina;
    }

    public void IncreaseStatsForLevelUp()
    {
        // 레벨업 시 스탯을 상승하는 로직을 추가합니다. 예를 들어, 각 스탯을 일정량씩 증가시킬 수 있습니다.
        Strength += 2;
        Agility += 2;
        Intelligence += 2;
        Stamina += 2;
    }
}

능력치를 관리하는 클래스 입니다. 각각 능력치를 Property로 구현한 것을 주의깊게 보셔야 합니다. 스탯은 값을 바꾸거나 값을 가져올 시점에 여러 이벤트가 처리가 되는 경우가 많습니다. 예를 들어서 전투력이 올라갈 경우 전투력이 얼마나 올랐는지 유저에게 보여주기 위한 UI를 띄워주는 경우를 들 수 있습니다. 이러한 경우 프로퍼티의 set부분에 이벤트를 발생시켜주면 손쉽게 구현이 가능합니다.

[레벨업 예시]

using UnityEngine;

public class Monster : MonoBehaviour
{
    public int maxHealth = 100;
    private int currentHealth;

    void Start()
    {
        currentHealth = maxHealth;
    }

    public void TakeDamage(int damage)
    {
        currentHealth -= damage;
        if (currentHealth <= 0)
        {
            Die();
        }
    }

    private void Die()
    {
        // 몬스터가 죽었을 때 경험치를 얻습니다.
        int experienceGained = 100; // 몬스터로부터 얻은 경험치

        // 플레이어 GameObject에서 Character 컴포넌트를 찾아서 경험치를 추가합니다.
        Character playerCharacter = GameObject.FindWithTag("Player").GetComponent<Character>();
        if (playerCharacter != null)
        {
            playerCharacter.GainExperience(experienceGained);
        }

        Debug.Log("Monster Died! Experience Gained: " + experienceGained);

        // 몬스터 오브젝트를 파괴하거나 비활성화하는 코드를 추가할 수 있습니다.
        gameObject.SetActive(false);
    }
}

몬스터가 죽었을 경우 캐릭터를 찾아 경험치를 부여해주는 방식으로 사용하시면 됩니다. 이 방법을 원하지 않으신다면 이벤트 프로그래밍을 사용하여 몬스터가 죽었을 때 이벤트를 발생시켜 해당 이벤트를 받아 경험치 처리를 해주면 됩니다.

[마무리]

이해를 돕기 위해서 가장 핵심이 되는 부분만 구현 하였습니다. 가장 중요한 점은 스탯을 관리하는 클래스(Stats) 캐릭터의 레벨업을 적용하는 클래스(Character) 경험치 데이터를 관리하는 클래스(ExperienceTable)로 나눠서 구현 해야 한다는 것 입니다. 각각의 역할을 명확히 해야 확장성과 유연성이 높아지며 이는 프로젝트의 퀄리티와 직결되는 문제 입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다