feat: 젬 반복 시전 로직 및 테스트 프리셋 추가

- SkillGemData에 카테고리, 시전 속도 배율, 추가 반복 횟수 필드를 추가함
- SkillLoadoutEntry가 젬 합산 기준 최종 속도와 반복 횟수를 계산하도록 확장함
- SkillController가 반복 횟수만큼 스킬을 재시전하고 시작 효과와 OnEffect를 매 반복에 다시 적용하도록 수정함
- 연속 젬과 반복 젬 테스트 프리셋을 추가하고 디버그 메뉴에 적용 및 계산 로그 경로를 보강함
- 공격형 테스트 젬 자산과 추가 대미지 이펙트를 정리하고 무젬 35, 반복 젬 70 피해를 검증함
This commit is contained in:
2026-03-26 12:36:03 +09:00
parent dedfb60a4c
commit b4475ea77f
21 changed files with 726 additions and 91 deletions

View File

@@ -44,6 +44,7 @@ namespace Colosseum.Editor
private const string CrushGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_파쇄.asset";
private const string ChallengerGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_도전자.asset";
private const string GuardianGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_수호.asset";
private const string RepeatGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_연속.asset";
private const string EdgeGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_예리함.asset";
private const string ImpactGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_충격.asset";
private const string BreachGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_관통.asset";
@@ -53,6 +54,7 @@ namespace Colosseum.Editor
private const string TankGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_탱커_젬테스트.asset";
private const string SupportGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_지원_젬테스트.asset";
private const string DpsGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_딜러_젬테스트.asset";
private const string RepeatGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_반복젬테스트.asset";
private const string TankDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_탱커_복합젬테스트.asset";
private const string SupportDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_지원_복합젬테스트.asset";
private const string DpsDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_딜러_복합젬테스트.asset";
@@ -522,6 +524,12 @@ namespace Colosseum.Editor
ApplyLoadoutPreset(DpsGemPresetPath, "딜러 젬");
}
[MenuItem("Tools/Colosseum/Debug/Apply Repeat Gem Loadout")]
private static void ApplyRepeatGemLoadout()
{
ApplyLoadoutPreset(RepeatGemPresetPath, "반복 젬");
}
[MenuItem("Tools/Colosseum/Debug/Apply Tank Dual Gem Loadout")]
private static void ApplyTankDualGemLoadout()
{
@@ -580,48 +588,77 @@ namespace Colosseum.Editor
CrushGemPath,
"파쇄",
"고위력 기술의 단일 피해를 강화하는 테스트용 젬",
SkillGemCategory.Attack,
1.15f,
1.1f,
1f,
0,
damageEffect);
CreateOrUpdateGemAsset(
ChallengerGemPath,
"도전자",
"고위력 기술에 위협 선점 기능을 얹는 테스트용 젬",
SkillGemCategory.Threat,
1f,
1f,
1f,
0,
tauntEffect);
CreateOrUpdateGemAsset(
GuardianGemPath,
"수호",
"고위력 기술에 보호막 보조를 얹는 테스트용 젬",
SkillGemCategory.Support,
1.05f,
1.1f,
1f,
0,
shieldEffect);
CreateOrUpdateGemAsset(
RepeatGemPath,
"연속",
"붙은 스킬을 한 번 더 반복 시전하는 테스트용 젬",
SkillGemCategory.Efficiency,
1.2f,
1.15f,
1.1f,
1,
null);
CreateOrUpdateGemAsset(
EdgeGemPath,
"예리함",
"고정 추가 피해를 부여하는 테스트용 공격 젬",
SkillGemCategory.Attack,
1f,
1f,
1f,
0,
edgeDamageEffect);
CreateOrUpdateGemAsset(
ImpactGemPath,
"충격",
"중간 고정 추가 피해를 부여하는 테스트용 공격 젬",
SkillGemCategory.Attack,
1f,
1f,
1f,
0,
impactDamageEffect);
CreateOrUpdateGemAsset(
BreachGemPath,
"관통",
"높은 고정 추가 피해를 부여하는 테스트용 공격 젬",
SkillGemCategory.Attack,
1f,
1f,
1f,
0,
breachDamageEffect);
AssetDatabase.SaveAssets();
@@ -653,6 +690,7 @@ namespace Colosseum.Editor
SkillGemData crushGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(CrushGemPath);
SkillGemData challengerGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(ChallengerGemPath);
SkillGemData guardianGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(GuardianGemPath);
SkillGemData repeatGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(RepeatGemPath);
SkillGemData edgeGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(EdgeGemPath);
SkillGemData impactGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(ImpactGemPath);
SkillGemData breachGem = AssetDatabase.LoadAssetAtPath<SkillGemData>(BreachGemPath);
@@ -698,6 +736,19 @@ namespace Colosseum.Editor
CreateEntry(gemTestSkill, crushGem),
CreateEntry(evadeSkill)));
CreateOrUpdatePresetAsset(
RepeatGemPresetPath,
"반복 젬 테스트",
"연속 젬을 사용하는 반복 시전 검증 프리셋",
CreateLoadoutEntries(
CreateEntry(slashSkill),
CreateEntry(pierceSkill),
CreateEntry(spinSkill),
CreateEntry(dashSkill),
CreateEntry(projectileSkill),
CreateEntry(gemTestSkill, repeatGem),
CreateEntry(evadeSkill)));
CreateOrUpdatePresetAsset(
TankDualGemPresetPath,
"탱커 복합 젬 테스트",
@@ -854,6 +905,8 @@ namespace Colosseum.Editor
float resolvedManaCost = loadoutEntry.GetResolvedManaCost();
float resolvedCooldown = loadoutEntry.GetResolvedCooldown();
float resolvedAnimationSpeed = loadoutEntry.GetResolvedAnimationSpeed();
int resolvedRepeatCount = loadoutEntry.GetResolvedRepeatCount();
StringBuilder builder = new StringBuilder();
builder.Append("[Debug] 6번 슬롯 계산값 | ");
@@ -863,8 +916,13 @@ namespace Colosseum.Editor
builder.Append(resolvedManaCost.ToString("0.###"));
builder.Append(" | Cooldown=");
builder.Append(resolvedCooldown.ToString("0.###"));
builder.Append(" | Speed=");
builder.Append(resolvedAnimationSpeed.ToString("0.###"));
builder.Append(" | Repeat=");
builder.Append(resolvedRepeatCount);
builder.Append(" | GemSlots=");
builder.Append(loadoutEntry.SocketedGems.Count);
AppendGemCategorySummary(builder, loadoutEntry);
Debug.Log(builder.ToString());
}
@@ -1098,7 +1156,16 @@ namespace Colosseum.Editor
EditorUtility.SetDirty(skill);
}
private static void CreateOrUpdateGemAsset(string assetPath, string gemName, string description, float manaCostMultiplier, float cooldownMultiplier, SkillEffect triggeredEffect)
private static void CreateOrUpdateGemAsset(
string assetPath,
string gemName,
string description,
SkillGemCategory category,
float manaCostMultiplier,
float cooldownMultiplier,
float castSpeedMultiplier,
int additionalRepeatCount,
SkillEffect triggeredEffect)
{
SkillGemData gem = AssetDatabase.LoadAssetAtPath<SkillGemData>(assetPath);
if (gem == null)
@@ -1115,8 +1182,11 @@ namespace Colosseum.Editor
SerializedObject serializedGem = new SerializedObject(gem);
serializedGem.FindProperty("gemName").stringValue = gemName;
serializedGem.FindProperty("description").stringValue = description;
serializedGem.FindProperty("category").enumValueIndex = (int)category;
serializedGem.FindProperty("manaCostMultiplier").floatValue = manaCostMultiplier;
serializedGem.FindProperty("cooldownMultiplier").floatValue = cooldownMultiplier;
serializedGem.FindProperty("castSpeedMultiplier").floatValue = castSpeedMultiplier;
serializedGem.FindProperty("additionalRepeatCount").intValue = additionalRepeatCount;
SerializedProperty castStartEffectsProperty = serializedGem.FindProperty("castStartEffects");
castStartEffectsProperty.arraySize = 0;
@@ -1253,6 +1323,33 @@ namespace Colosseum.Editor
builder.Append("]");
}
private static void AppendGemCategorySummary(StringBuilder builder, SkillLoadoutEntry loadoutEntry)
{
if (builder == null || loadoutEntry == null || loadoutEntry.SocketedGems == null)
return;
bool hasGem = false;
StringBuilder categoryBuilder = new StringBuilder();
for (int i = 0; i < loadoutEntry.SocketedGems.Count; i++)
{
SkillGemData gem = loadoutEntry.SocketedGems[i];
if (gem == null)
continue;
if (hasGem)
categoryBuilder.Append(", ");
categoryBuilder.Append(gem.Category);
hasGem = true;
}
if (!hasGem)
return;
builder.Append(" | Category=");
builder.Append(categoryBuilder);
}
private static void CastOwnedPlayerSkillAsServer(ulong ownerClientId, int slotIndex)
{
if (!EditorApplication.isPlaying)