TIL - 17

Chu_uhC·2023년 11월 28일
0

📄 23.11.27✍ 인터렉션 UI

기본부터 만들기 시작하니 생각보다 힘이든다.
리팩토링을 새로하기엔 시간이 충분한걸까?
오히려 기본적으로 구현된 부분이 있기에 더욱 어려운 것 같다.

📄 23.11.28✍ 전략 패턴에 개성을 더하기

✨ 기존에 전략 패턴을 사용할 때 가장 큰 문제점은 모두가 같은 인터페이스만 사용하였기에 비슷한 코드밖에 작성하지 못하였다.
하지만 더 많은 기능을 추가하고 사용하는 방법이 있다.

🔨 기존에 사용하던 방식

public interface IBuildingAbility
{
    public void Init(PassiveBuildingData data);
    public void Activation();
    public void Deactivation();
}

public class AbilityHeroStat : IBuildingAbility
{
    private PassiveBuildingData _data;

    public void Init(PassiveBuildingData data)
    {
        _data = data;
    }

    public void Activation() { }
    public void Deactivation() { }
}

 속받는 모두가 같은 초기화 함수를 사용하기에 PassiveBuildingData만을 사용하여 기능을 만들어 내야한다.
Data에 더 많은 정보를 추가함으로써도 해결이 되지만 사용하지 않는 클래스들도 그 값을 가지고 있기에 불필요한 메모리 낭비가 되는 건 개선해야하는 부분 중 하나가 될 수 밖에 없다.

🔨 해결 방법

public interface IColliderProcessable
{
    public void ColliderInit(List<BaseBuilding> baseBuilding);
}

public class AbilityGroundStat : IBuildingAbility, IColliderProcessable
{
    private List<BaseBuilding> _baseBuildings;
    private PassiveBuildingData _data;

    public void ColliderInit(List<BaseBuilding> baseBuilding)s
    {
        _baseBuildings = baseBuildings;
    }

    public void Init(PassiveBuildingData data)
    {
        _data = data;
    }

	...
}

 무나도 당연한 인터페이스 역할인 기능 추가를 활용하는 방법이다.
인터페이스에 대한 명확한 개념이 없었기에 이 방법을 생각하는데 엄청나게 오래 걸렸던 것 같다.
이렇게 함으로써 class AbilityGroundStatCollider를 가질 수 있는 기능이 추가되었다. 그럼 이 부분을 어떻게 활용할 것인가에 대하여 여러가지 방법이 있지만 현재 구조상 가장 간단한 방법으로 구현해보자.

🔨 인터페이스가 두 개인 구조를 사용해보자

public override void Init(BuildingType type)
{
    base.Init(type);

    switch (PassiveType)
    {
        case BuildingPassiveType.Water:
            Ability = new AbilityGroundStat();
            break;
        case BuildingPassiveType.HeroCount:
            Ability = new AbilityHeroStat();
            break;
        default:
            break;
    }
    
	// 여기서부터가 인터페이스를 체크하는 부분
    // is as 캐스팅을 두 번 사용하기에 효율적인 코드는 아니다.
    if (Ability is IColliderProcessable)
    {
        IColliderProcessable cAbility = Ability as IColliderProcessable;
        cAbility.ColliderInit(detectivedBuilding);
    }
	Ability.Init(_passiveData);
    Ability.Activation()
}

 순하지만 IColliderProcessable를 상속받은 클래스라면 ColliderInit가 실행될 것이며 또한 Init, Activation가 공통적으로 실행 될 것이다.
이런 식으로 사용해봄으로써 인터페이스가 왜 객체지향의 꽃이라고도 불리는지 이해할 수 있게되었다.

📌 인터페이스가 꽃이라고 덕지덕지 붙이면 오히려 코드에 방해가 되고 구조를 짜는데 있어 시간이 오래 걸려 개발 시간이 늘어지게 되는 경우도 발생할 수 있다.

📄 23.11.29✍ 코루틴으로 Press구현하기

✨ 게임을 하다보면 오입력을 방지하기 위해서 키를 일정 시간동안 입력해줘야지 작동되는 방식이있다.
이런 방식은 따로 UI를 띄우지 않아도 되기때문에 플레이어의 몰입을 방해하지않는다고 생각한다.

🔨 입력을 받을 클래스

public Image Ring;
public event Action OnCompletePress; // 실행될 함수

public void InputStart()
{
    StartCoroutine(nameof(PressEnter));
}

public void InputCancel()
{
    StopCoroutine(nameof(PressEnter));
    Ring.fillAmount = 0.0f;
}

private IEnumerator PressEnter()
{
    while (Ring.fillAmount < 1.0f)
    {
        Ring.fillAmount += 0.7f * Time.deltaTime; // 원이 차오르는 속도
        yield return null;
    }
    Ring.fillAmount = 0.0f;
    OnCompletePress;
}

 조는 코루틴을 시작할 함수끝내는 함수 그리고 일정 시간 뒤 함수를 실행할 코루틴만 만들면 된다.
그리고 이 구조를 키입력을 담당하는 클래스에게 맡기면 된다.

🔨 InputSystem - SendMessage

public void OnMap(InputValue value)
{
    bool isPressed = value.isPressed;
    
    if (isPressed)
        _travelGuideUI.StartEnter();
    else
        _travelGuideUI.CancelEnter();
}

 풋 시스템에서 키를 입력하면 눌렸을 때, 땔 때를 값으로 받아볼 수 있다.
즉, '누르는 중'일 때를 확인하는 것이 아니므로 성능적으로도 우수하다고 할 수 있다.

📄 23.11.30✍ 밴드 공연

을 성공적으로 마무리했다.

📄 23.12.1✍ 아이템부분을 거의 끝냈다.

굿!

profile
ChuNyan

0개의 댓글