์ฒซ ์ถ๋ฐ์ ์ โ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ํ๋ฉด ์ ๊ด๋ฆฌ(๋๋ ๊ตฌ๋ถ) ํ ์ ์์๊น?โ๋ ์ง๋ฌธ์์ ์์ ๋์๋ค.
์ต๊ทผ ๋ค์ด ๊ธฐํ์์ ์ฌ์ฉ์๊ฐ ์์ ๋กญ๊ฒ ์ฑ(๋๋ ์ฑ ๋ด๋ถ ํน์ ๊ธฐ๋ฅ)์ ์ปค์คํ ํ๋ ๊ธฐ๋ฅ์ ์๊ตฌํ๊ณ ์๋ค. ์ฌ์ฉ์๊ฐ ์์ ๋กญ๊ฒ ์ฑ์ ๊พธ๋ฏธ๊ฑฐ๋ ๋๋ ์บ๋ฆญํฐ๋ฅผ ์์ ๋กญ๊ฒ ๊พธ๋ฏธ๋ ๋ฑ ๊ฒฐ๊ตญ ์ฌ์ฉ์ ์ ๋ง์ ๋ง๋๋ก ์ํ๋ ์ค์ ์ ๋ค์ํ๊ฒ ์ ๊ณต์ ํด์ค์ผ ํ๋ค๋ ์ด์ผ๊ธฐ๋ฅผ ๋ฃ๊ณ ์๋ค.
์ด๋ป๊ฒ ํ๋ฉด ์ข์๊น๋ฅผ ๊ณ์ ๊ณ ๋ฏผ์ ํ๋ค๊ฐ ๊ฒฐ๊ตญ ๋ ์๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด์๋ค.
์ฆ, ํด๋์ค ๋ด๋ถ์์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ๋ณ๋์ ํ์ผ ํํ๋ก ๊ด๋ฆฌ๋ฅผ ํ๋ ๋ฐฉ์์ ์ฌ์ฉํด๋ณด๊ณ ์ ํ๋ค.
์ด์ ๊ฐ์ด ๋ฐ์ดํฐ์ ๋ก์ง์ ๊ตฌ๋ถ ์ง๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์ฐพ๋ ์ค MVP ํจํด์ ๋ฐ๊ฒฌํ๊ฒ ๋์ด ์คํฐ๋๋ฅผ ์์ํ๊ฒ ๋์๋ค.
Unity์์ ๋ฐ์ดํฐ ์์ฒด๋ฅผ Asset ํํ๋ก ๊ด๋ฆฌ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋๋ฐ ๋ฐ๋ก Scriptable Object์ด๋ค.
(Scriptable Object์ ๋ํ ์ค๋ช ์ ์ฌ๊ธฐ ๋งํฌ๋ฅผ ์ฐธ์กฐ)
MVP ํจํด ์์ฒด์ ๋ํ ์ค๋ช ์ ์ฌ๊ธฐ ๋ธ๋ก๊ทธ์ ์์ธํ ๋์ ์์ผ๋ ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
์ฌ๊ธฐ์ ์ง์ ํด๋ณผ ๊ฒ์ Slider๋ฅผ ํตํด ์บ๋ฆญํฐ์ ๋จธ๋ฆฌ ์์์ ๋ณ๊ฒฝํด๋ณด๋ ์๋๋ฆฌ์ค๋ฅผ MVP ํจํด์ผ๋ก ๊ตฌํ์ ํด๋ณด๋ ๊ฒ์ด๋ค.
View
โ Slider๋ฅผ ์ด๋
Presenter
โ ๋ณ๊ฒฝ๋ UI ๊ฐ์ Scriptable Object์ ์ ์ฅ
Scriptable Obejct
์ผ๋จ ์ฌ๊ธฐ๊น์ง ๊ตฌํ์ ํด๋ณด๊ณ Scriptable Obejct์ ๊ฐ์ ์ด๋ป๊ฒ ์บ๋ฆญํฐ์๊ฒ ์ ๋ฌ์ ํด์ค์ง ์ด์ด์ ์ด์ผ๊ธฐ๋ฅผ ํด๋ณด์.
- ์ฌ ๊ตฌ์ฑ
- ์์ค
HairColorPresenter.cs
using UnityEngine;
using UnityEngine.UI;
public class HairColorPresenter : MonoBehaviour
{
// View
[SerializeField]
private Slider RedColor_Slider;
[SerializeField]
private Slider GreenColor_Slider;
[SerializeField]
private Slider BlueColor_Slider;
// Model
[SerializeField]
private HairColorModel HairColorModel;
private void Awake()
{
RedColor_Slider.onValueChanged.AddListener(v => HairColorModel.RedValue = v);
GreenColor_Slider.onValueChanged.AddListener(v => HairColorModel.GreenValue = v);
BlueColor_Slider.onValueChanged.AddListener(v => HairColorModel.BlueValue = v);
}
}HairColorModel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "HairColorModel", menuName = "Hair")]
public class HairColorModel : ScriptableObject
{
public float RedValue;
public float GreenValue;
public float BlueValue;
}- Slider์ ๋ณ๊ฒฝ๋ ๊ฐ์ด ๋ฐ๋ก Sciptable Object์ ์ ์ฅ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
- (์ค์)Play๋ฅผ ์ข
๋ฃํด๋
Sciptable Object๊ฐ์ด ๊ทธ๋๋ก ์๋ ๊ฒ์ ์ ์ ์๋ค.
์ด์ ์ด๋ป๊ฒ ํ๋ฉด Model ๊ฐ์ด ๋ณ๊ฒฝ ๋์์ ๋ ๋ณ๊ฒฝ๋ ๊ฐ์ GameObject์ ์๋ ค์ค ์ ์์๊น?
์ผ๋จ UI๋ฅผ ์์ ํ์ ๋ Model ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ฒ๊น์ง๋ ๊ตฌํ์ด ๋์๋ค.
์ด์ ๋จ์ ๊ฒ์ ๋ณ๊ฒฝ๋ Model์ ๋ฐ์ดํฐ๋ฅผ GameObject์๋ ๋ฐ์์ ์์ผ์ฃผ๋ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ํด ๋ค์ํ ๋ฐฉ์์ด ์๊ฒ ์ง๋ง ๋๊ฐ์ง ๋ฐฉ์์ ํ์ฉํด์ ๊ตฌํ์ ํด๋ณด๋ ค๊ณ ํ๋ค.
- Addressable System
- ์ด๋ฒคํธ ๊ตฌ๋
Addressable์ ์์ฆ ์ ๋ํฐ์์ ๋ฐ๊ณ ์๋ Asset ๊ด๋ฆฌ ์์คํ ์ธ๋ฐ ์์ฒญ ๊น๊ฒ ๋ค์ด๊ฐ๊ธฐ ๋ณด๋ค Asset์ด ์๋ ๊ฒฝ๋ก ๊ฐ์ ํตํด ์์ ์ ์ฝ๊ฒ ๋ถ๋ฌ์ค๋ ๋ก์ง๋ง ์ฌ์ฉํด๋ณด๋ ค๊ณ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฒคํธ ๊ตฌ๋ ๋ฐฉ์์ ์์ค๋ฅผ ๋ณด๋ฉด ์ดํด๊ฐ ๋ ๊ฒ์ด๋ค.
Addressable์ ๋ํด์๋ ์ฌ๊ธฐ ๋งํฌ๋ฅผ ํตํด ์ฐธ๊ณ ๋ฅผ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
- ์ฌ ์ ํ
- Addressables ์ค์
- Model ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
public class Hair : MonoBehaviour
{
[SerializeField]
private Image Image;
private HairColorModel hairColor { get; set; }
private void Awake()
{
Addressables.LoadAssetAsync<HairColorModel>("HairModel").Completed += ao =>
{
if (ao.IsDone)
{
hairColor = ao.Result;
}
};
}
}- HairColorModel์์ ์ด๋ฒคํธ ์์ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
[CreateAssetMenu(fileName = "HairColorModel", menuName = "Hair")]
public class HairColorModel : ScriptableObject
{
public float RedValue;
public float GreenValue;
public float BlueValue;
// ๊ฐ Color ๊ฐ์ด ๋ณ๊ฒฝ ๋์์ ๋ ์คํ๋ ์ด๋ฒคํธ ์ถ๊ฐ
public UnityAction<float> OnRedValueChanged;
public UnityAction<float> OnGreenValueChanged;
public UnityAction<float> OnBlueValueChanged;
}- Presenter์์ Slider์ Model์ ์ด๋ฒคํธ๋ฅผ ์ฐ๊ฒฐ
using UnityEngine;
using UnityEngine.UI;
public class HairColorPresenter : MonoBehaviour
{
// View
[SerializeField]
private Slider RedColor_Slider;
[SerializeField]
private Slider GreenColor_Slider;
[SerializeField]
private Slider BlueColor_Slider;
// Model
[SerializeField]
private HairColorModel HairColorModel;
private void Awake()
{
// UI๊ฐ ๋ณ๊ฒฝ ๋์์ ๋
// Model์ ๊ฐ์ ์ ์ฅํ๊ณ ํด๋น ์ด๋ฒคํธ๋ฅผ ์คํ
RedColor_Slider.onValueChanged.AddListener(v =>
{
HairColorModel.RedValue = v;
HairColorModel.OnRedValueChanged?.Invoke(v);
});
GreenColor_Slider.onValueChanged.AddListener(v =>
{
HairColorModel.GreenValue = v;
HairColorModel.OnGreenValueChanged?.Invoke(v);
});
BlueColor_Slider.onValueChanged.AddListener(v =>
{
HairColorModel.BlueValue = v;
HairColorModel.OnBlueValueChanged?.Invoke(v);
});
}
}- Hair์์ Model์ ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
public class Hair : MonoBehaviour
{
[SerializeField]
private Image Image;
private HairColorModel hairColor { get; set; }
private Color color = new Color(r: 0, g: 0, b: 0, a: 1);
private void Awake()
{
Addressables.LoadAssetAsync<HairColorModel>("HairModel").Completed += ao =>
{
if (ao.IsDone)
{
hairColor = ao.Result;
// ๋ชจ๋ธ์ด ๋ค๊ณ ์๋ ์ด๋ฒคํธ ๊ตฌ๋
hairColor.OnRedValueChanged += ChangeRedColor;
hairColor.OnGreenValueChanged += ChangeGreenColor;
hairColor.OnBlueValueChanged += ChangeBlueColor;
}
};
}
private void ChangeRedColor(float value)
{
color.r = value;
Image.color = color;
}
private void ChangeGreenColor(float value)
{
color.g = value;
Image.color = color;
}
private void ChangeBlueColor(float value)
{
color.b = value;
Image.color = color;
}
}๊ตณ์ด ์ด๋ ๊ฒ ์ด๋ ต๊ฒ ๊ตฌํ์ ํด์ผํ๋ ์ถ์ ์๊ตฌ์ฌ์ด ์๊ธธ ์๋ ์์ง๋ง,
์์ ์ด์ผ๊ธฐ ํ ๊ฒ์ฒ๋ผ ๋ฐ์ดํฐ์ ๋ก์ง์ ๊ตฌ๋ถ์ ์ง๊ธฐ ์ํด์ ์์ ๊ฐ์ ๋ฐฉ์์ ์ฌ์ฉํด๋ณด์๋ค.
์ฆ, ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ ๋ก์ง์ ์ฒ๋ฆฌํ๋ Hair class์์๋ UI๋ฅผ ์ ํ ๋ชฐ๋ผ๋ ๋๊ณ
๋ฐ์ดํฐ๋ฅผ ํ์ฉํ ๋ก์ง์ ์ด๋ป๊ฒ ์งค ๊ฒ์ธ์ง์๋ง ์ง์ค์ ํ๋ฉด ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ฌ๊ธฐ์ ์๋ ๋ถ๋ถ์ ๋ ๋ณด์ํ๋ฉด ์กฐ๊ธ ๋ ์ฝ๋๊ฐ ๊น๋ํด ์ง ๊ฒ ๊ฐ๋ค.
- HairColorModel์์ ์์ฑ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ๋ฐ๋ก ์ด๋ฒคํธ๊ฐ ์คํ ์ํฌ ์ ์๋ ๋ก์ง ์ถ๊ฐ
- RGB ๊ฐ ๋ณ๊ฒฝ์์ ์ค๋ณต๋๋ ์ฝ๋ ์ ๊ฑฐ โ RGB ๊ฐ์ ๋ฐ๋ก ๋ฐ๋ก ๊ตฌ๋ถ ์ง๋ ๊ฒ์ด ์๋๋ผ ํ๋์ ํจ์๋ก ๋นผ๋๋ ๋ฐฉ์





