캐릭터에 무기를 달기 어렵다는 점 때문에 외관상 바뀌지 않아도 되는 스킬 포인트 시스템을 차용하기로 했다.

 

초기 구상

원거리/근거리가 주 공격/ 보조 공격으로 주어지며 업그레이드로 다양한 스킬 트리를 구사할 수 있도록 한다.

즉, 기본 공격인 주 공격과 보조 공격은 스킬 선택에 따라 달라진다.

 

Skill의 역할

기본 공격(주 공격 / 보조 공격)은 스킬 포인트를 통해 업그레이드 할 수 있고 마우스 좌/우클릭을 통해 조작 가능하다.

패시브 스킬은 시간제한이 있으며, 특정 조건에 발동한다.

 

  • 업그레이드는 총 3레벨까지 올릴 수 있다.
  • 3레벨 달성 시, 해당하는 스킬 트리의 패시브 스킬이 자동으로 활성화 된다.
  • 스킬 포인트는 게임 플레이를 하며 얻을 수 있다.(스토리 단서를 모았을 시로 구상 중)

'부트캠프 > Project' 카테고리의 다른 글

Enemy - FSM(2)  (0) 2024.02.08
Enemy - FSM(1)  (0) 2024.02.07
Projectile 구현  (0) 2024.01.19
Stat / Status 구현  (0) 2024.01.18
StatModifier 구현 계획  (0) 2024.01.17

Projectile은 게임 내에서 발사되는 발사체(또는 투사체) 오브젝트이다.

 

Projectile

구현 방법

Rigidbody를 통해 충돌처리를 구현하고, 코루틴을 통해 발사체의 지속시간을 구현했다.

 

 

구현 기능

OnTriggerEnter2D(Collider2D collision): 몇 가지 예외를 제외하고 Creature를 공격한다.
OnDisable(): 코루틴을 중단한다.
SetInfo(Creature owner): Creature에 대한 발사체 정보를 초기화하고 코루틴 중복을 방지한다.
CoDestroy(): 발사체의 지속시간만큼 대기한다.

public class Projectile : Thing
{
    public Creature Owner { get; protected set; } // 발사체 주인.

    // public new Creature.Status; // Creature의 Status에서 지속시간과 데미지 가져오는 방법 TODO.
    public float Duration { get; protected set; } // 발사체 지속시간.
    public float Damage { get; protected set; } // 발사체 데미지.
    public Vector2 Velocity { get; set; } // 발사체 속도.

    protected Rigidbody2D _rigidbody; // 충돌처리를 위한 Rigidbody.
    private Coroutine _coDestroy; // 코루틴이 null인지 활성화 되어있는지 확인하기 위한 필드.

    // Rigidbody가 붙은 발사체에 대한 속도.
    protected virtual void FixedUpdate()
    {
        _rigidbody.velocity = Velocity;
    }

    protected virtual void OnTriggerEnter2D(Collider2D collision)
    {
        Creature creature = collision.GetComponent<Creature>();
        if (!creature.IsValid() || !this.IsValid()) return;
        if (creature == Owner) return; // Creature가 발사체의 주인이라면.
        if (creature.State.Current == CreatureState.Dead) return; // Creature의 현재 상태가 죽었다면.

        creature.OnHit(Owner, Damage, new() { time = 0.1f, speed = 10f, direction = (creature.transform.position - this.transform.position).normalized }); // Creature 공격.

        _rigidbody.velocity = Velocity = Vector2.zero;
        if (this.IsValid()) Main.Object.DespawnProjectile(this);
    }

    protected void OnDisable()
    {
        StopAllCoroutines(); // 모든 코루틴 중단.
        _coDestroy = null;
    }

    public override bool Initialize()
    {
        if (!base.Initialize()) return false;

        _rigidbody = this.GetComponent<Rigidbody2D>();

        return true;
    }

    public virtual Projectile SetInfo(Creature owner) // Creature에 대한 발사체 정보.
    {
        this.Owner = owner;
        Duration = 5; // 임시
        Damage = 10; // 임시

        if (_coDestroy != null) StopCoroutine(this._coDestroy); // 코루틴 중복 방지.
        _coDestroy = StartCoroutine(CoDestroy());

        return this;
    }

    private IEnumerator CoDestroy()
    {
        yield return new WaitForSeconds(Duration); // 발사체 지속시간만큼 대기.
        _coDestroy = null;
        Main.Object.DespawnProjectile(this); // 오브젝트가 비활성화 시.
    }
}

 

 

