묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬 사용에 관한 질문이 있습니다.
스킬시스템의public bool Use(Skill skill){ skill = Find(skill); Debug.Assert(skill != null, $"SkillSystem::IncreaseStack({skill.CodeName}) - Skill이 System에 등록되지 않았습니다."); return skill.Use();}여기에서 스킬을 사용한다는것은 알겠는데 등록되어있는 스킬을 사용하는 방식이 어떤건지 잘 모르겠습니다.모든 참조를 이용해서 찾아도 스킬테스트에서 사용한 것 말고는 없고 이벤트를 이용한것인가 싶어서 다 찾아보아도 안보여서 질문을 드립니다.
-
해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
SendBuffer.cs 삭제 후 대체 되는 부분의 장단점?
루키스님 안녕하세요?기존 SendBuffer.cs는 메모리 누수 이슈 등으로 삭제하고새로운 기법을 알려준다고 말씀해주셨는데 그게 최종적으로 ClientSession.cs의 Send()함수가 되는게 맞을까요? (아래 코드블록)맞다면 Send()가 호출 될 때 마다 버퍼를 새로 생성하기 때문에SendBuffer.cs의 강점이었던 하나의 거대한 메모리를 사용하면서 버퍼 생성 및 Copy가 줄어드는 이점이 없어진 걸로 이해가 됐는데,기존의 SendBuffer.cs와 새로운 대체된 Send()의 장단점이 각각 궁금합니다. ClientSession.cspublic void Send(IMessage packet) { string msgName = packet.Descriptor.Name.Replace("_", string.Empty); MsgId msgId = (MsgId)Enum.Parse(typeof(MsgId), msgName); ushort size = (ushort)packet.CalculateSize(); byte[] sendBuffer = new byte[size + 4]; Array.Copy(BitConverter.GetBytes((ushort)(size + 4)), 0, sendBuffer, 0, sizeof(ushort)); Array.Copy(BitConverter.GetBytes((ushort)msgId), 0, sendBuffer, 2, sizeof(ushort)); Array.Copy(packet.ToByteArray(), 0, sendBuffer, 4, size); Send(new ArraySegment<byte>(sendBuffer)); }
-
해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ArraySegment<byte>.Offset의 정의와 사용법이 궁금합니다.
안녕하세요?AraaySegment 관련해서 코드리뷰하다 궁금한게 생겨서 질문 드립니다. ArraySegment<byte>.Offset이 잘 이해가 안가서요. 제가 알아 본게 맞다면?Offset은 항상 0이 아니고 데이터가 시작하는 위치를 가르킴그렇다면 _buffer는 항상 0부터 데이터를 사용하고 있으므로 항상 Offset은 0임그렇다면 RecvBuffer.cs의 이 코드는 이렇게 바꿔도 되지 않을까? 원래 코드public void Clean() { int dataSize = DataSize; if (dataSize == 0) { // 남은 데이터가 없으면 복사하지 않고 커서 위치만 리셋 _readPos = _writePos = 0; } else { // 남은 찌끄레기가 있으면 시작 위치로 복사 Array.Copy(_buffer.Array, _buffer.Offset + _readPos, _buffer.Array, _buffer.Offset, dataSize); _readPos = 0; _writePos = dataSize; } } 수정 후 Array.Copy(_buffer.Array, readPos, buffer.Array, 0, dataSize); _readPos = 0; _writePos = dataSize; 마찬가지로 Session.cs 에서 _buffer정보를 리턴해 주는 이 코드는 이렇게도 되지 않을까?수정 전void RegisterRecv() { if (_disconnected == 1) return; _recvBuffer.Clean(); ArraySegment<byte> segment = _recvBuffer.WriteSegment; _recvArgs.SetBuffer(segment.Array, segment.Offset, segment.Count); 수정 후_recvBuffer.Clean(); ArraySegment<byte> segment = _recvBuffer.WriteSegment; _recvArgs.SetBuffer(segment.Array, segment.Offset, segment.Count); 제가 계속 곱씹어봤는데 Offset에 대한 이해가 안되서 ㅜㅜ 답변해주시면 감사하겠습니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
코드 구현한 부분에서 Disconnect()함수가 동시 실행되는 경우가 있나요?
여러 스레드에 의해 동시에 Disconnect()가 여러번 실행되는 걸 막으려고 Interlocked를 사용하여 처리한다고 하셨는데 현재 Session#1 강의 코드까지는 위와 같은 상황이 발생할 부분이 보이지 않는다고 생각하는데 맞을까요?
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬 구현 질문입니다
현재 제가 인벤토리를 만들어 사용할 스킬을 등록하는 스킬창과 획득한 스킬을 보관하는 스킬보관창을 만들었습니다스킬창에 있는 스킬은 활성화되고 보관창에 있는것은 비활성화되게 할려는 의도입니다.액티브 스킬의 경우 키를 눌러 발동하기 때문에 문제가 없는데패시브 스킬의 경우 스킬보관창에 있어도 계속해서 발동됩니다.그래서 패시브 타입인 경우 스킬보관창에 있을 경우 비활성화되게 하기 위해skill 스크립트와 skillsystem 스크립트에 비활성화 변수를 추가하여 의도한 목적을 제작할려고 하였는데어디에서 제어해야 하는지 감이 안잡혀 이 부분에 대해 어딜 수정해야 되는지에 대한 조언을 부탁드립니다...
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
상태패턴과 브랜드 트리가 필요한 프로젝트의 경우
결국 상태 패턴을 적용해서 그걸 그대로 애니메이터의 스테이트로 연동하면서정리하셨는데 만약 상태패턴을 그대로 쓰면서 브랜트 트리를 꼭 써야하는 프로젝트면어떤식으로 정리하시는지 궁금합니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
Extension 에서 구현한 함수의 이름이 해당 클래스에 이미 구현된 함수와 이름이 겹치는 경우
안녕하세요, Extension 관련 구현에 대해 연습해보다가 궁금증이 생겨 질문드립니다. 예를들어 우리가 구현한 Extension 클래스 안에 AddUIEvent 와 같은 메소드를 추가해주면서 this GameObject go 라는 문법을 써줌으로서, 마치 GameObject 의 함수인 것처럼 쓸수 있게되었는데요,만약 Extension 클래스안에 ToString 이라는 함수를 만들어주면, 실제로는 최상위 클래스인 Object 클래스 내에 구현된 ToString 이 호출되는 것을 확인했습니다. 이럴 경우, 이름을 적절히 잘 회피해서 쓰는 방법 이외에 내가 구현한 함수를 쓰도록 하는 다른 방법이 있을까요?
-
해결됨새싹부터 시작하는 Unity 게임 개발
섹션2. 메서드와 접근자에서 잘못된 설명이 있어요.
안녕하세요. public 접근자를 붙인 변수를 전역 변수,private 접근자를 붙인 변수를 지역 변수라고 설명하셨는데 이는 잘못된 설명 같습니다. 확인 후 수정 부탁드립니다.수고하세요.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
pending과 listen의 backlog와는 어떤 관계가 있는건가요?
Session #1강의 1분대에서 backlog라고 최대 대기 수를 두었기 때문에 동시다발적으로 pending이 false가 뜨는 경우가 현실적으로 없다라고 하셨는데 잘 이해가 안됩니다... ㅠㅠ
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
object 형의 박싱 언박싱에 관련해서 궁금합니다.
안녕하세요. 강습 잘 시청하고 있는데 궁금한 부분이 생겨서요.object 형을 많이 쓰던데, 실제 게임을 이 상태로 스킬을 구현해서 출시한다고 한다면 박싱 언박싱에 관련해서 성능 이슈는 없을까요? (ex : Stat.cs Dictionary<object, Dictionary<object, float>> bonusValuesByKey .. ) IdentifiedObject.cs 에서 object Clone() => Instantiate(this); 무시할 만한 수준일지 , 코드가 더 복잡하게 구현될 요지가 있어서 강의용으로 범용적으로 작업하셨는지 해서요.아님 object 형이 아닌 좀 더 나은 방향이 있다면 의견 듣고 싶습니다. 감사합니다.
-
해결됨유니티 시스템 프로그래밍 Pt.1 - 상용 게임 구현을 위한 핵심 시스템 올인원 패키지
유저 인벤토리 Pt.2
InventoryItemDataList에 유저가 보유한 아이템 목록이 저장하고 해당 리스트 객체를 PlayerPrefs로 저장할 때 JSON을 쓰는 이유는 PlayerPrefs에서 int, float, string만 저장할 수 있기 때문에로 이해했는데 맞나요? 그리고 굳이 JSON 이여 할 이유가 있나요? 또 PlayerPrefs에 유저가 접근이 가능하다고 하는데그러면 악의적으로 변형이 가능하지 않나요?이 경우는 어떻게 대비하나요?
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Getcomponent 호출 빈도에 관하여 질문이 있습니다.
저번에 조언해주신것을 통해서 다른 에셋들과 오픈소스들을 뜯어가면서 저만의 프레임워크를 설계중입니다.그런데 다른 객체의 스텟을 가져와서 영향을 주려면 Getcomponent종류를 사용 할 수밖에 없는 것 같아 보이고 강의에서도 Getcomponent스킬의 대상을 지정할때 사용되는것을 보고 질문을 드립니다.Getcomponent가 프레임 단위로 실행되는 수준만 아니면 되는건가요?그러면 혹시 다른 게임에서의 예시로 버그, 해킹 툴의 요소로 공격속도를 비정상적으로 올라간상태로 공격시 프레임드랍이 걸리는 이유가 이때 Getcomponent같은게 실행이 많이 되어서 그런걸까요? ex)다크소울이었는지 엘든링이었는지 기억이 나질 않지만 버그로 인해 프레임단위로 공격하고 렉을 유발시켰던걸로 기억합니다.public void SearchTargets(){var result = TargetSearcher.SearchTargets(Owner, Owner.gameObject);Targets = result.targets.Select(x => x.GetComponent<Entity>()).ToArray();TargetPositions = result.positions;}
-
미해결따라하면서 배우는 고박사의 유니티 기초
유니티3d 기초 하고 있는데. 따라하기가 전혀 안됩니다.
영상에서 나오는 학습자료 넣는것은 공유된 것과 다르내요. 제가 받은것과 영상과 달라 수업자체를 따라가기 어렵습니다.뿐만 아니라, 대부분 영상들이 과정도 설명도 없이 넘어가는게 많습니다!
-
미해결[유니티 3D] 실전! 생존게임 만들기 - Advanced
currentFireRate 질문
총 구현 16:45까지 currentFireRate 설명을 들었는데 왜 0이 되어야 발사가 가능한지 이유를 잘 모르겠습니다
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
TargetSearcher없이 어떻게 해야하는지 질문이 있습니다.
콜라이더를 이용해서 하는 공격은무기 콜라이더 액션을 만든다음에public class WeaponColliderAction : SkillAction{ [SerializeField] private string weaponSocketName; public override void Apply(Skill skill) { var socket = skill.Owner.GetTransformSocket(weaponSocketName); socket.AddComponent<SkillCollider>(); } public override object Clone() { return new WeaponColliderAction() { weaponSocketName = weaponSocketName }; }}무기에 해당하는 오브젝트를 찾아서 스킬 콜라이더 스크립트를 추가하고public class SkillCollider : MonoBehaviour{ private Entity owner; private Skill skill; public void Setup(Entity owner, Skill skill) { this.owner = owner; // 현재 Skill의 Level 정보를 저장하기 위해 Clone을 보관 this.skill = skill.Clone() as Skill; } private void OnTriggerEnter(Collider other) { if (other.GetComponent<Entity>() == owner) return; var entity = other.GetComponent<Entity>(); if (entity) entity.SkillSystem.Apply(skill); Destroy(gameObject); }}해당 스킬이 적용되게 구현을 하였는데 이런식으로 구현하는지 맞는지와 TargetSearcher없이 자기 자신에게 사용하는 스킬을 Skill스크립트에 있는 public Entity Owner { get; private set; }와 public IReadOnlyList<Entity> Targets { get; private set; }을 활용하면 될것같은데 어떻게 구현하는지 모르겠어서 질문드립니다. 너무 많은 질문을 드리는것같아 죄송합니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Retrieving array size but no array was provided 오류가 발생합니다.
property.arraySize이 문제인것 같은데private void DrawSkillDatas(){// Skill의 Data가 아무것도 존재하지 않으면 1개를 자동적으로 만들어줌if (skillDatasProperty.arraySize == 0){// 배열 길이를 늘려서 새로운 Element를 생성skillDatasProperty.arraySize++;// 추가한 Data의 Level을 1로 설정skillDatasProperty.GetArrayElementAtIndex(0).FindPropertyRelative("level").intValue = 1;}if (!DrawFoldoutTitle("Data"))return;EditorGUILayout.PropertyField(isAllowLevelExceedDatasProperty);// Level 상한 제한이 없다면 MaxLevel을 그대로 그려주고,// 상한 제한이 있다면 MaxLevel을 상한으로 고정 시키는 작업을 함if (isAllowLevelExceedDatasProperty.boolValue)EditorGUILayout.PropertyField(maxLevelProperty);else{// Property를 수정하지 못하게 GUI Enable의 false로 바꿈GUI.enabled = false;var lastIndex = skillDatasProperty.arraySize - 1;// 마지막 SkillData(= 가장 높은 Level의 Data)를 가져옴var lastSkillData = skillDatasProperty.GetArrayElementAtIndex(lastIndex);// maxLevel을 마지막 Data의 Level로 고정maxLevelProperty.intValue = lastSkillData.FindPropertyRelative("level").intValue;// maxLevel Property를 그려줌EditorGUILayout.PropertyField(maxLevelProperty);GUI.enabled = true;}EditorGUILayout.PropertyField(defaultLevelProperty); for (int i = 0; i < skillDatasProperty.arraySize; i++){var property = skillDatasProperty.GetArrayElementAtIndex(i);var isUseCastProperty = property.FindPropertyRelative("isUseCast");var isUseConcentrateProperty = property.FindPropertyRelative("isUseConcentration");var chargeDurationProperty = property.FindPropertyRelative("chargeDuration");var chargeTimeProperty = property.FindPropertyRelative("chargeTime");var needChargeTimeToUseProperty = property.FindPropertyRelative("needLeastChargeTime");var perfectDamageChargeTimeProperty = property.FindPropertyRelative("perfectDamageChargeTime");var perfectDamageChargeTimeDetectionProperty = property.FindPropertyRelative("perfectDamageTimeDetection");EditorGUILayout.BeginVertical("HelpBox");{// Data의 Level과 Data 삭제를 위한 X Button을 그려주는 Foldout Title을 그려줌// 단, 첫번째 Data(= index 0) 지우면 안되기 때문에 X Button을 그려주지 않음// X Button을 눌러서 Data가 지워지면 true를 return함if (DrawRemovableLevelFoldout(skillDatasProperty, property, i, i != 0)){// Data가 삭제되었으며 더 이상 GUI를 그리지 않고 바로 빠져나감// 다음 Frame에 처음부터 다시 그리기 위함EditorGUILayout.EndVertical();break;}EditorGUI.indentLevel += 1;if (property.isExpanded){// SkillData Property 내부로 들어감 -> Property == level field;property.NextVisible(true);DrawAutoSortLevelProperty(skillDatasProperty, property, i, i != 0);// Level Upfor (int j = 0; j < 2; j++){property.NextVisible(false);EditorGUILayout.PropertyField(property);}// PrecedingAction// Toggle Type일 때는 PrecedingAction을 사용하지 않을 것이므로,// Instant Type일 때만 PrecedingAction 변수를 보여줌property.NextVisible(false);if (useTypeProperty.enumValueIndex == (int)SkillUseType.Instant)EditorGUILayout.PropertyField(property);// Action And Settingfor (int j = 0; j < 8; j++){// 다음 변수의 Property로 이동하면서 그려줌property.NextVisible(false);EditorGUILayout.PropertyField(property);}// Castproperty.NextVisible(false);if (IsDrawPropertyAll && !isUseConcentrateProperty.boolValue)EditorGUILayout.PropertyField(property);elseproperty.boolValue = false;property.NextVisible(false);if (isUseCastProperty.boolValue)EditorGUILayout.PropertyField(property);// Chargeproperty.NextVisible(false);if (IsDrawPropertyAll && !isUseCastProperty.boolValue)EditorGUILayout.PropertyField(property);for (int j = 0; j < 5; j++){property.NextVisible(false);if (isUseConcentrateProperty.boolValue)EditorGUILayout.PropertyField(property);}// 최대 chargeTime 값을 chargeDuration 값으로 제한chargeTimeProperty.floatValue = Mathf.Min(chargeTimeProperty.floatValue, chargeDurationProperty.floatValue);// 최대 needChargeTime 값을 chargeTime 값으로 제한needChargeTimeToUseProperty.floatValue = Mathf.Min(chargeTimeProperty.floatValue, needChargeTimeToUseProperty.floatValue);perfectDamageChargeTimeProperty.floatValue = Mathf.Clamp(perfectDamageChargeTimeProperty.floatValue,needChargeTimeToUseProperty.floatValue,chargeTimeProperty.floatValue);// Effectproperty.NextVisible(false);EditorGUILayout.PropertyField(property); //// EffectSelector의 level 변수를 effect의 최대 level 제한함for (int j = 0; j < property.arraySize; j++){var effectSelectorProperty = property.GetArrayElementAtIndex(j);// Selector의 level Property를 가져옴var levelProperty = effectSelectorProperty.FindPropertyRelative("level");// Selector가 가진 effect를 가져옴var effect = effectSelectorProperty.FindPropertyRelative("effect").objectReferenceValue as Effect;var maxLevel = effect != null ? effect.MaxLevel : 0;var minLevel = maxLevel == 0 ? 0 : 1;levelProperty.intValue = Mathf.Clamp(levelProperty.intValue, minLevel, maxLevel);}}파란색인 부분에서 계속 걸리는데 무슨 문제인지 모르겠습니다. 파란색 뒷부분은 너무 길어져서 잘랐습니다.skillDatasProperty를 가져오는거라 Skill의 skillDatas가[SerializeField]private SkillData[] skillDatas;배열인것도 확인을 하였지만if (property.isArray){int size = property.arraySize;Debug.Log("사이즈 :" + size);}else{Debug.LogError("이 속성은 배열 또는 리스트가 아닙니다.");}이걸로 확인하니 배열이 아니라고 오는데 어떻게 배열이 아니게 된건지 모르겠습니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
전투시스템과 결합하려고 합니다.
현재 강의에서는 탑뷰 형식의 AOS와 적합한 스킬 사용 방식이기에 제가 개발하려는 전투시스템에 맞춰서 공격 판정을 콜라이더를 주로 사용하려고 합니다.공격을 실행하면 애니메이션 시작과 동시에 스킬이 발동되게 하고 애니메이션 이벤트를 활용해서 특정 구간에 콜라이더를 활성화 해준 다음 비 활성화해주고 애니메이션이 끝나면 스킬이 종료되는 방식으로 공격을 구현하려고 하는데 많이 비효율적일까요. 학습한 내용을 이해한거로는 투사체 스킬은 Targetsearcher은 연관이 없고 인디케이터가 공격할 좌표만 정해주고 캐릭터를 해당 좌표를 향해 회전해주고 발사하는 것이기에 Targetsearcher와 인디케이터를 전부 없애버리고 투사체 스킬의 투사체 생성 대신에 소켓을 이용해서 공격판정 무기를 찾은 다음 해당 스킬 스크립트를 생성시켜준 다음에 애니메이션 이벤트로 콜라이더를 활성화 비 활성화로 공격 판정을 구현하고 공격 애니메이션이 끝나면 해당 스크립트를 삭제시켜주는 방식으로 구현을 생각중입니다.혼자서 독학 중이라 다른 사람들의 개발 방식을 볼 때마다 제 방식에 대한 확신을 가지지 못하는 것 같습니다.
-
미해결[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + T2)
다운 받은 맵 프리팹을 오픈해보니 핑크색으로 보이네요
구글링을 해보니 shader 문제라고 하는데 세팅하는 방법이 있을까요?2022.3.45f1 lts 버전입니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
쓰레드 질문
선생님 강의 잘 듣고 있습니다. 혹시 쓰레드 시작쓰레드 종료stop호출종료 대기중종료 성공 순으로 로그가 떠야 하는데다른 온라인 게임 실행 도중에 디버깅을 하면로그 순서가 조금 바뀌더라구요 이 현상은 왜 일어나는건가요?
-
해결됨유니티 시스템 프로그래밍 Pt.1 - 상용 게임 구현을 위한 핵심 시스템 올인원 패키지
개발 도서 질문
혹시 게임개발이나 개발관련 추천하시는 책이 있으실까요?최근 남는시간에 책을 읽고있는데 지식공유자님이 추천하시는 책을 읽어보고 싶어서 질문드립니다!책을 많이 읽었던편이 아니라 유명한거라도 괜찮습니다 있으시다면 2-3가지 정도 부탁드립니다 (_ _)감사합니다 추가로 섹션6에 업적/미션 Pt.2에 Resources/Textures 폴더를 누락하신 듯 합니다.때문에 IconGolds와 IconGems 텍스쳐를 불러오지 못하네요통합강의자료에는 있어서 그걸로 임포트 했습니다!