์๋ฌธ:RPG Programming Pitfalls #1: Stat System
๋กคํ๋ ์ ๊ฒ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ณต์กํ ์์คํ
์ด๋ฉฐ, ๊ฒ์ ํ๋ก๊ทธ๋๋จธ๊ฐ ๋๊ธฐ ์ํ ๊ธธ์ ์ด์ ๋ง ์์ํ ์ฌ๋์๊ฒ ์ผ๋ฐ์ ์ผ๋ก ์ถ์ฒํ ๋งํ ์ฅ๋ฅด๋ ์๋๋๋ค. ์ฒ์๋ถํฐ ํ๋ก์ ํธ๋ฅผ ๋ฐฉํดํ๋ ๋ถ๊ฑด์ ํ ์ํคํ
์ฒ๋ฅผ ์ ํํจ์ผ๋ก์จ ์ค์ค๋ก์ ๋ฐ๋ฑ์ ์ฐ์ ์ ์๋ ๋ฐฉ๋ฒ์ ์ผ๋ง๋ ์ง ์์ต๋๋ค. ์ํ๊น๊ฒ๋ ๋ง์ ์ธ๊ธฐ ํํ ๋ฆฌ์ผ๋ ์ด๋ฌํ ํจ์ ์ ํ๋ ์ด์ ๋น ์ง๊ฒ ๋ฉ๋๋ค.
RPG ํ๋ก๊ทธ๋๋ฐ ํจ์ ๋ฌธ์ ์๋ฆฌ์ฆ๋ ๋กคํ๋ ์ ๊ฒ์ ๊ฐ๋ฐ(๋ฐ ๋ค๋ฅธ ์ฅ๋ฅด์์๋)์์ ํํ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ์์ ์ ์ด๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋
ผ์ํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค. ํต์ฌ์ ์ข์ ์์ด๋์ด์ฒ๋ผ ๋ณด์๋ ๊ณผ๊ฑฐ์ ์์ ์ ์ง์ฅ์ ๊น์ ๊ตฌ๋ฉ์ด๋ก ์ ์ฃผํ๊ณ ์ถ์ง ์์ ํด๊ฒฐ์ฑ
์ ์ ๊ณตํ๋ ๊ฒ์ด๋ฉฐ, ์ด๋ ์ ๊ฐ 6๊ฐ์ ๋ค๋ฅธ RPG๋ฅผ ์์
ํ๋ฉด์ ๊ฐ์ฅ ์ต์ ์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ๋จํ ๊ฒ์
๋๋ค.
์ด ๊ธ์ ์ฝ๋๋ C#์ผ๋ก ์์ฑํ๊ณ ์์ง๋ณ ๋ด์ฉ์ Unity๋ฅผ ์ฌ์ฉํ์ง๋ง ์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ์์ง์ ์ ์ฉํ ์ ์์ต๋๋ค.
์ด ์๋ฆฌ์ฆ์ ์ฒซ ๋ฒ์งธ ๊ธ์ RPG์ ํต์ฌ์ ์ด๋ฃจ๋ ํต๊ณ์ ๋ํด ๋ค๋ฃน๋๋ค. ์ฌ์ค ๋๋ถ๋ถ์ ๊ฒ์์์ ๋ค์ํ ๊ฐ์ ์ถ์ ํ๊ธฐ ์ํด ๋ช ๊ฐ์ง ์์คํ
์ ์ฌ์ฉํ์ง๋ง, RPG์์๋ ๋ฉ์ปค๋์ฆ์ ํต์ฌ์ด์ ๋งค์ฐ ๋์ ์ ๋๋ ์์์
๋๋ค.
์ด ๊ธ์์๋ ๋ค์ ์ฃผ์ ์ ๋ํด ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1.์คํฏ์ด๋ ๋ฌด์์ด๋ฉฐ ์ด๋ป๊ฒ ๋ณ์๋ก ๊ตฌํ๋๋๊ฐ?
2.์ ์ ๊ทผ ๋ฐฉ์์ ๋ฌธ์ ์
3.๋์
๋๋ฆฌ(Dictonary)๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๋ค ์ ์ฐํ ๊ตฌํ ๋ง๋ค๊ธฐ
4.์ถ๊ฐ์ ์ธ ํธ์์ฑ ์ถ๊ฐํ๊ธฐ
5.Unity ์์ง์์ ์๋ฃจ์
์ฌ์ฉ
์ฐ๋ฆฌ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ๋ณต์ ํ๊ณ ์ ํ๋ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
(์ญ์ฃผ:๋์ ์ค ๋๋๊ณค ์บ๋ฆญํฐ ์ํธ ์ํธ)
์บ๋ฆญํฐ ์ํธ. (2023 ๋
6 ์ 30 ์ผ). ์ํค๋ฐฑ๊ณผ์์. https://en.wikipedia.org/wiki/Character_sheet
์ง๊ด์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์บ๋ฆญํฐ์ ๋ค์ํ ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ์๋ก ์ธ๋ถํํ๋ ๊ฒ์
๋๋ค:
1 2 3 4 5 6 | public int Strength; public int Dexterity; public int Constitution; public int HitPoints; public int ProficiencyBonus; public int Attack => Strength + ProficiencyBonus; | cs |
์ด๋ ๊ฒ ์์ฑํ๋ฉด, ํ๋์ ๋๋ถ๋ถ์ ํํ ๋ฆฌ์ผ์์ ๋์ค๋๋๋ก ํ๋์์ ๋ชจ๋ ๊ฒ์ด ๊ด์ฐฎ์ ๊ฒ์ ๋๋ค.
ํ์ํ ์์ฑ๊ณผ ๋ฅ๋ ฅ์ ๊น๋ํ ๋ณ์ ํ๋์ ์ ๋ ฅํ๊ธฐ๋ง ํ๋ฉด ๋๊ณ ,
๋๋ก๋ ์์ '๊ณต๊ฒฉ(Attack)' ๊ฐ์ด ์กฐ๊ธ ๋ณต์กํ ์์ฑ๋ ์ ๋ ฅํ ์ ์์ต๋๋ค.
ํ์ง๋ง HitPoint(์ฒด๋ ฅ)์ ๊ฒฝ์ฐ ํ์ฌ์ ์ต๋์น๋ฅผ ๋ชจ๋ ์ถ์ ํด์ผ ํ๋ฏ๋ก ๋ ๊ฐ ์ด์์ ๋ณ์๊ฐ ํ์ํ๋ค๋ ์ฌ์ค์ ๊นจ๋ซ๊ฒ ๋ฉ๋๋ค.
1 2 | public int MaxHitPoints; public int CurrentHitPoints; | cs |
์ทจ์ฝ
์ฃผ๋ฌธ์ด ์ง์๋๋ ๋์ ๋์ ์บ๋ฆญํฐ์ ํ ์์ฑ์ 2๋งํผ ๋ฎ์ถฅ๋๋ค.
์ฃผ๋ฌธ์ ํ์ด๋ณด๋ฉด ๋ฏผ์ฒฉ(Dexterity)๊ณผ ๊ฐ๊ฑดํจ(Constitutin)์๋ ๋น์ทํ ์ฃผ๋ฌธ์ด ์๊ณ ๋ค๋ฅธ ์์ฑ์๋ ๋น์ทํ ์ฃผ๋ฌธ์ด ์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
์ด์ ๋ชจ๋ ์์ฑ์ ๋ํด ๋์ผํ ์์
์ ์ํํด์ผ ํฉ๋๋ค! ์๋๋ฉด ๋ ๋์ ํด๊ฒฐ์ฑ
์ด ์์๊น์?
์คํฏ ํด๋์ค
๊ฐ ์์ฑ์ ๋ํด ์ต์ ๋ ๊ฐ(์ต์๊ฐ๋ ์ถ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ ๊ทธ ์ด์)์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๋์ ์บ๋ฆญํฐ์ ์คํฏ์ ์ง์์ ์ด๊ณ ํ์ฌ ์ํ๋ฅผ ์ถ์ ํ๋ ์ปค์คํ
ํด๋์ค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | public class Stat { // Fields private string _name; private int _currentValue; private int _maxValue; private int _minvalue; // Public Getters public string Name => _name; public int CurrentValue => _currentValue; public int MaxValue => _maxValue; public int MinValue => _minvalue; // Events private event System.Action<int> _onValueChanged; public event System.Action<int> OnValueChanged { add { _onValueChanged += value; } remove { _onValueChanged -= value; } } // Constructors public Stat(string name, int value, int minValue, int maxValue) { _name = name; _minvalue = minValue; _maxValue = maxValue; // Set the value through the SetValue method so it's guaranteed to be between min, max SetValue(value); } /// <summary> /// The most commonly used constructor that defaults the value to the max value /// </summary> /// <param name="name">Name of the stat</param> /// <param name="value">Current and max value</param> public Stat(string name, int value) : this(name, value, 0, value) { } // Methods /// <summary> /// Adjust the current value, used often when you don't really need to know the stat's boundaries (e.g. taking damage) /// </summary> /// <param name="amount"></param> public void Adjust(int amount) { SetValue(_currentValue + amount); } /// <summary> /// Sets the current value and clamps it between min, max /// </summary> /// <param name="newValue">The value to set</param> public void SetValue(int newValue) { // If nothing has changed, don't do anything if (newValue == _currentValue) return; _currentValue = Mathf.Clamp(newValue, _minvalue, _maxValue); _onValueChanged?.Invoke(_currentValue); } /// <summary> /// Resets the value to its maximum. Often used in effects like healing or resetting a character to their default state. /// </summary> public void ResetToMax() { SetValue(_maxValue); } /// <summary> /// Resets the value to the minimum value (usually 0). Useful for any stat that is gained temporarily. /// </summary> public void ResetToMin() { SetValue(_minvalue); } } | cs |
์์์๋ ๊ฐ ์คํฏ์ ๋ํด ํ์ฌ, ์ต์, ์ต๋ ์ธ ๊ฐ์ง ๊ฐ์ ์ ์ํ์ต๋๋ค.
์คํฏ์ ํ์ฌ ๊ฐ์ ์์ ํด์ผ ํ ๋(์: ์บ๋ฆญํฐ๊ฐ ํผํด๋ฅผ ์ ์์ ๋) Adjust ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
Adjust() ๋ด๋ถ์์ ํ์ฌ ๊ฐ์ ์์ ํ ๊ฐ์ ๋ํ SetValue() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ํ์๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ต์๊ฐ๊ณผ ์ต๋๊ฐ ์ฌ์ด์ ๊ณ ์ ํฉ๋๋ค.
๋ํ SetValue() ๋ฉ์๋๋ ํ์ฌ ๊ฐ์ด ๋ณ๊ฒฝ๋์์์ ๋ชจ๋ ์ฌ๋์๊ฒ ์๋ฆฌ๊ธฐ ์ํด OnValueChanged ์ด๋ฒคํธ๋ฅผ ํธ์ถํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ฐ๋ฏธ์ง ํ๋กํฐ๋ฅผ ํ์ํ ๋ ๋งค์ฐ ํธ๋ฆฌํฉ๋๋ค.
์์ ์ฃผ๋ฌธ์ด ์ฝ๋์์ ์ด๋ป๊ฒ ๋ณด์ด๋์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
ํจ์ฌ ๋์์ก์ฃ ? ํ์ง๋ง ์ฌ์ ํ ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
๊ฐ๋ฅํ ๋ชจ๋ ์คํฏ ๊ฐ์ ์ฃผ๋ฌธ์ ์์ฉํ๋ ค๋ฉด ๊ฐ ์์ฑ์ ๋ํด ๊ฑฐ์ ๋์ผํ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
์ฃผ๋ฌธ์ด ์ง์๋๋ ๋์ ๋ค๋ฅธ ํจ๊ณผ๊ฐ ํ ์์ฑ์ ๋ณ๊ฒฝํ๋ฉด ์ฃผ๋ฌธ์ด ์ข
๋ฃ๋๋ฉด ์์ฑ์ด ์๋ ๊ฐ์ผ๋ก ๋์๊ฐ๋ฏ๋ก ๋ฌดํจํ๋ฉ๋๋ค.
์ด ๊ฐ์ ์๋์ ์ต๋ ํ์ ๊ณ ์ ๋์ด ์์ผ๋ฏ๋ก ๋์์ ํ์ ์ฆ๊ฐ์ํค๋ ์ฃผ๋ฌธ์๋ ๋ค๋ฅธ ํด๊ฒฐ์ฑ
์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด ๋ค๋ฅธ ๋ง์ ๋ฌธ์ ๋ ํด๊ฒฐ๋๋ฏ๋ก ์ง๊ธ์ ์ฒซ ๋ฒ์งธ ๋ฌธ์ ์ ์ง์คํด ๋ณด๊ฒ ์ต๋๋ค.
-
๊ธ์์ ์ ํ์ ๋์ค์ ์ถ๊ฐ ๋ฒ์ญํจ
ใณใณ
์ ๋ณด ๊ฐ์ฌํฉ๋๋ค~