묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Dead 애니메이션 출력 오류입니다.
현재 이렇게 되어있는 상태인데 왜인지 Dead 애니메이션만 실행이 안돼요... 코드는 그대로 복붙한 상태라 애니메이터 쪽이 문제인 것 같은데 뭐가 문제인 걸까요??
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
커스텀 에디터에 관하여 질문이 있습니다.
Quest의 커스텀 에디터를 작성하였는데Quest가 가진 TaskGroups의 TaskGroup의 변수를 수정하였는데 수정이 안되는데 커스텀 에디터의 하위 요소에도 부가적인 작업을 해야 수정이 되는건가요?protected SerializedProperty taskGroupsProperty;protected SerializedProperty rewardsProperty;protected SerializedProperty useAutoCompleteProperty;protected SerializedProperty isCancelableProperty;protected SerializedProperty isSaveavleProperty;protected SerializedProperty acceptConditonsProperty;protected SerializedProperty cancelConditionProperty;protected override void OnEnable(){ base.OnEnable(); taskGroupsProperty = serializedObject.FindProperty("taskGroups"); rewardsProperty = serializedObject.FindProperty("rewards"); useAutoCompleteProperty = serializedObject.FindProperty("useAutoComplete"); isCancelableProperty = serializedObject.FindProperty("isCancelable"); isSaveavleProperty = serializedObject.FindProperty("isSaveable"); acceptConditonsProperty = serializedObject.FindProperty("acceptionConditions"); cancelConditionProperty = serializedObject.FindProperty("cancelConditions");}public override void OnInspectorGUI(){ base.OnInspectorGUI(); serializedObject.Update(); if (DrawFoldoutTitle("Task")) EditorGUILayout.PropertyField(taskGroupsProperty); if (DrawFoldoutTitle("Rewards")) EditorGUILayout.PropertyField(rewardsProperty); if (DrawFoldoutTitle("Option")) EditorGUILayout.PropertyField(useAutoCompleteProperty); EditorGUILayout.PropertyField(isCancelableProperty); EditorGUILayout.PropertyField (isSaveavleProperty); if (DrawFoldoutTitle("Condition")) EditorGUILayout.PropertyField(acceptConditonsProperty); EditorGUILayout.PropertyField(cancelConditionProperty); serializedObject.ApplyModifiedProperties();}이런식으로 작성을 하였는데다른 enum으로 수정을 하여도 기본값인 Null이 출력됩니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬 구현 질문입니다
워크래프트3 영웅들 패시브 오라처럼 영웅이 살아있을때 영구적으로 지속되는 스킬은패시브로 짧은 주기마다 계속해서 효과를 주면 되는걸까요?간단한 스탯 영구적 증가 효과 스킬을패시브 타입으로 세팅에 apllycount 1, cooldown 1이펙트 세팅에서 duration 1.5 로이와 같이 하여 구현을 해보았습니다.혹여 더 좋은 방법이나 위의 방법이 문제가 있을지 궁금하여 질문드립니다.
-
해결됨[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Selct에 대해서 질문드립니다.
안녕하세요 강사님 궁금한게 있어서 질문 드립니다.제가 구현하고 싶은 부분은 리그오브 레전드의 스마트키 기능과 같은 부분입니다.제가 이해한 것이 맞다면 강의 안에서는Select로 비동기적 처리를 할 때 추가 입력을고정된 입력값(마우스 클릭)을 받아서 Select의 비동기적 처리를 구현한것으로 이해했습니다.만약 제가 롤의 SmartKey 기능과 같은 눌렀다가 키를 뗄때(스킬이 등록된 키마다 받아야할 입력이 달라짐)의 입력으로 비동기적 처리를 구현하고 싶다면 어떤식으로 구현해야 할까요?제가 고민해본 방법은 다음과 같습니다.Skill에 ReleaseInput()이라는 함수를 만든다.그리고 TargetSelectionAction에 똑같은 이름의 ReleaseInput() 함수를 만든다.ReleaseInput() 함수는 SkillSlot의 바인딩된 키 값을 기준으로 키를 뗄 때 호출된다.Skill의 RealeseInput()호출되면 Skill -> TargetSearch -> TargetSelectionAction 의 순서로 TargetSelection에 접근하여 TargetSelection의 추가로 만든releaseInput()함수를 호출한다.TargetSelectionAction에 releaseInputOccur이벤트를 만들고 ReleaseInput()함수로 이 이벤트를 Invoke해준다."키를 뗌" 액션을 Select의 비동기 방식에서 추가 입력값으로 이용하고 싶다면 releaseInputOccur이벤트에 추가적인 함수를 구독하여 기능을 구현한다.이런 식으로 생각해봤는데. 제가 아직 이 TargetSearcher 시스템에 이해도가 부족해서, 구현해주신 TargetSearcher 의 흐름을 망치지 않고 추가 기능을 만든 것 인지 아직 헷갈립니다.그래서 강사님께서 SmartKey방식을 구현하신다면 어떤 방식으로 구현하실지 궁금해서 여쭤봅니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
UseInAction에 대해서 질문드립니다.
제가 TargetSelectionTimingOption을 useInAction으로 했는데 SpawnSkillObjectAction클래스의 Apply부분에서 에러가 발생합니다.public override void Apply(Skill skill){foreach (var targetPosition in skill.TargetPositions) // 이 부분에서 에러 발생{var skillObject = GameObject.Instantiate(skillObjectPrefab).GetComponent<SkillObject>();skillObject.transform.position = targetPosition + (Vector3.up * 0.001f);skillObject.Setup(skill, targetSearcherForSkillObject, duration, applyCount, objectScale);}} 에러는 다음 오류가 발생합니다.NullReferenceException: Object reference not set to an instance of an objectSpawnSkillObjectAction.Apply (Skill skill) (at Assets/Scripts/Core/Skill/Action/SpawnSkillObjectAction.cs:25)Skill.Apply (System.Boolean isConsumeApplyCount) (at Assets/Scripts/Core/Skill/Skill.cs:643)InActionState.Apply () (at Assets/Scripts/Core/Skill/StateMachine/State/InActionState.cs:75)InActionState.Enter () (at Assets/Scripts/Core/Skill/StateMachine/State/InActionState.cs:23)StateMachine`1[EntityType].ChangeState (StateMachine`1+StateData[EntityType] newStateData) (at Assets/Scripts/Core/StateMachine/StateMachine.cs:88)StateMachine`1[EntityType].ChangeState (State`1[EntityType] newState, System.Int32 layer) (at Assets/Scripts/Core/StateMachine/StateMachine.cs:99)StateMachine`1[EntityType].TryTransition (System.Collections.Generic.IReadOnlyList`1[T] transtions, System.Int32 layer) (at Assets/Scripts/Core/StateMachine/StateMachine.cs:117)StateMachine`1[EntityType].Update () (at Assets/Scripts/Core/StateMachine/StateMachine.cs:135)Skill.Update () (at Assets/Scripts/Core/Skill/Skill.cs:396)SkillSystem.UpdateSkills () (at Assets/Scripts/Core/Skill/SkillSystem.cs:165)SkillSystem.Update () (at Assets/Scripts/Core/Skill/SkillSystem.cs:76)
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Effect만 이용하고 싶습니다.
Combat 시스템에 effect만 따로 사용하고 싶은데 아래처럼 그냥 사용하면[SerializeField] private Effect stunEffect; playerEntity.SkillSystem.Apply(stunEffect);Effect.cs var stackActions = StackActions.Where(x => x.Stack <= currentStack && !aplliedStackActions.Contains(x) && x.IsApplicable);위의 블록에서 ArgumentNullException: Value cannot be null 오류가 뜨더라구요 아마 StackActions값이 null이라 뜨는 것 같은데Skill을 사용 안하고 Effect를 사용하니 초기화 과정에서 문제가 있는 것 같습니다. 아니면 혹시 다르게 사용할 방법이 있을까 싶어서 질문드려봅니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬의 Statemachine에서 변수를 가져오는 방법이 있을까요
너무 많은 질문을 드려서 죄송합니다.InActionState에서 액션을 추가해서 이벤트를 통해서 SkillSystem에서 이벤트가 호출될때를 이용하려고 하는데 SkillSystem에서 직접적으로 해당 스킬을 가져와서 스킬의 StateMachine을 가져오려고해도 가져올수가 없습니다. 애니메이션 이벤트를 활용하는 함수에서Owner.StateMachine.GetCurrentState() is InSkillActionState ownerState를 이용하면 가져올수있을까 했는데 안되네요스킬의 statemachine의 내부에 있는 InActionState에서 Entity가 가진 변수를 가져오는건 알겠는데 skillsystem에서 skill의 statemachine에 포함되는 inActionstate의 변수를 가져오는 방법을 잘 모르겠습니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
InActionState에 추가하는 변수에 관하여 질문이 있습니다.
InActionState 플레이어의 입력을 받게 하려고 했는데 private PlayerInputEnum[] playerinput; 이렇게 변수를 만들고playerinput = Entity.Owner.PlayerEntityInput.playerInputList; 이거를 통해서 가져오려고 했는데 이걸 Setup에 넣으면 스테이트 머신이 고장나면서 버그가 발생하고KeyNotFoundException: The given key '0' was not present in the dictionary.System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <834b2ded5dad441e8c7a4287897d63c7>:0)StateMachine`1[EntityType].GetCurrentState (System.Int32 layer) (at Assets/Scripts/Core/StateMachine/StateMachine.cs:360)StateMachine`1[EntityType].GetCurrentStateType (System.Int32 layer) (at Assets/Scripts/Core/StateMachine/StateMachine.cs:363)Skill.GetCurrentStateType (System.Int32 layer) (at Assets/Scripts/Core/Skill/Skill.cs:600)Test.SkillTest.OnGUI () (at Assets/Scripts/Test/Skill/SkillTest.cs:53)UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)Enter에 넣어야 멀쩡히 작동을해서 질문을 드립니다.다른 변수로 테스트를 해보아도 배열 형태의 변수만 버그가 발생하는것 같아 질문을 드립니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬 사용에 관한 질문이 있습니다.
스킬시스템의public bool Use(Skill skill){ skill = Find(skill); Debug.Assert(skill != null, $"SkillSystem::IncreaseStack({skill.CodeName}) - Skill이 System에 등록되지 않았습니다."); return skill.Use();}여기에서 스킬을 사용한다는것은 알겠는데 등록되어있는 스킬을 사용하는 방식이 어떤건지 잘 모르겠습니다.모든 참조를 이용해서 찾아도 스킬테스트에서 사용한 것 말고는 없고 이벤트를 이용한것인가 싶어서 다 찾아보아도 안보여서 질문을 드립니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스킬 구현 질문입니다
현재 제가 인벤토리를 만들어 사용할 스킬을 등록하는 스킬창과 획득한 스킬을 보관하는 스킬보관창을 만들었습니다스킬창에 있는 스킬은 활성화되고 보관창에 있는것은 비활성화되게 할려는 의도입니다.액티브 스킬의 경우 키를 눌러 발동하기 때문에 문제가 없는데패시브 스킬의 경우 스킬보관창에 있어도 계속해서 발동됩니다.그래서 패시브 타입인 경우 스킬보관창에 있을 경우 비활성화되게 하기 위해skill 스크립트와 skillsystem 스크립트에 비활성화 변수를 추가하여 의도한 목적을 제작할려고 하였는데어디에서 제어해야 하는지 감이 안잡혀 이 부분에 대해 어딜 수정해야 되는지에 대한 조언을 부탁드립니다...
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
object 형의 박싱 언박싱에 관련해서 궁금합니다.
안녕하세요. 강습 잘 시청하고 있는데 궁금한 부분이 생겨서요.object 형을 많이 쓰던데, 실제 게임을 이 상태로 스킬을 구현해서 출시한다고 한다면 박싱 언박싱에 관련해서 성능 이슈는 없을까요? (ex : Stat.cs Dictionary<object, Dictionary<object, float>> bonusValuesByKey .. ) IdentifiedObject.cs 에서 object Clone() => Instantiate(this); 무시할 만한 수준일지 , 코드가 더 복잡하게 구현될 요지가 있어서 강의용으로 범용적으로 작업하셨는지 해서요.아님 object 형이 아닌 좀 더 나은 방향이 있다면 의견 듣고 싶습니다. 감사합니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
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;}
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
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와 인디케이터를 전부 없애버리고 투사체 스킬의 투사체 생성 대신에 소켓을 이용해서 공격판정 무기를 찾은 다음 해당 스킬 스크립트를 생성시켜준 다음에 애니메이션 이벤트로 콜라이더를 활성화 비 활성화로 공격 판정을 구현하고 공격 애니메이션이 끝나면 해당 스크립트를 삭제시켜주는 방식으로 구현을 생각중입니다.혼자서 독학 중이라 다른 사람들의 개발 방식을 볼 때마다 제 방식에 대한 확신을 가지지 못하는 것 같습니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
uphandcast만 트리거를 쓰는건지 궁금합니다.
// 인자로 받은 animatorParameter가 bool Type이면 owner의 StateMachine으로 인자로 받은 command를 보냄// Transition이 Command를 받아들였으면, State로 UsingSKill Message와 Skill 정보를 보냄if (animatorParameter.type == AnimatorParameterType.Bool && ownerStateMachine.ExecuteCommand(command)) ownerStateMachine.SendMessage(EntityStateMessage.UsingSkill, (skill, animatorParameter));// 인자로 받은 animatorParameter가 trigger Type이면 행동에 제약을 주지 않을 것이므로 ToDefaultState Command를 보내고// Transition이 받아들였는지와 상관없이, State로 UsingSkill Message와 skill 정보를 보냄else if (animatorParameter.type == AnimatorParameterType.Trigger){ ownerStateMachine.ExecuteCommand(EntityStateCommand.ToDefaultState); ownerStateMachine.SendMessage(EntityStateMessage.UsingSkill, (skill, animatorParameter));} 왜 Uphandcast만 트리거 타입이 되는지와 행동에 제약을 받지않는건지 궁금합니다.
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
다른형식의 근접공격에 대해 질문할것이 있습니다.
다크소울과 몬스터헌터 같은 게임의 근접공격 구현은 스킬의 액션에 새로운 액션을 만든 다음 피격 판정이 있는 무기에 콜라이더를 넣어준 다음 기존의 투사체 공격에 있는 소켓을 이용해서 구현하면 될까요
-
해결됨[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
Input 스킬 구현 질문
안녕하세요! 좋은 강의 감사합니다. 리븐 Q와 아트록스 Q와 같이 Input형 스킬이면서 n번째 사용 스킬이 다른 경우(ex) 리븐 Q 3타 에어본) 어떻게 구현하면 좋을 지 질문 드립니다!
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
스텟 연동 관련해서 질문이 있습니다.
제가 기존에 개발해둔 아이템 시스템을 연동시키면서 아이템의 스텟을 정할때 Resources/Stat폴더를 참조하고 그걸 기반으로 Enum으로 해당 스텟들이 있는 스크립트 파일을 만든 다음에 아래에 있는 버튼을 눌러서 일일히 Enum 파일을 동기화시켰는데 너무 번거로운것 같습니다. 생성, 삭제, 수정할때마다 동기화시키면 작업할때마다 딜레이가 너무 커지는데 다른 방법이 있을까요if (dataType == typeof(Stat)){GUI.color = Color.yellow;// Data를 이름 순으로 정렬하는 Button을 그림if (GUILayout.Button($"Press it after you finish editing")){StatEnumSynchronizer.SyncStatEnum();EditorUtility.SetDirty(database);AssetDatabase.SaveAssets();}}아래는 해당 enum파일을 만드는 스크립트입니다.using System;using System.IO;using System.Linq;using UnityEditor;using UnityEngine;public static class StatEnumSynchronizer{private const string StatFolderPath = "Assets/Resources/Stat";[MenuItem("Tools/Sync Stat Enum")]public static void SyncStatEnum(){if (!Directory.Exists(StatFolderPath)){Debug.LogError($"Directory does not exist: {StatFolderPath}");return;}var statFiles = Directory.GetFiles(StatFolderPath, "*.asset", SearchOption.TopDirectoryOnly);var statCodeNames = statFiles.Select(file => AssetDatabase.LoadAssetAtPath<Stat>(file)).Where(stat => stat != null).Select(stat => stat.CodeName).Distinct().OrderBy(name => name).ToList();string enumPath = "Assets/Scripts/Enum/ItemStatusAttribute.cs";using (var writer = new StreamWriter(enumPath, false)){writer.WriteLine("public enum ItemStatusAttribute");writer.WriteLine("{");writer.WriteLine(" Default,");foreach (var codeName in statCodeNames){string enumName = SanitizeEnumName(codeName);writer.WriteLine($" {enumName},");}writer.WriteLine("}");}AssetDatabase.Refresh();Debug.Log("Stat Enum synchronized.");}private static string SanitizeEnumName(string name){return new string(name.Where(c => !char.IsWhiteSpace(c) && (char.IsLetterOrDigit(c) || c == '_')).ToArray()).Replace(" ", "_").Replace("-", "_").ToUpper();}}
-
미해결[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템
텍스트 변환 Mark에 대하여 질문이 있습니다.
EffectAction에서public string BuildDescription(Effect effect, string description, int stackActionIndex, int stack, int effectIndex){ var stringsByKeyword = GetStringsByKeyword(effect); if (stringsByKeyword == null) return description; if (stack == 0) // ex. description = "적에게 $[EffectAction.defaultDamage.0] 피해를 줍니다." // defaultDamage = 300, effectIndex = 0, stringsByKeyword = new() { { "defaultDamage", defaultDamage.ToString() } }; // description.Replace("$[EffectAction.defaultDamage.0]", "300") => "적에게 300 피해를 줍니다." description = TextReplacer.Replace(description, "effectAction", stringsByKeyword, effectIndex.ToString()); else // Mark = $[EffectAction.Keyword.StackActionIndex.Stack.EffectIndex] description = TextReplacer.Replace(description, "effectAction", stringsByKeyword, $"{stackActionIndex}.{stack}.{effectIndex}"); return description;}여기 부분에서 왜 굳이 스택 0번째 인걸 구분하고 Effect에서 여기에서public string BuildDescription(string description, int effectIndex){ Dictionary<string, string> stringsByKeyword = new Dictionary<string, string>() { { "duration", Duration.ToString("0.##") }, { "applyCount", ApplyCount.ToString() }, { "applyCycle", ApplyCycle.ToString("0.##") } }; description = TextReplacer.Replace(description, stringsByKeyword, effectIndex.ToString()); description = Action.BuildDescription(this, description, 0, 0, effectIndex); // 여기부분에 질문이 있습니다 여기에서 0번째 것을 구분하고 var stackGroups = StackActions.GroupBy(x => x.Stack); foreach (var stackGroup in stackGroups) { int i = 0; foreach (var stackAction in stackGroup) description = stackAction.BuildDescription(this, description, i++, effectIndex); }// 여기에서 1스택이상 스킬의 텍스트를 전부 변환해주는데 return description;} EffectStackAction에서public string BuildDescription(Effect effect, string baseDescription, int stackActionIndex, int effectIndex) => action.BuildDescription(effect, baseDescription, stackActionIndex, stack, effectIndex);이렇게 까지 분리해서 텍스트로 변환하는지 여쭤보고 싶습니다.그냥 0번째부터 텍스트를 변환하면 안되는건지 질문이 있습니다.