Developer G
@developerg
Học viên
1,113
Đánh giá khóa học
76
Đánh giá khóa học
4.7
안녕하세요, 게임을 사랑하고 개발을 사랑하는 게임 프로그래머 Developer G입니다.
저는 어떻게하면 깔끔하고 체계적인 코드를 작성할 수 있을지 항상 고민하는데요,
제 고민의 결과물들을 여러분들에게 아낌없이 가르쳐드리겠습니다!
Khóa học
Đánh giá khóa học
- [Thăng cấp đoàn kết!] Hệ thống kỹ năng được phát triển theo mô-đun
- [Tăng cấp đoàn kết!] Hệ thống nhiệm vụ và thành tích được phát triển theo mô-đun
- [Thăng cấp đoàn kết!] Hệ thống kỹ năng được phát triển theo mô-đun
- [유니티 레벨 업!] Hệ thống vật phẩm phát triển theo mô-đun
- [Thăng cấp đoàn kết!] Hệ thống kỹ năng được phát triển theo mô-đun
Bài viết
Hỏi & Đáp
ChargingState에서 질문이 있습니다.
수강해주셔서 감사합니다. 1) 비동기 입력 처리플레이어의 조준이나 클릭 대기는 즉발적이지 않은 '비동기적인 상황'입니다. 따라서 매 프레임 타겟을 찾았는지 검사하기보다는, 타겟 서처가 선택을 마쳤을 때만 콜백으로 결과를 알려주도록 하는 이벤트 주도 방식이 훨씬 효율적입니다. 2) 깔끔한 재시도 구조OnTargetSearchCompleted 콜백 내부를 보시면, 타겟팅에 성공하지 못했거나 최소 차지 시간을 채우지 못해 스킬 사용에 실패했을 경우 다시 SelectTarget을 호출해 재시도하도록 되어 있습니다. 만약 이를 Update에서 구현했다면 여러 Flag 변수와 조건문이 뒤섞여 Update문의 코드가 매우 지저분해졌을 것입니다. 결론적으로 복잡한 상태 분기를 피하면서 함수들의 책임 분리를 지키기 위한 설계라고 이해해 주시면 되겠습니다감사합니다.
- 0
- 1
- 37
Hỏi & Đáp
Indicator와 SelectionAction 및 SearchAction 간의 관계에 대해 질문있습니다.
수강해주셔서 감사합니다.1) 제안하신 설계(Indicator가 범위 체크를 담당)가 책임 분리에 어긋나는가?네, 단일 책임 원칙 관점에서는 조금 어긋납니다. Indicator의 본질적인 책임은 View/UI입니다. 플레이어에게 범위를 보여주는 역할이죠. 여기에 물리적인 충돌 체크나 거리 계산 같은 Logic를 넣게 되면, View와 Logic이 섞이게 됩니다. 거기다 이렇게 되면 나중에 '화면에 인디케이터는 안 띄우지만, 사각형 범위로 적을 찾는 스킬' 같은 것을 만들 때 곤란해집니다. 시각적 표현이 없는 데도 Indicator 객체를 생성해야 하는 모순이 발생하기 때문입니다.2) 현재 방식말씀하신 것처럼 "현재 코드가 원형/원뿔에 제한되어 있어서 새로운 형태를 추가하려면 로직이 꼬이지 않을까?"라고 충분히 우려하실 수 있습니다. 하지만 현재 강의의 구조는 이미 형태 확장을 고려하여 설계되어 있습니다.IndicatorViewAction 클래스의 ShowIndicator(..., object range, ...) 함수를 보시면 매개변수 타입이 float가 아니라 object로 되어 있죠? 제가 이 값을 object로 선언해둔 이유가 특정 형태에 구애받지 않고 유연하게 데이터를 넘기기 위함입니다.예를 들어, 사각형(Box) 범위 스킬을 새로 추가한다고 가정해 보겠습니다.BoxSearchAction (로직): 내부에서 사각형 크기(Vector3 extents)를 가지고 Physics.OverlapBox 같은 물리 연산을 알아서 처리합니다. 그리고 Indicator를 띄울 때는 자신이 가진 Vector3 값을 Range Property의 반환값으로 넘겨줍니다. (SelectTarget class 참고)BoxIndicatorViewAction (뷰): 넘어온 object 매개변수를 다시 Vector3로 캐스팅해서 화면에 사각형을 그려주기만 하면 끝입니다. 꼭 BoxSearchAction이아니라도 Range로 Vector3를 return하는 SearchAction은 이 IndicatorView와 호환이 되는겁니다. 물론 View에 설정하는 Indicator 자체도 박스 형태를 구현할 수 있는 Indicator Prefab을 설정해야겠죠.이렇게 하면 Action은 물리 연산만, Indicator는 시각 효과만 완벽하게 분리되어 담당하게 됩니다(Action - IndicatorView - Indicator 구조). 기존 코드를 뜯어고칠 필요 없이, 새로운 Action과 View 클래스를 파생시키는 것만으로 무한히 확장할 수 있는 구조인 것이죠. 좀 더 타입 안정성을 지키고 싶다하면 object가 아니라 IndicatorData 같은 구조체나 클래스를 만들어 넣기는 것도 괜찮습니다.감사합니다.
- 0
- 2
- 55
Hỏi & Đáp
선생님 질문 있습니다!
수강해주셔서 감사합니다. 강의의 난이도는 퀘스트 시스템 강의에서는 커스텀 에디터를 직접 만들기 때문에 오딘 인스펙터가 필요하지 않습니다. 감사합니다.
- 0
- 2
- 36
Hỏi & Đáp
Effect.GetData 함수 질문있습니다.
수강해주셔서 감사합니다.GetData 함수는 전투 로직보다는 주로 UI나 툴팁에서 활용하기 위해 미리 만들어둔 유틸리티 함수입니다. 예를 들어, 스킬 창에서 "다음 레벨로 올리면 데미지가 얼마나 늘어날까?"를 미리 보여줘야 할 때, GetData(현재 레벨 + 1)을 호출해서 다음 레벨의 데이터를 빼오기 위한 용도입니다. 가져온 다음 Level Data로 UI를 구성해서 보여주는거죠.참고로 강의에서 GetData 구현은 데이터가 1레벨, 2레벨, 3레벨처럼 1씩 순차적으로 구성되어 있다는 전제하에 작성된 심플한 방식입니다. 만약 1레벨 다음 데이터가 3레벨인 것처럼 구간을 건너뛰는 방식이라면, GetData의 로직도 단순 인덱스 접근이 아니라 Effect.Level 프로퍼티에서 했던 것처럼 조건 검색을 하도록 수정해야 합니다.코드를 아주 디테일하게 분석하고 계시네요. 꼼꼼하게 코드를 뜯어보며 공부하시는 모습이 아주 좋습니다.감사합니다.
- 0
- 2
- 37
Hỏi & Đáp
CanTransitionToSelf 질문 있습니다.
수강해주셔서 감사합니다. MakeTransition에서 canTransitionToSelf를 사용자가 지정하지 못하게 내부적으로 처리해둔 이유는, 사용자가 설정해봤자 아무런 의미가 없기 때문입니다. 두 가지 경우로 나누어 생각해보면 쉽습니다. 1. 다른 상태로 전이할 때 (예: MakeTransition)이때는 현재 상태(Idle)와 전이할 상태(Walk)가 서로 다릅니다. 애초에 '자기 자신으로의 전이' 상황 자체가 아니기 때문에, 이 옵션에 true를 넣든 false를 넣든 전이 로직에 아무런 영향을 주지 않는 무의미한 값이 됩니다. 2. 같은 상태로 전이할 때 (예: MakeTransition)개발자가 명시적으로 을 작성했다는 것은 '공격 중에 특정 조건이 맞으면 다시 공격을 처음부터 실행하겠다(콤보 공격 등)'는 확고한 의도입니다. 하지만 여기서 canTransitionToSelf를 false로 설정하게 되면 절대로 전이가 안 되겠죠? 이러면 결국 '스스로에게 전이하라고 명령해놓고 스스로의 전이는 막아놓은' 논리적 모순이 발생하여 동작하지 않는 코드가 됩니다. 다시 말해, MakeTransition은 출발지와 도착지가 명확하기 때문에 옵션을 열어두는 것이 불필요합니다.MakeAnyTransition과의 차이점반면 MakeAnyTransition은 '현재 상태가 무엇이든 무조건 지정된 상태로 이동해라'라는 광역 명령입니다. 만약 캐릭터가 이미 '사망' 상태에 진입해 있는데, 매 프레임 체력이 0 이하라는 조건이 맞는다고 계속 사망 상태로 무한 루프하면 안 되겠죠?MakeAnyTransition은 이미 해당 상태에 진입해 있을 때 불필요한 재진입을 허용할지 말지 결정할 '유연성'이 반드시 필요해서 옵션을 열어둔 것입니다. canTransitionToSelf는 오직 MakeAnyTransition의 무한 루프를 막기 위한 옵션입니다.감사합니다.
- 0
- 2
- 43
Hỏi & Đáp
Stat의 MaxValue에 관하여 질문이 있습니다.
수강해주셔서 감사합니다.강의에서는 MaxValue를 최대 HP로 가정한게 맞습니다.다만, MaxHP, HP 이렇게 2개의 Stat을 만들고 HP의 MaxValue를 MaxHP Stat으로 설정할 수 있게 만드는게 확장성 좋습니다. (Stat에 MaxStat을 설정하면 MaxValue가 MaxStat의 Value 값을 반환하게 Stat 클래스 확장 필요)감사합니다.
- 0
- 1
- 35
Hỏi & Đáp
Stat vs StatScaleFloat
질문 내용을 정정해주셔서 감사합니다. 이제 정확히 어떤 부분을 고민하시는지 알겠습니다. 현재 강의에서 다룬 Stat 클래스는 BonusValue(덧셈)만 처리하도록 되어 있어서, 질문하신 것처럼 "최종 수치를 퍼센트로 뻥튀기"하는 기능은 추가적인 구현이 필요합니다. 핵심은 BonusScale(배율) 개념을 도입하는 것입니다. 기존 Stat 클래스에 BonusValue처럼 배율을 관리하는 변수(BonusScale)를 추가하고, 최종 값을 계산하는 공식을 수정해야 합니다. public class Stat : IdentifiedObject { // [추가] 배율 보너스의 총합 (예: 10% 증가면 0.1) private float bonusScale; // [추가] 배율 보너스를 저장할 딕셔너리 (키 관리용) private Dictionary bonusScalesByKey = new Dictionary(); // [중요] 최종 값 계산 공식 수정 // 기존: (기본값 + 보너스값) // 수정: (기본값 + 보너스값) * (1 + 배율보너스) public float Value { get { float totalValue = (defaultValue + bonusValue) * (1f + bonusScale); return Mathf.Clamp(totalValue, minValue, maxValue); } } // [추가] 배율을 설정하는 함수 (SetBonusValue와 비슷한 구조) public void SetBonusScale(string key, float scale) { // 기존에 등록된 키라면 먼저 뺍니다 (갱신 로직) if (bonusScalesByKey.ContainsKey(key)) bonusScale -= bonusScalesByKey[key]; bonusScalesByKey[key] = scale; bonusScale += scale; // (값이 변했으니 이벤트 호출하는 로직 등은 기존과 동일하게 처리) } } 이제 SetBonusScale이라는 무기가 생겼으니, 라바돈의 죽음모자는 이렇게 구현하면 됩니다. public void EquipRabadon(Entity player) { Stat apStat = player.Stats.GetStat("AbilityPower"); // 1. 주문력 +120 (깡수치 증가) -> 기존 기능 apStat.SetBonusValue("Rabadon_Flat", 120f); // 2. 주문력 35% 증가 (퍼센트 증가) -> 추가한 기능 // 35% 증가는 0.35를 더해주는 것과 같습니다. // 공식: (기본 + 120) * (1 + 0.35) = 1.35배 뻥튀기 apStat.SetBonusScale("Rabadon_Scale", 0.35f); } 만약 캐릭터의 기본 주문력이 100이라고 가정해 봅시다.SetBonusValue로 120이 더해집니다. -> 합계 220SetBonusScale로 0.35(35%)가 적용됩니다. -> 배율 1.35최종 계산: 220 * 1.35 = 297이렇게 BonusScale 변수를 하나 추가하고 Value 계산 식에 곱하기 연산을 추가해 주시면, 롤이나 다른 RPG 게임에 나오는 다양한 퍼센트 증가 옵션을 아주 쉽게 구현하실 수 있습니다. 해당 내용은 혹시 ItemSystem 강의를 구매하셨다면 해당 강의에 더 자세히 나와있습니다.감사합니다.
- 0
- 4
- 70
Hỏi & Đáp
Stat vs StatScaleFloat
수강해주셔서 감사합니다.정확히 질문이 무엇인지 파악하지 못하여 여러 답변을 드립니다.질문하신 "Bonus Value를 부여하고 싶을 때"는 StatScaleFloat을 건드리는 게 아니라, 원본 Stat 자체에 값을 더해주시면 됩니다. // 1. 게임 로직에서 원본 Stat에 보너스를 부여합니다. // (예: 버프를 받아서 공격력이 50 증가함) attackStat.SetBonusValue("Buff_PowerUp", 50f); // 2. StatScaleFloat을 사용하는 스킬 데미지 계산 부분 // 수강생분께서 별도로 코드를 수정하지 않아도, // scaleStat이 참조하는 attackStat의 값이 이미 50 늘어났기 때문에 // 최종 데미지는 자동으로 증가해서 계산됩니다. float finalDamage = skillDamageStatScale.Value; StatScaleFloat은 Inspector에서 미리 세팅해두는 '공식'이라면, Bonus Value는 게임 도중에 수시로 변하는 값을 처리하기 위해 존재합니다. 저 같은 경우 보통 아이템 장착이나 버프 스킬을 구현할 때 다음과 같이 코드를 작성합니다.public class EquipmentItem : MonoBehaviour { [SerializeField] private float bonusAttack = 10f; // 아이템을 장착했을 때 호출 public void Equip(Entity owner) { // 1. 플레이어의 스탯 중 '공격력'을 찾아옵니다. var attackStat = owner.GetStat("Attack"); // 2. 원본 스탯에 Bonus Value를 부여합니다. // "Sword"라는 키값을 줘서 나중에 이 값만 뺄 수 있게 합니다. if (attackStat != null) attackStat.SetBonusValue("Sword", bonusAttack); } // 아이템을 해제했을 때 호출 public void Unequip(Entity owner) { var attackStat = owner.GetStat("Attack"); // 3. 부여했던 보너스 수치를 제거합니다. if (attackStat != null) attackStat.RemoveBonusValue("Sword"); } } Scale처럼 Inspector에서 BonusValue를 주고 싶으신거라면 StatScaleFloat을 확장해서 [Calculation Mode] 같은 옵션을 추가해 사용하면 됩니다. public enum CalculationMode { Fixed, // 고정값 (Bonus Value 개념) Scaled // 스탯 비례 (기본값 + 스탯 보정) } [Serializable] public struct AdaptiveFloat { public CalculationMode mode; // 1. 기본값 (고정 데미지 or 기본 수치) // Fixed 모드일 때는 이 값 자체가 최종값이 됨 public float defaultValue; // 2. 비례할 스탯 (Scaled 모드용) public Stat scaleStat; // 3. 비례 계수 (Scaled 모드용) // 예: 0.5f면 스탯의 50%만큼 추가, 1.0f면 100% 추가 public float scaleRatio; public float Value { get { float statValue = scaleStat != null ? scaleStat.Value : 0f; // [Fixed 모드] : 계수 없이 정직하게 합산 // 공식: 기본데미지 + 힘 if (mode == CalculationMode.Fixed) return defaultValue + statValue; // [Scaled 모드] : 계수(Ratio)를 곱해서 합산 // 공식: 기본데미지 + (힘 * 0.5) return defaultValue + (statValue * scaleRatio); } } } 혹시나 질문하신게 다른 것이였다면 다시 질문해주시면 대답 드리겠습니다.감사합니다.
- 0
- 4
- 70
Hỏi & Đáp
애니매이션 버그가 있는것 같습니다.
수강해주셔서 감사합니다.해당 문제는 유니티 NavAgent를 쓰다보니 생기는 문제로 마우스 클릭을 막 하거나 Player Entity가 Enemy Entity에 부딪치고하다보면 그런 문제가 생길 수 있습니다. 강의에서 캐릭터 컨트롤러는 중요하지 않기 때문에 간단한 형태로 만들어서 그렇습니다.감사합니다.
- 0
- 2
- 60
Hỏi & Đáp
StatsOverride질문이 있습니다.
수강해주셔서 감사합니다.맞습니다. 만약 StatOverride가 없다면, 체력이 다른 캐릭터를 만들 때마다 새로운 STAT_HP_Warrior, STAT_HP_Mage 같은 Stat을 계속 만들어야 해서 관리가 힘들어지겠죠? HpStat 슬롯은 이 캐릭터가 '어떤 스탯'을 사용하는지 정의하는 용도이고, 아래 Overrides는 그 스탯의 '구체적인 수치'를 이 캐릭터에 맞게 튜닝하는 용도라고 이해하시면 됩니다. Warriror는 200, Mage는 100식으로요.감사합니다.
- 0
- 2
- 47





![Thumbnail image of the [Thăng cấp đoàn kết!] Hệ thống kỹ năng được phát triển theo mô-đun](https://cdn.inflearn.com/public/courses/333173/cover/1ebf894e-36b3-4254-b9f7-9c1e0f43e02b/333173.png?w=148)
![Thumbnail image of the [Tăng cấp đoàn kết!] Hệ thống nhiệm vụ và thành tích được phát triển theo mô-đun](https://cdn.inflearn.com/public/courses/327970/cover/7e68ea5f-28f1-40ee-af0b-a223bd98d182/327970-eng.png?w=148)