'부트캠프 > Project' 카테고리의 다른 글

Enemy - FSM(1)  (0) 2024.02.07
Skill 구상  (0) 2024.01.23
Stat / Status 구현  (0) 2024.01.18
StatModifier 구현 계획  (0) 2024.01.17
Resource Manager 구현  (0) 2024.01.15

캐릭터나 오브젝트의 다양한 수치적 속성(생명력, 공격력 등)을 관리하는 Stat과 그 스탯들을 관리하는 Status를 구현한다.

 

Stat

구현 방법

새로운 스탯 인스턴스를 생성하여 초기값을 생성하는 생성자를 만들고, StatModifier에서 modifier의 값을 받아 스탯의 수정치를 확인하고 수정하는 함수를 구현한다.

 

 

구현 기능

Stat(): 새로운 스탯 인스턴스를 생성하고 초기값을 생성하는 생성자.
SetValue(): 값을 받으면 바뀐 값을 대입한다.
AddModifier() /RemoveModifier(): 수정치를 추가하거나 삭제한다.
GetModifyValue(): Value를 해당하는 StatModifierType으로 계산한다.

public class Stat
{
    public StatType Type { get; private set; }
    public float Min { get; private set; }
    public float Max { get; private set; }
    public float Value { get; private set; }
    public float OriginValue { get; private set; }

    private List<StatModifier> _modifiers = new(); // 스탯이 가지고 있는 수정치 목록.

    public event Action<Stat> OnChanged;

    // 새로운 스탯 인스턴스를 생성하고 초기값을 생성하는 생성자.
    public Stat(StatType type, float value = 0, float min = 0, float max = float.MaxValue)
    {
        this.Type = type;
        this.Min = min;
        this.Max = max;
        SetValue(value);
    }

    // 값을 받으면 바뀐 값을 대입.
    public void SetValue(float value)
    {
        OriginValue = value;
        Value = GetModifyValue();
        OnChanged?.Invoke(this);
    }

    // 수정치를 추가하거나 삭제하는 기능.
    public void AddModifier(StatModifier modifier)
    {
        _modifiers.Add(modifier);
        Value = GetModifyValue();
        OnChanged?.Invoke(this); // 능력치에 변화가 있다면 호출.
    }
    public void RemoveModifier(StatModifier modifier)
    {
        _modifiers.Remove(modifier);
        Value = GetModifyValue();
        OnChanged?.Invoke(this); // 능력치에 변화가 있다면 호출.
    }


    // _modifiers 리스트에 들어있는 객체들의 StatModifierType을 비교하여 Value를 해당하는 StatModifierType으로 계산한다.
    private float GetModifyValue()
    {
        float value = OriginValue;
        for (int i = 0; i < _modifiers.Count; i++)
        {
            // Stat 계산 방법.
            if (_modifiers[i].Type == StatModifierType.Add) value += _modifiers[i].Value;
            else if (_modifiers[i].Type == StatModifierType.Multiple) value *= _modifiers[i].Value;
            else if (_modifiers[i].Type == StatModifierType.Override) value = _modifiers[i].Value;
        }
        value = Mathf.Clamp(value, Min, Max);
        return value;
    }
}

 

 

Status

구현 방법

수정할 스탯 리스트를 받아 알맞은 스탯에 추가하거나 제거하는 기능을 구현한다.

 

 

구현 기능

StatType: 스탯 타입들. COUNT는 갯수를 파악하기 위한 상수이다.

StatModifierType: 수정치 계산 종류.

Stat this: 스탯 종류를 받아온다.

Status(): 스탯 종류를 확인 후, 딕셔너리에 추가.

Status(CreatureData data): 기존 데이터를 받아와 스탯에 대입한다.

AddModifiers / RemoveModifiers: 변화될 스탯을 리스트에서 찾아 스탯에 변화를 주는 함수들를 추가하거나 제거한다.

public enum StatType
{
    HpMax,
    HpRegen,
    Damage,
    Defense,
    MoveSpeed,
    AttackSpeed,
    //Cost,
    //Range,
    //Sight,
    COUNT // StatType 갯수 파악을 위한 상수.
}

public enum StatModifierType
{
    Add,
    Multiple,
    Override,
}


public class Status
{
    private Dictionary<StatType, Stat> _stats;

    public Stat this[StatType type]
    {
        get => _stats[type];
    }

