안녕하세요, 게임을 사랑하고 개발을 사랑하는 게임 프로그래머 Developer G입니다.
저는 어떻게하면 깔끔하고 체계적인 코드를 작성할 수 있을지 항상 고민하는데요,
제 고민의 결과물들을 여러분들에게 아낌없이 가르쳐드리겠습니다!
강의
로드맵
전체 1수강평
- [유니티 레벨 업!] 모듈식으로 개발하는 아이템 시스템
- [유니티 레벨 업!] 모듈식으로 개발하는 퀘스트&업적 시스템
- [유니티 레벨 업!] 모듈식으로 개발하는 퀘스트&업적 시스템
- [유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
게시글
질문&답변
안녕하세요 강좌 진행 순서에 대해 문의드립니다.
수강해주셔서 감사합니다.난이도는 퀘스트 -> 아이템 -> 스킬 순으로 어려워집니다.퀘스트 (기초)아이템 (기본)스킬 (심화)정도라고 생각하시면 됩니다.감사랍니다.
- 0
- 1
- 10
질문&답변
TargetSearcher에 대해서 질문이 있습니다
수강해주셔서 감사합니다.1. 강의 내용에 얽매이실 필요 없습니다. 기준점이 여러 개가 필요하다면 TargetSelectionResult를 수정하셔서 각 변수를 배열 형태로 만드시면 됩니다. Simple is best, 대게 가장 단순한 방식이 가장 좋은 방식입니다.2. 저 같은 경우 기능 구현을 하다 막히면 제가 만드려고하는 하는 기능들이 있는 게임들을 살펴봅니다. 너무 특이해서 딱 맞는 예제가 없을 경우에는 비슷한 예제라도 찾아봅니다. 예를 들어, '어떤' 스킬을 만들고 싶다면 롤 같이 그 스킬이 있는 게임을 해보면서 그 스킬이 어떤 식으로 동작하는지 반복해서 보구요, 그러면서 머리 속으로 각 동작을 어떻게 구현할지 계속 설계를 합니다. "리신 Q는 투사체네", Q를 맞은 적은 머리에 뭐가 뜨네? 이건 디버프 효과로 처리해야겠다", "Q를 한번 더 누르면 머리에 뭐가 뜬 적한테 날아가네? 음...이건 스킬의 발동 조건으로 '디버프가 있을 때'를 넣어야겠다." 이런 식입니다. 아무래도 막연한 생각하는 것보다는 눈에 뭐가 보이면 훨씬 생각하기 쉬우니까요. 그래서 많은 게임을 해보면서 레퍼런스 쌓는게 중요하구요, 게임 프로그래머들의 흔한 직업병으로 게임을 하다 말고 "이거 어떻게 구현했을까?"하고 기능을 바라보며 머리 속으로 설계를 해보는게 있습니다.그 외에 요즘은 회사들에서 AI를 페어 프로그래머로 두는걸 권장하기 때문에 저도 AI와 대화를 많이 나누는 편입니다. AI가 제대로 답변하든 잘못 답변하든 대화를 하는 과정에서 생각이 정리되거든요.
- 0
- 1
- 16
질문&답변
카테고리 클래스를 어떻게 해야할지 모르겠어요ㅜㅜ
수강해주셔서 감사합니다.답변이 늦어 죄송합니다.1. Quest와 Task가 IdentifiedObject를 상속 받는 형태로 구현하시면 됩니다. 그 다음은 Quest와 Task를 ItemSystemWindow에 등록해주면 됩니다.2. Equals와 GetHashCode 함수를 구현한 이유는 operator ==을 구현하기 위한 필수 구현이기 때문입니다.감사합니다.
- 0
- 2
- 29
질문&답변
NPOI 오류가 뜨는데
수강해주셔서 감사합니다, 그리고 답변이 늦어 죄송합니다.강의에서 설명드렸다싶이 NPOI DLL은 Editor에서만 사용가능하게 설정해놔서 Build시에 NPOI를 참조하지 않기에 TestCode들이 참조가 없어 Error를 뱉는 것입니다.ExcelConvertTest.cs와 NPOIExample.cs의 내용을 #if UNITY_EDITOR 전처리문으로 감싸주시거나 삭제하시면 정상적으로 빌드가 되실겁니다.감사합니다.
- 0
- 2
- 33
질문&답변
돌진해서 몸박을하면 피격자를 날리면서 데미지를 입히는 스킬은 이 시스템에서 어떻게 만들 수 있을까요??
수강해주셔서 감사합니다.돌진 부분 전체를 SkillAction으로 구현해주시면 됩니다.DashAttackAction.csStart => 돌진 시작, owner.Movement.StartDash();Apply => Target들에게 Skill을 적용함, target.SkillSystem.Apply(skill)Release => 돌진 종료, owner.Movement.StopDash();ApplyCycle과 ApplyCount를 0(무한)으로 주고, SelectionAction을 Entity 자신, SearchAction을 Entity 주변으로 하면 Entity가 돌진하며 자기 주변 적을 때리겠죠? 때린 적을 또 때리지 않기 위해서는 한번 때린 적은 Caching 해뒀다가 같은 적이 Target으로 잡히면 무시해야할 겁니다.owner.StartDash식으로 Entity에 돌진을 구현을 하지 않고 DashAttackAction.cs 자체에 Coroutine이나 Task로 Action 자체에 Entity를 돌진 구현을 하시는 방법도 있습니다.감사합니다.
- 0
- 2
- 69
질문&답변
아이템 시스템 강의
안녕하세요.회사 게임 출시가 늦어지면서 강의 출시 시기도 같이 미뤄졌습니다. 현재 마무리 단계에 있으며 다음 달 초에는 확실히 강의 출시가 될 것 같습니다. 기다려주시는데 늦어진 점 정말 죄송합니다.
- 0
- 2
- 74
질문&답변
스킬 관련 질문입니다
수강해주셔서 감사합니다.스킬을 강화하는 방법은 두 가지 있습니다.1. 강화 버전의 스킬을 미리 만들어두고 필요할 때 현재 스킬을 강화된 스킬로 교체화염구 -> 강화·화염구얘기하신 예로는 특정 스킬을 획득하면 화염구를 강화·화염구로 교체하고, 특정 스킬이 사라지면 다시 기본 화염구로 교체해주면 될겁니다.2. Skill의 Effect를 실시간 업데이트Skill에 Effect를 추가할 수 있게 수정해주시고, Effect의 효과도 수정 가능하게 만들어주시면 됩니다.// Skill에 새로운 효과 추가skill.AddEfffect(newEffect);// Skill에 있는 화상 효과를 가져옴var targetEffect = skill.Effects.First(x => x.CodeName == "BURN");// 가져온 화상 효과에서 Action을 가져와 적용 Stack을 2로 수정(targetEffect.Action as BurnAction).ApplyStack = 2;감사합니다.
- 0
- 2
- 82
질문&답변
Quest System의 확장성에 대한 질문
수강해주셔서 감사합니다.-제한 시간 안에 클리어 했는가이건 아래와 같이 무언가를 클리어시 그 정보를 Target으로 만들어 Report를 보내면 됩니다.// ClearInfostruct ClearInfo { int stageLevel, flaot clearTime }// QuesrSystemQuestSystem.Instance.ReceiveReport(CATEGORY_STAGE_CLEAR, clearInfo, 1);// TaskTarget.IsEqual// 스테이지 클리어 정보가 조건에 맞다면 true를 return.if (target is ClearInfo clearInfo)return clearInfo.level == targetStageLevel && clearInfo.clearTime elsereturn false; -특정 스킬을 사용하지 않았는가, 특정 아이템을 보유하고 있는 상태로 완료했는가Task쪽에 Task 동작마다 호출되는 모듈을 추가하면 됩니다.// Task의 각 단계에서 실행될 Module// TaskCustomAction.cspublic virtual OnStart(Task task) {} // Task의 Start 함수에서 실행public virtual OnEnd(Task task) {} // Task의 End 함수에서 실행// Taskvoid Start(){...customAction.OnStart(this);}void End(){...customAction.OnEnd(this);}OnStart에서 캐릭터가 어떤 스킬을 사용하는지 이벤트로 감시하는 모듈을 만들고,특정 스킬을 사용하면 Task가 실패되게 만들면 되겠죠.// SkillObservingAction : TaskCustomActionpublic override OnStart(Task task){// 특정 스킬을 사용하면 Task 실패task.Owner.Owner.onSkillUsed += OnSkillUsed;}public overrride OnEnd(Task task){// Task가 끝났으니 추적 종료task.Owner.Owner.onSkillUsed -= OnSkillUsed;}보시는 것처럼 Task의 조건을 만드는건 여러 방법이 있기 때문에'QuestReport로 보낼 Target Data를 다듬을 것인가? 아니면 Task의 Module을 만들 것인가?'Quest를 만들 때 판단이 필요합니다.아울러 Task의 Module 같은 경우는 만들어둔 Module을 차곡차곡 잘 쌓아두면 이후에 다른 게임을 개발할 때도 사용할 수 있으니 가능하면 내용을 범용적으로 사용할 수 있도록 만드시는게 좋습니다.Module에 대한 Reference를 작성해둔다면, 기획자나 디자이너가 참고해서 만들어둔 Module들을 사용해 직접 Quest를 제작하고 테스트 해볼 수도 있을 겁니다.감사합니다.
- 0
- 1
- 72
질문&답변
통일된 Stat을 사용하지 않고 모듈화 방식으로 Stats를 만드신 이유가 궁금합니다.
수강해주셔서 감사합니다.방식에 관해서는 모든 Entity가 통일된 Stat을 가져도 상관은 없습니다.다만, 개발을 하다보면 특정 Entity만 가지고 있는 Stat이나 Player만 가지고 있는 Stat을 만들 때도 존재합니다. Player만 사용할 Stat을 수 십, 수 백 종의 모든 Monster가 가지고 있는 것도 낭비이기 때문에 공용으로 모두 같은 Stat을 가지게 할지, Stat을 따로 선별해서 넣어줄지 선택지를 만들어준 것이라고 생각하시면 됩니다. Stat이라는게 유저의 입장에서 힘, 지능, 민첩 이런 것만 있을 것이라 생각하기 쉽지만, 실제 개발에서는 현금 결제나 광고, 계정에 대한 정보, 게임 내적 Data 등 다양한 것들이 Player의 눈에 보이지 않는 Stat으로 만들어지기도 합니다.저 같은 경우 공용으로 사용할 Stat들을 System에서 설정해두고, Entity가 만들어질 때 자동으로 Entity의 Stats에 설정되게 만들어놓았구요, 거기에 따로 Stat이 필요한 Entity의 경우 직접 필요한 Stat을 추가해주는 방식을 사용합니다.감사합니다.
- 0
- 1
- 98
질문&답변
Effect에 기능 확장에 대해서 질문이 있습니다.
수강해주셔서 감사합니다.Effect를 다양한 상황에 적용시키기 위해서는 EffectAction의 Callback 함수를 연결할 수 있는 다양한 event들을 촘촘히 만들고, 때에 따라서는 특정 Damage 유형을 Stat으로 만드는 등 적절한 처리 방법을 고민해야합니다.예를 들어, 죽으면 즉시 부활하는 효과라고 가정하면 아래와 같이 EffectAction을 만들 수 있을겁니다. EffectAction.cs public override Start(Effect effect) { effect.Owner.Owner.onTakeDamage += OnTakeDamage; } public override bool Apply(Effect effect) { // event를 통해 효과를 적용했다면, 상태를 리셋하고 true를 return if (isApplied) { isApplied = false; return true; } return isApplied; } public override Release(Effect effect) { effect.Owner.Owner.onTakeDamage -= OnTakeDamage; } public void OnTakeDamage(Entity target, float damage); { // 대상이 이번에 Damage를 받고 죽었다면 HP가 1인 상태로 부활시킴 if (target.IsDead) { target.HPStat.Value = 1f; isApplied = true; } }Effect가 실행될 때 Owner Entity의 onTakeDamage Event에 Callback 함수를 연결해두고, Entity가 죽으면 효과가 발동하는 형식입니다.특정 종족에게 가하는 피해 증가는 종족 피해 배율을 Stat으로 만들 수 있을겁니다.예를 들어, Elf 종족에 대한 Damage 증가를 담당하는 INCREASED_DAMAGE_TO_ELF Stat을 만들고, Effect는 Stat의 수치를 증가시키면 됩니다. EffectAction.cs public override Start(Effect effect) { } public override bool Apply(Effect effect) { effect.Owner.Owner.Stats.SetBonusValue("STAT_INCREASED_DAMAGE_TO_ELF", this, 0.2f); } public override Release(Effect effect) { effect.Owner.Owner.Stats.RemoveBonusValue("STAT_INCREASED_DAMAGE_TO_ELF", this); }// Entity.cs public void GiveDamage(Entity target) { float damage = Stats.GetValue("DAMAGE"); if (target.Race == Race.Elf) damage *= Stats.GetValue(STAT_INCREASED_DAMAGE_TO_ELF); target.TakeDamage(damage) }위는 예시라서 if문으로 하드 코딩했지만, 제대로 만들 때는 Entity가 제대로된 종족 값을 가지도록 확장을 해야겠죠.Damage 감소 같은건 Damage를 계산할 때 사용할 Action Callback들을 받아서Invocation을 통해서 연결된 Action들을 순회하면서 최종 값을 구할 수 있습니다 EffectAction.cs public override Start(Effect effect) { effect.Owner.Owner.CalcDamage += CalcDamage; } public override bool Apply(Effect effect) { // event를 통해 효과를 적용했다면, 상태를 리셋하고 true를 return if (isApplied) { isApplied = false; return true; } return isApplied; } public override Release(Effect effect) { effect.Owner.Owner.CalcDamage -= CalcDamage; } private float CalcDamage(Entity instigator, DamageType damageType, float damage) { // 공격한 적의 Damage Type이 화속성이면 Damage를 무묘화시킴. if (damage > 0f && damageType == DamageType.Fire) { isApplied = true; return 0f; } // 적의 Damage Type이 화속성이 아니라면 Effect가 작동하지않음 else return damage; }// TakeDamage 함수 안 // 연결된 Callback 함수들을 순회하며 최종 Damage 계산을 함. // 위 Effect가 발동할 경우 최종 Damage는 0이 됨. foreach (var calc in CalcDamage.GetInvocationList().Cast()) damage = calc.Invoke(this, damageType, damage);보시듯 복잡한 체계를 가진 전투 시스템은 복합적인 방식을 사용하여 구현하여야하기 때문에 모든 프로그래밍적 역량을 끌어올릴 필요가 있습니다. 그래서 RPG 게임 개발이 어렵다고 많이들 얘기하는 것입니다.감사합니다.
- 0
- 2
- 104





![Thumbnail image of the [유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템](https://cdn.inflearn.com/public/courses/333173/cover/1ebf894e-36b3-4254-b9f7-9c1e0f43e02b/333173.png?w=148)
![Thumbnail image of the [유니티 레벨 업!] 모듈식으로 개발하는 퀘스트&업적 시스템](https://cdn.inflearn.com/public/courses/327970/cover/7e68ea5f-28f1-40ee-af0b-a223bd98d182/327970-eng.png?w=148)