오늘은 자동재화를 많이 추가해보겠다. 상속(Inheritance)과 인터페이스(Interface) 를 활용해봐야겠다.
Unity에서 상속을 사용한 게임 오브젝트 확장 및 UI 업데이트
오늘은 Unity를 사용하여 게임 오브젝트를 확장하고, 다양한 종류의 오브젝트에 맞춘 UI 업데이트를 구현하는 작업을 진행했습니다. 이 과정에서 몇 가지 중요한 패턴과 개념을 배우게 되었습니다.
1. 상속(Inheritance)과 인터페이스(Interface)
상속: RootBase 클래스를 기반으로 Root1과 Root2 클래스가 상속을 받아 구현되었습니다. 상속을 통해 중복 코드를 줄이고, 공통된 기능을 부모 클래스에서 정의하여 코드의 재사용성을 높였습니다.
인터페이스: IRoot 인터페이스를 사용하여 공통된 메서드 서명을 정의하고, 이를 여러 클래스에서 구현함으로써 일관된 인터페이스를 제공합니다. 이는 다형성을 활용하여 다양한 타입의 객체를 동일한 방법으로 처리할 수 있게 해줍니다.
2. 이벤트와 델리게이트
이벤트: 이벤트를 사용하여 특정 조건이 발생했을 때 다른 객체가 이에 반응하도록 설계했습니다. LifeGenerated 델리게이트와 OnGenerationRateChanged 이벤트를 통해 라이프가 생성되거나 생성 속도가 변경될 때 이를 통지합니다.
델리게이트: 델리게이트를 사용하여 메서드를 참조하고, 이벤트가 발생했을 때 이를 호출하도록 설정했습니다. 이를 통해 코드의 결합도를 낮추고, 유연성을 높일 수 있었습니다.
3. UI 업데이트
UI 요소 참조: TextMeshProUGUI 컴포넌트를 사용하여 UI 텍스트 요소를 업데이트했습니다. 이를 통해 게임 오브젝트의 상태를 화면에 실시간으로 반영할 수 있었습니다.
UI 업데이트 메서드 재정의: RootBase 클래스에서 기본적인 UI 업데이트 로직을 정의하고, 이를 Root2 클래스에서 재정의하여 특정 클래스에 맞춘 UI 변경을 구현했습니다. 예를 들어, Root2 클래스에서는 "뿌리 레벨" 대신 "산호 레벨"로 표시되도록 재정의했습니다.
4. 설계 패턴 적용
템플릿 메서드 패턴(Template Method Pattern): RootBase 클래스의 GenerateLife 메서드는 템플릿 메서드 패턴을 적용하여, 기본적인 라이프 생성 로직을 정의하고 이를 자식 클래스에서 재정의하여 추가 기능을 구현할 수 있도록 했습니다.
옵저버 패턴(Observer Pattern): 이벤트와 델리게이트를 활용하여 옵저버 패턴을 구현했습니다. 이는 객체 상태 변화에 따른 알림을 다른 객체가 받을 수 있게 해주어, 객체 간의 의존성을 줄이고, 확장성을 높였습니다.
using TMPro;
using UnityEngine;
public interface IRoot
{
void ApplyIncreaseRate(float rate);
float GetTotalLifeGeneration();
}
public class RootBase : MonoBehaviour, IRoot
{
// 기본 속성 정의
public int rootLevel = 1; // 뿌리의 현재 레벨
public float baseLifeGeneration = 1; // 기본 라이프 생성량
public int lifeGenerationPerLevel = 1; // 레벨 당 추가 라이프 생성량
public int upgradeLifeCost = 20; // 업그레이드 비용
public float generationInterval = 1f; // 라이프 생성 주기
public TextMeshProUGUI rootLevelText; // 뿌리 레벨 UI 텍스트
public TextMeshProUGUI rootUpgradeCostText; // 업그레이드 비용 UI 텍스트
public TextMeshProUGUI generationRateText; // 생산률 UI 텍스트
private float timer; // 타이머 변수
// 이벤트 및 델리게이트 정의
public delegate void LifeGenerated(float amount);
protected event LifeGenerated OnLifeGenerated; // 라이프 생성 이벤트
public event System.Action OnGenerationRateChanged; // 생성 속도 변경 이벤트
// 초기화 메서드
protected virtual void Start()
{
// 이벤트 구독
OnLifeGenerated -= LifeManager.Instance.IncreaseWater;
OnLifeGenerated += LifeManager.Instance.IncreaseWater;
// UI 업데이트
UpdateUI();
}
// 매 프레임마다 호출되는 메서드
protected virtual void Update()
{
// 타이머 업데이트
timer += Time.deltaTime;
if (timer >= generationInterval)
{
// 라이프 생성
GenerateLife();
timer = 0f;
}
}
// 라이프 생성 메서드
protected virtual void GenerateLife()
{
float generatedLife = GetTotalLifeGeneration(); // 총 라이프 생성량 계산
InvokeLifeGenerated(generatedLife); // 라이프 생성 이벤트 호출
}
// 라이프 생성 이벤트 호출 메서드
protected void InvokeLifeGenerated(float amount)
{
OnLifeGenerated?.Invoke(amount);
}
// 업그레이드 비용 계산 메서드
public int CalculateUpgradeCost()
{
return rootLevel * 20;
}
// 라이프 생성 업그레이드 메서드
public virtual void UpgradeLifeGeneration()
{
rootLevel++; // 레벨 증가
if (rootLevel % 25 == 0)
{
baseLifeGeneration *= 2; // 매 25레벨마다 라이프 생성량 2배 증가
}
else
{
baseLifeGeneration += lifeGenerationPerLevel; // 기본 라이프 생성량 증가
}
upgradeLifeCost += 20; // 업그레이드 비용 증가
OnGenerationRateChanged?.Invoke(); // 생성 속도 변경 이벤트 호출
UpdateUI(); // UI 업데이트
}
// UI 업데이트 메서드
public virtual void UpdateUI()
{
UpdateRootLevelUI(rootLevel, upgradeLifeCost); // 뿌리 레벨 UI 업데이트
UpdateGenerationRateUI(GetTotalLifeGeneration()); // 생산률 UI 업데이트
}
// 라이프 생성 속도 적용 메서드
public virtual void ApplyIncreaseRate(float rate)
{
baseLifeGeneration *= 1 + rate; // 라이프 생성 속도 증가
OnGenerationRateChanged?.Invoke(); // 생성 속도 변경 이벤트 호출
UpdateUI(); // UI 업데이트
}
// 뿌리 레벨 UI 업데이트 메서드
public virtual void UpdateRootLevelUI(int rootLevel, int upgradeCost)
{
rootLevelText.text = $"뿌리 레벨: {rootLevel}"; // 뿌리 레벨 텍스트 설정
rootUpgradeCostText.text = $"강화 비용: {upgradeCost} 물"; // 업그레이드 비용 텍스트 설정
}
// 생산률 UI 업데이트 메서드
public virtual void UpdateGenerationRateUI(float generationRate)
{
if (generationRateText != null)
{
generationRateText.text = $"생산률: {generationRate} 물/초"; // 생산률 텍스트 설정
}
}
// 총 라이프 생성량 계산 메서드
public virtual float GetTotalLifeGeneration()
{
return baseLifeGeneration;
}
}
using System;
using TMPro;
using UnityEngine;
public class Root2 : RootBase
{
protected override void Start()
{
baseLifeGeneration = 3; // 여기서 baseLifeGeneration 값을 3으로 설정합니다.
base.Start();
LifeManager.Instance.RegisterRoot(this);
UpdateUI();
}
protected override void GenerateLife()
{
float generatedLife = GetTotalLifeGeneration();
InvokeLifeGenerated(generatedLife);
}
public override void UpdateUI()
{
base.UpdateUI();
}
public override void UpdateRootLevelUI(int rootLevel, int upgradeCost)
{
rootLevelText.text = $"산호 레벨: {rootLevel}";
rootUpgradeCostText.text = $"강화 비용: {upgradeCost} 물";
}
public override float GetTotalLifeGeneration()
{
return baseLifeGeneration;
}
}
오늘은 Unity에서 상속과 인터페이스를 활용하여 게임 오브젝트를 확장하고, 이벤트와 델리게이트를 사용하여 UI를 업데이트하는 방법을 배웠습니다. 이를 통해 코드의 재사용성과 확장성을 높일 수 있었으며, 다양한 설계 패턴을 적용하여 보다 효율적이고 유지보수 가능한 코드를 작성할 수 있었습니다.