    // 스탯 타입을 확인하고 딕셔너리에 추가.
    public Status()
    {
        _stats = new();
        for (int i = 0; i < (int)StatType.COUNT; i++)
        {
            _stats.Add((StatType)i, new Stat((StatType)i));
        }
    }

    // 크리처의 기존 데이터를 받아와서 스탯에 대입.
    public Status(CreatureData data)
    {
        _stats = new()
        {
            [StatType.HpMax] = new(StatType.HpMax, data.HpMax),
            [StatType.HpRegen] = new(StatType.HpRegen, data.HpRegen),
            [StatType.Damage] = new(StatType.Damage, data.Damage),
            [StatType.Defense] = new(StatType.Defense, data.Defense),
            [StatType.MoveSpeed] = new(StatType.MoveSpeed, data.MoveSpeed),
            [StatType.AttackSpeed] = new(StatType.AttackSpeed, data.AttackSpeed),
        };
    }

    // 변화될 스탯을 리스트에서 찾아 스탯에 변화를 주는 함수를 추가 / 제거.
    public void AddModifiers(List<StatModifier> modifiers)
    {
        for (int i = 0; i < modifiers.Count; i++)
        {
            this[modifiers[i].Stat].AddModifier(modifiers[i]);
        }
    }
    public void RemoveModifiers(List<StatModifier> modifiers)
    {
        for (int i = 0; i < modifiers.Count; i++)
        {
            this[modifiers[i].Stat].RemoveModifier(modifiers[i]);
        }
    }
}

'부트캠프 > Project' 카테고리의 다른 글

Skill 구상  (0) 2024.01.23
Projectile 구현  (0) 2024.01.19
StatModifier 구현 계획  (0) 2024.01.17
Resource Manager 구현  (0) 2024.01.15
<프로젝트> 팀과제 Unity 리듬 게임 회고  (2) 2024.01.09

스탯을 각 개체 클래스의 필드로 직접 관리하게 되면, 다양한 유형의 수정치를 적용하거나 스탯 간 복잡한 상호작용을 구현하기 어렵고 스탯 관리 로직이 특정 클래스와 밀접하게 결합되어 있으면 다른 클래스나 시스템에서 재사용하기 어렵다.

새로운 스탯 타입 또는 수정치를 추가하기 위해 기존 클래스를 크게 수정해야 할 수도 있어 유지보수가 어렵고 비슷한 스탯 관리 코드가 중복될 가능성도 있다.

그렇기 때문에 기존 스탯과 결합하여 스탯을 변화시키는 수정치인 StatModifier를 따로 구현하기로 했다.

 

구현 계획

  • 어떤 스탯을 얼마나 어떻게 수정할 것인지 정보를 받아온다.
  • 새로운 수정치 인스턴스를 생성하고 초기값을 설정하는 생성자
  • string 값(Modifiers)을 받아 새 인스턴스를 생성하는 생성자

 

Stat에서 캐릭터나 오브젝트의 다양한 수치적 속성(생명력, 공격력 등)을 관리하고 Status에서 모든 Stat을 관리하도록 Class를 분리한다.

public class StatModifier
{
    public StatType Stat { get; set; }
    public StatModifierType Type { get; set; }
    public float Value { get; set; }

    // 기본 생성자.
    public StatModifier() { }

    // Modifier 값을 받아온다.
    public StatModifier(StatType stat, StatModifierType type, float value)
    {
        Stat = stat;
        Type = type;
        Value = value;
    }

    // json 파일의 Modifier를 나눠서 Enum으로 변환한다. 
    public StatModifier(string s)
    {
        string[] strings = s.Split('_');
        Stat = (StatType)Enum.Parse(typeof(StatType), strings[0]);
        Type = (StatModifierType)Enum.Parse(typeof(StatModifierType), strings[1]);
        Value = float.Parse(strings[2]);
    }

    // 받은 값들을 깊은복사한다.
    public StatModifier Copy()
    {
        return new(Stat, Type, Value);
    }
}

 

'부트캠프 > Project' 카테고리의 다른 글

Projectile 구현  (0) 2024.01.19
Stat / Status 구현  (0) 2024.01.18
Resource Manager 구현  (0) 2024.01.15
<프로젝트> 팀과제 Unity 리듬 게임 회고  (2) 2024.01.09
<프로젝트> 팀과제 Unity 리듬 게임(4)  (1) 2024.01.05

+ Recent posts