WL #977 PD 지시 6건 — ① 해머 기본 공격 이펙트 #976 전 값으로 되돌림(WLImpactFx) + 원래 의도대로 해머 기본 스킬 대지 솟음 바위 줄기 이펙트 0.45 → 0.225(판정 반경 그대로) ② 활 기본 멀티샷 디버프 제거(화살 데이터 부가 효과 None · SetSkillExtraType 끔 · 실측 더미 방어 감소 0 s) ③ 멀티샷 6 → 8발 · 부채 60 → 35°(실측 8발 × 3 · 방향 −18~+18°) ④ 활 시위 화살(새 WLNockArrow · 기본 화살 투사체 메시 사본 WL_NockArrow · 상태별 당김 구간 · 꼬리 = 오른손) ⑤ 맹약(오브) 주력 구슬 3 m 나갔다 되돌아와 몸에 흡수(새 WLOrbReturn · 원본 Skill_EnergyBall 훅 1줄 · 맞아도 안 꺼짐 = 나갈 때 · 돌아올 때 최대 2회 · 실측 명중 2 · 흡수 10) ⑥ 비수 기본 무자비한 일격 경로 호 녹색 · 투명도 0.75 + 수리검(새 WLShurikenRider · MasterStylizedFX GreenProjectile 사본이 호 가장자리를 따라 돎 · 원본 훅 1줄 · 실측 최대 8)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
bb37626e34
commit
918252e95e
|
|
@ -76,15 +76,25 @@ PrefabInstance:
|
|||
propertyPath: m_IsActive
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
|
||||
type: 3}
|
||||
propertyPath: InitialModule.startColor.maxColor.a
|
||||
value: 0.75
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
|
||||
type: 3}
|
||||
propertyPath: InitialModule.startColor.maxColor.b
|
||||
value: 0.23
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
|
||||
type: 3}
|
||||
propertyPath: InitialModule.startColor.maxColor.g
|
||||
value: 0.55
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
|
||||
type: 3}
|
||||
propertyPath: InitialModule.startColor.maxColor.r
|
||||
value: 0.3
|
||||
value: 0.17
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6424247364373830703, guid: 8a02c4042c68dd244abad8cf394dab42,
|
||||
type: 3}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ public class Skill_BrutalSlash : ProjectileBase
|
|||
yield return new WaitForSeconds(WL.Combat.Weapon.WLSkillTiming.Seconds(this, "charge", 1.0f)); // WL #976 훅(1줄) — 모으기(애니메이션 멈춤) 시간 = WLSkillTiming.json(비수 기본 0.5 s · 규칙 없으면 원본 1.0 s)
|
||||
m_ProjecTileData.shooter.m_animation.speed = 1f;
|
||||
DSUtil.InActivateGameObjects(gos_effect, 1);
|
||||
WL.Combat.Weapon.WLShurikenRider.Begin(this); // WL #977 훅(1줄) — 경로 이펙트(Multiple Slashes 호)에 수리검 여러 개(WLShurikenRider.json)
|
||||
m_sacc.Set(m_ProjecTileData);
|
||||
yield return new WaitForSeconds(1.5f);
|
||||
OptionInfo.Ins.Set_PCMove(m_ProjecTileData.shooter, true);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public class Skill_EnergyBall : ProjectileBase
|
|||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
list_energyball[i].gameObject.SetActive(true);
|
||||
if (WL.Combat.Weapon.WLOrbReturn.Take(this, list_energyball, count)) yield break; // WL #977 훅(1줄) — 구슬 3 m 나갔다 되돌아와 몸에 흡수 · 나갈 때 · 돌아올 때 판정(WLOrbReturn.json)
|
||||
|
||||
// 에너지볼 이동
|
||||
while (m_LifeTime > 0f)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@
|
|||
10502
|
||||
],
|
||||
"prefab": "WL_Hit_Hammer",
|
||||
"scale": 0.5,
|
||||
"_note_976": "#976 PD 「해머 기본 공격 이펙트 크기를 절반으로」 — 피격 1.0 → 0.5 · 휘두르기 WL_Impact_Swing_Orange 1~3타 1.0 → 0.5 · 1타 지면 충격 WL_Impact_Explosion 0.18 → 0.09(10502 수호자의 철퇴 · lineup 밖도 같은 규칙)",
|
||||
"scale": 1.0,
|
||||
"fit": 1.4,
|
||||
"offsetCompensate": true
|
||||
},
|
||||
|
|
@ -198,7 +197,7 @@
|
|||
1
|
||||
],
|
||||
"prefab": "WL_Impact_Swing_Orange",
|
||||
"scale": 0.5,
|
||||
"scale": 1.0,
|
||||
"euler": [
|
||||
0,
|
||||
0,
|
||||
|
|
@ -219,7 +218,7 @@
|
|||
2
|
||||
],
|
||||
"prefab": "WL_Impact_Swing_Orange",
|
||||
"scale": 0.5,
|
||||
"scale": 1.0,
|
||||
"euler": [
|
||||
0,
|
||||
0,
|
||||
|
|
@ -240,7 +239,7 @@
|
|||
3
|
||||
],
|
||||
"prefab": "WL_Impact_Swing_Orange",
|
||||
"scale": 0.5,
|
||||
"scale": 1.0,
|
||||
"euler": [
|
||||
0,
|
||||
0,
|
||||
|
|
@ -379,7 +378,7 @@
|
|||
],
|
||||
"stage": 1,
|
||||
"prefab": "WL_Impact_Explosion",
|
||||
"scale": 0.09,
|
||||
"scale": 0.18,
|
||||
"forward": 0.0,
|
||||
"tipContact": true,
|
||||
"contactHeight": 0.15,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a032af506dbe53b45a7d61a730bfa011
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &2286313539756212851
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3384687383004869994}
|
||||
m_Layer: 0
|
||||
m_Name: WL_NockArrow
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3384687383004869994
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2286313539756212851}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8083545554685379984}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &4089787332761738456
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8083545554685379984}
|
||||
- component: {fileID: 3926352655812325371}
|
||||
- component: {fileID: 1485827680575776289}
|
||||
m_Layer: 0
|
||||
m_Name: PP_Theme_10_Arrow_003
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8083545554685379984
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4089787332761738456}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 2, y: 2, z: 2}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3384687383004869994}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &3926352655812325371
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4089787332761738456}
|
||||
m_Mesh: {fileID: 8511194730541559256, guid: 5d798ba6e93b7a540acce3c4f1f61184, type: 3}
|
||||
--- !u!23 &1485827680575776289
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4089787332761738456}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 1ed5c689ba8eacc4c8e9d3b8ba968880, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2ae2870e0f79868449616e7385aff319
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"enabled": 1,
|
||||
"classes": [ 10402 ],
|
||||
"prefab": "WL/Fx/WL_NockArrow",
|
||||
"lengthMeters": 0.55,
|
||||
"nockOffset": 0.0,
|
||||
"rules": [
|
||||
{ "state": "attack", "from": 0.20, "to": 0.56 },
|
||||
{ "state": "Bow_Attack2", "from": 0.20, "to": 0.56 },
|
||||
{ "state": "Bow_Attack3", "from": 0.20, "to": 0.92 },
|
||||
{ "state": "Bow_Skill4_Push", "from": 0.16, "to": 0.48 }
|
||||
],
|
||||
"note": "#977 PD 「활 시위를 당길 때 화살 오브젝트가 보이게 해줘.(보유중인 리소스 중 화살을 찾아볼 것)」 — 화살 = 기본 화살 투사체 Projectile_10402 의 PP_Theme_10_Arrow_003 메시 사본(WL_NockArrow) · 꼬리 = 오른손 · 촉 = 왼손(활) 쪽 · 길이 0.55 m(PM 값) · 보이는 구간 = 상태별 정규화(시위를 잡은 뒤 ~ 놓는 순간): 1 · 2타 BowShot 0.20~0.56(#967 놓는 순간 0.56) · 3타 FR_Bow3 0.20~0.92(Projectile 0.92) · 4타 Bow_Skill4_Push 0.16~0.48(Projectile 0.48 · 두 손 거리 편집 모드 실측) · 주력 · 멀티샷 모으기도 같은 attack 상태(0.30~0.56)라 함께"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61cd89b69fbb2fe4ea94cec3d0416008
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"enabled": 1,
|
||||
"skills": [ "Skill_EnergyBall" ],
|
||||
"outMeters": 3.0,
|
||||
"returnSpeedMul": 1.0,
|
||||
"absorbDist": 0.35,
|
||||
"absorbSeconds": 0.12,
|
||||
"maxSeconds": 4.0,
|
||||
"note": "#977 PD 「오브 주력 스킬 시전 시 발사 된 오브가 3m 범위까지 날아갔다가 되돌아오며 플레이어 몸으로 흡수 되듯 소멸하게 해줘. (되돌아올 때에도 판정이 발생되어 최대 2번의 피해를 입힐 수 있어야 함)」 — 맹약 주력 에너지볼 난사(703303) · 구슬마다 3 m 나감 → PC 몸 가운데로 같은 속도로 되돌아옴 → 0.35 m 안에서 0.12 s 작아지며 꺼짐 · 맞아도 구슬을 끄지 않아 나갈 때 · 돌아올 때 적마다 최대 2회(PM 값 = 돌아오는 속도 · 흡수 거리 · 시간)"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d72b7ae42ffb4374a9d8d5a4d3d74001
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -48,10 +48,12 @@
|
|||
"projectile": "Projectile_10402",
|
||||
"volleys": 3,
|
||||
"interval": 0.2,
|
||||
"arrows": 6,
|
||||
"arrows": 8,
|
||||
"drawFraction": 0.8,
|
||||
"noExtra": 1,
|
||||
"note_977": "#977 PD 「활 기본 스킬에 명중 된 적에게 발생하는 디버프를 제거」 · 「탄환 수를 8발로 늘리고, 화살 간 간격을 더 좁혀(지금은 조금만 떨어져서 적이 안맞는 경우가 빈번)」 — noExtra 1(703404 부가 효과 방어력 감소 끔) · 6 → 8발 · 부채 60° → 35°(화살 사이 12° → 5° · 5 m 에서 화살 사이 약 1.06 → 0.44 m · PM 값)",
|
||||
"note_976": "#976 PD 「활 기본 공격이 투사체 형태로 발사되어야 하는데 투사체처럼 보이지 않아. 기본 활 투사체와 동일한 투사체를 발사하도록 변경하고, 연속 공격 간격을 0.2초로 줄여줘 (발사하는 투사체 수량도 6발로 줄여줘)」 — PM 해석: 활 기본 스킬(멀티샷 Q) · 화살 Projectile_ArcherSkill2Arrow(주력 속사 금빛 줄기) → Projectile_10402(기본 공격 화살 · 겉모습 WLProjectileVisual 그대로) · 간격 0.5 → 0.2 s · 다발마다 10 → 6발(3회 그대로) · 다시 당기기 = 0.2 × 0.8 = 0.16 s(원래 당김 0.23 s 보다 빨리)",
|
||||
"fanDegrees": 60,
|
||||
"fanDegrees": 35,
|
||||
"rangeMul": 1.0,
|
||||
"pierce": 0,
|
||||
"mark": 0,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"enabled": 1,
|
||||
"skills": [ "Skill_BrutalSlash" ],
|
||||
"classes": [ 10202 ],
|
||||
"layer": "Multiple Slashes",
|
||||
"prefab": "WL/Fx/WL_Fx_DaggerShuriken",
|
||||
"every": 8,
|
||||
"maxRiders": 12,
|
||||
"riderScale": 0.3,
|
||||
"rimFraction": 1.0,
|
||||
"maxSeconds": 2.5,
|
||||
"note": "#977 PD 「비수의 기본 스킬 시전 시 Master Stylized Projectile 에셋의 첨부 된 스크린샷과 같은 수리검을 경로 이펙트에 다수 보이게 연출해줘. (이때 이펙트 궤적의 색상을 기본 공격처럼 녹색 계열로 바꾸고, 투명도를 조금 부여해서 자연스럽게 구성해줘)」 — 수리검 = MasterStylizedFX Projectiles/GreenProjectile 사본(녹색 초승달 소용돌이 + 흰 별 = 스크린샷 · 진행 방향으로 돌림 · 처음 만든 ShurikensHit 층 사본은 녹색 베기 띠가 사각으로 보여 바꿈) · 경로 = 무자비한 일격 Multiple Slashes 호(시작색 (0.17,1.00,0.23) 투명도 0.75 · 기본 공격 녹색) · 호 입자 8개 중 1개에 수리검(최대 12) · 호 가장자리에 붙어 호와 함께 돈다 · 크기 0.3(PM 값)"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 823f6a91f866d5042b6dcee5b4a9cd74
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -84,7 +84,8 @@
|
|||
"center": "caster",
|
||||
"fx": {
|
||||
"prefab": "WL/Fx/WL_Fx_StaffPath",
|
||||
"scale": 0.45,
|
||||
"scale": 0.225,
|
||||
"_note_977": "#977 PD 「해머 기본 스킬 이펙트를 줄이라고 한건데 기본 공격 이펙트를 줄인 것 같아」 — #976 의 절반을 기본 공격에서 되돌리고 기본 스킬(대지 솟음) 바위 줄기 이펙트 0.45 → 0.225 · 판정 반경 3.5 m · 퍼짐 9 m/s 는 그대로(원장)",
|
||||
"bodyScale": 0,
|
||||
"offset": [
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLNockArrow.cs — 활 시위를 당기는 동안 화살(기본 화살 투사체와 같은 메시)을 당기는 손 ~ 활 사이에 보인다 (#977 · 2026-10-24)
|
||||
//
|
||||
// PD 원문: 「활 시위를 당길 때 화살 오브젝트가 보이게 해줘.(보유중인 리소스 중 화살을 찾아볼 것)」
|
||||
// ■ 화살 = Resources/WL/Fx/WL_NockArrow(Projectile_10402 의 PP_Theme_10_Arrow_003 메시 사본 · 루트 +Z = 촉)
|
||||
// ■ 활 직업(classes)의 애니메이터 상태가 규칙(state · 정규화 from~to = 시위를 당겨 놓기 전까지)에 들면 매 LateUpdate(IK 뒤)에
|
||||
// 꼬리 = 오른손 · 촉 방향 = 왼손(활 잡은 손) 쪽 · 길이 lengthMeters 로 놓고, 아니면 숨긴다 · 스킬 러너(WLRapidShot)도 같은 attack 상태라 함께
|
||||
// ■ 값 = Resources/WL/WLNockArrow.json (C45) · 끄기 = enabled 0
|
||||
// 🔴 Debug.LogError 금지(원본 팝업).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.Combat.Weapon
|
||||
{
|
||||
[System.Serializable]
|
||||
public class WLNockArrowRule { public string state = ""; public float from, to = 1f; }
|
||||
|
||||
[System.Serializable]
|
||||
public class WLNockArrowJson
|
||||
{
|
||||
public int enabled = 0;
|
||||
public int[] classes = new int[0];
|
||||
public string prefab = "WL/Fx/WL_NockArrow";
|
||||
public float lengthMeters = 0.55f; // 보이는 화살 길이(m)
|
||||
public float nockOffset = 0f; // 꼬리를 오른손에서 촉 쪽으로 더 미는 거리(m)
|
||||
public WLNockArrowRule[] rules = new WLNockArrowRule[0];
|
||||
public string note = "";
|
||||
}
|
||||
|
||||
public static class WLNockArrow
|
||||
{
|
||||
public const string ResourcesPath = "WL/WLNockArrow";
|
||||
public static int ShownFrames; public static string LastState = "", LastLog = "";
|
||||
static WLNockArrowJson s_cfg; static GameObject s_runner;
|
||||
|
||||
internal static WLNockArrowJson Cfg
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_cfg != null) return s_cfg;
|
||||
s_cfg = new WLNockArrowJson();
|
||||
var ta = Resources.Load<TextAsset>(ResourcesPath);
|
||||
if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; }
|
||||
try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; }
|
||||
return s_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
static void Boot()
|
||||
{
|
||||
s_cfg = null;
|
||||
if (Cfg.enabled == 0 || s_runner != null) return;
|
||||
s_runner = new GameObject("[WL977] NockArrow"); s_runner.hideFlags = HideFlags.HideAndDontSave;
|
||||
Object.DontDestroyOnLoad(s_runner); s_runner.AddComponent<WLNockArrowRunner>();
|
||||
}
|
||||
}
|
||||
|
||||
[DefaultExecutionOrder(1000)] // 애니메이션 · 활 손 IK(WLBowPoseIK) 뒤
|
||||
internal sealed class WLNockArrowRunner : MonoBehaviour
|
||||
{
|
||||
GameObject _arrow; float _tailZ, _len = 1f;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
bool show = false;
|
||||
try
|
||||
{
|
||||
var c = WLNockArrow.Cfg; var pc = MyValue.MyPC as PCActor;
|
||||
if (c.enabled != 0 && pc != null && pc.m_animation != null && pc.m_animation.isHuman && !pc.IsDead() &&
|
||||
(c.classes == null || c.classes.Length == 0 || System.Array.IndexOf(c.classes, pc.Get_ID()) >= 0))
|
||||
{
|
||||
var an = pc.m_animation; var st = an.GetCurrentAnimatorStateInfo(0); float n = st.normalizedTime;
|
||||
if (c.rules != null) foreach (var r in c.rules) if (r != null && st.IsName(r.state) && n >= r.from && n <= r.to) { show = true; WLNockArrow.LastState = r.state; break; }
|
||||
if (show)
|
||||
{
|
||||
var rh = an.GetBoneTransform(HumanBodyBones.RightHand); var lh = an.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
if (rh == null || lh == null || !Ensure(c)) show = false;
|
||||
else
|
||||
{
|
||||
var d = lh.position - rh.position;
|
||||
if (d.sqrMagnitude < 1e-6f) show = false;
|
||||
else
|
||||
{
|
||||
float s = c.lengthMeters / Mathf.Max(1e-3f, _len); var rot = Quaternion.LookRotation(d.normalized);
|
||||
var t = _arrow.transform; t.localScale = Vector3.one * s; t.rotation = rot;
|
||||
t.position = rh.position + rot * new Vector3(0f, 0f, c.nockOffset - _tailZ * s); // 꼬리(_tailZ) = 오른손
|
||||
WLNockArrow.ShownFrames++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex) { WLNockArrow.LastLog = "실패 — " + ex.Message; show = false; }
|
||||
if (_arrow != null && _arrow.activeSelf != show) _arrow.SetActive(show);
|
||||
}
|
||||
|
||||
bool Ensure(WLNockArrowJson c)
|
||||
{
|
||||
if (_arrow != null) return true;
|
||||
var p = Resources.Load<GameObject>(c.prefab); if (p == null) { WLNockArrow.LastLog = "화살 프리팹 없음 " + c.prefab; return false; }
|
||||
_arrow = Instantiate(p); _arrow.name = "[WL977] NockArrow"; DontDestroyOnLoad(_arrow);
|
||||
float zmin = float.MaxValue, zmax = float.MinValue; // 루트 기준 메시 경계(꼬리 · 촉)
|
||||
foreach (var mf in _arrow.GetComponentsInChildren<MeshFilter>(true))
|
||||
{
|
||||
if (mf.sharedMesh == null) continue; var b = mf.sharedMesh.bounds; var m = _arrow.transform.worldToLocalMatrix * mf.transform.localToWorldMatrix;
|
||||
for (int i = 0; i < 8; i++) { var v = m.MultiplyPoint3x4(new Vector3((i & 1) == 0 ? b.min.x : b.max.x, (i & 2) == 0 ? b.min.y : b.max.y, (i & 4) == 0 ? b.min.z : b.max.z)); zmin = Mathf.Min(zmin, v.z); zmax = Mathf.Max(zmax, v.z); }
|
||||
}
|
||||
_tailZ = zmin < zmax ? zmin : 0f; _len = zmin < zmax ? zmax - zmin : 1f;
|
||||
WLNockArrow.LastLog = "화살 길이(원본) " + _len.ToString("F2") + " m · 꼬리 z " + _tailZ.ToString("F2");
|
||||
_arrow.SetActive(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4b28c9abcf17d241a9f98363bc2eab0
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLOrbReturn.cs — 맹약(오브) 주력 「에너지볼 난사」(Skill_EnergyBall) 구슬이 정해진 거리까지 날아갔다 되돌아와 플레이어 몸에 흡수되듯 사라진다 (#977 · 2026-10-24)
|
||||
//
|
||||
// PD 원문: 「오브 주력 스킬 시전 시 발사 된 오브가 3m 범위까지 날아갔다가 되돌아오며 플레이어 몸으로 흡수 되듯 소멸하게 해줘.
|
||||
// (되돌아올 때에도 판정이 발생되어 최대 2번의 피해를 입힐 수 있어야 함)」
|
||||
// ■ 원본(Skill_EnergyBall.Co_Shoot): 구슬 N 개를 방사형으로 수명 동안 앞으로 · 구슬마다 ProjectileHitChecker(Off_OnlyThisObj_byHit 1 = 맞으면 그 구슬만 꺼짐)
|
||||
// ■ WL — 원본 이동 직전 훅 1줄(Take)이 넘겨받는다: 구슬마다 outMeters 까지 앞으로 → PC 몸 가운데로 되돌아옴 → absorbDist 안에서 absorbSeconds 동안 작아지며 꺼짐
|
||||
// · 맞아도 구슬을 끄지 않는다(체커 Off_OnlyThisObj_byHit 0 · 투사체 m_Pierce 1 — 끝나면 원래 값) → 나가며 들어갈 때 1회 · 돌아오며 다시 들어갈 때 1회 = 적마다 최대 2회
|
||||
// ■ 값 = Resources/WL/WLOrbReturn.json (C45) · enabled 0 = 원본 그대로
|
||||
// 🔴 Debug.LogError 금지(원본 팝업).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.Combat.Weapon
|
||||
{
|
||||
[System.Serializable]
|
||||
public class WLOrbReturnJson
|
||||
{
|
||||
public int enabled = 0;
|
||||
public string[] skills = new string[0]; // 원본 스킬 클래스 이름(비우면 훅을 단 스킬 모두)
|
||||
public float outMeters = 3f; // 나가는 거리(m · 구슬 시작 자리에서 수평)
|
||||
public float returnSpeedMul = 1f; // 돌아오는 속도 = 투사체 속도 × 이 값
|
||||
public float absorbDist = 0.35f; // PC 몸 가운데에서 이 거리(m) 안이면 흡수 시작
|
||||
public float absorbSeconds = 0.12f; // 흡수(작아지며 꺼짐) 시간
|
||||
public float maxSeconds = 4f; // 상한 — 넘으면 남은 구슬도 끈다
|
||||
public string note = "";
|
||||
}
|
||||
|
||||
public static class WLOrbReturn
|
||||
{
|
||||
public const string ResourcesPath = "WL/WLOrbReturn";
|
||||
public static int Taken, Absorbed, Errors;
|
||||
public static float LastOutSeconds, LastTotalSeconds;
|
||||
public static string LastLog = "";
|
||||
static WLOrbReturnJson s_cfg;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; }
|
||||
|
||||
internal static WLOrbReturnJson Cfg
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_cfg != null) return s_cfg;
|
||||
s_cfg = new WLOrbReturnJson();
|
||||
var ta = Resources.Load<TextAsset>(ResourcesPath);
|
||||
if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; }
|
||||
try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; }
|
||||
return s_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>원본 Skill_EnergyBall.Co_Shoot 이동 직전 훅 — true 면 WL 이 구슬을 움직이고 끝에 원본 투사체를 끈다(원본 이동 · Off 건너뜀).</summary>
|
||||
public static bool Take(ProjectileBase pb, List<Transform> balls, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = Cfg; if (c.enabled == 0 || pb == null || balls == null || count <= 0) return false;
|
||||
if (c.skills != null && c.skills.Length > 0 && System.Array.IndexOf(c.skills, pb.GetType().Name) < 0) return false;
|
||||
var pd = pb.Get_ProjectTileData(); if (pd == null || DSUtil.CheckNull(pd.shooter)) return false;
|
||||
var run = pb.GetComponent<WLOrbReturnRunner>(); if (run == null) run = pb.gameObject.AddComponent<WLOrbReturnRunner>();
|
||||
run.Begin(pb, pd, balls, count, c);
|
||||
Taken++;
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception ex) { Errors++; LastLog = "넘겨받기 실패 — " + ex.Message; return false; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>넘겨받은 에너지볼 묶음 1개의 진행 — 나감 · 되돌아옴 · 흡수 · 끝(원래 값 되돌림 + 원본 투사체 끄기).</summary>
|
||||
internal sealed class WLOrbReturnRunner : MonoBehaviour
|
||||
{
|
||||
public void Begin(ProjectileBase pb, ProjectileData pd, List<Transform> balls, int count, WLOrbReturnJson c)
|
||||
{
|
||||
StopAllCoroutines();
|
||||
StartCoroutine(Run(pb, pd, balls, count, c));
|
||||
}
|
||||
|
||||
IEnumerator Run(ProjectileBase pb, ProjectileData pd, List<Transform> balls, int count, WLOrbReturnJson c)
|
||||
{
|
||||
var shooter = pd.shooter;
|
||||
int n = Mathf.Min(count, balls.Count);
|
||||
bool pierce0 = pb.m_Pierce; pb.m_Pierce = true; // 체커가 Off(false) 를 불러도 묶음이 꺼지지 않게
|
||||
var checkers = new List<ProjectileHitChecker>(); var offs = new List<bool>();
|
||||
for (int i = 0; i < n; i++)
|
||||
foreach (var ck in balls[i].GetComponentsInChildren<ProjectileHitChecker>(true)) { checkers.Add(ck); offs.Add(ck.Off_OnlyThisObj_byHit); ck.Off_OnlyThisObj_byHit = false; }
|
||||
var start = new Vector3[n]; var dir = new Vector3[n]; var phase = new int[n]; var absorbT = new float[n]; var scale0 = new Vector3[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
start[i] = balls[i].position; var f = balls[i].forward; f.y = 0f;
|
||||
dir[i] = f.sqrMagnitude > 1e-6f ? f.normalized : Vector3.forward; scale0[i] = balls[i].localScale;
|
||||
}
|
||||
float speed = Mathf.Max(0.1f, pd.Speed), t0 = Time.time, tOut = -1f; int done = 0;
|
||||
while (done < n && Time.time - t0 < c.maxSeconds)
|
||||
{
|
||||
if (DSUtil.CheckNull(shooter)) break;
|
||||
Vector3 home = shooter.Get_Center_position();
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var b = balls[i]; if (b == null || phase[i] == 3) continue;
|
||||
if (!b.gameObject.activeSelf) { phase[i] = 3; done++; continue; } // 다른 이유로 꺼짐
|
||||
float step = speed * Time.deltaTime;
|
||||
if (phase[i] == 0) // 나감
|
||||
{
|
||||
b.position += dir[i] * step;
|
||||
var tr = b.position - start[i]; tr.y = 0f;
|
||||
if (tr.magnitude >= c.outMeters) { phase[i] = 1; if (tOut < 0f) tOut = Time.time - t0; }
|
||||
}
|
||||
else if (phase[i] == 1) // 되돌아옴(PC 몸 가운데로)
|
||||
{
|
||||
var to = home - b.position; float d = to.magnitude, rs = step * Mathf.Max(0.1f, c.returnSpeedMul);
|
||||
if (d <= c.absorbDist + rs) { b.position = home; phase[i] = 2; absorbT[i] = 0f; }
|
||||
else { b.position += to / d * rs; b.rotation = Quaternion.LookRotation(to); }
|
||||
}
|
||||
else // 흡수 — 몸 가운데에서 작아지며 꺼짐
|
||||
{
|
||||
absorbT[i] += Time.deltaTime; b.position = home;
|
||||
float k = 1f - Mathf.Clamp01(absorbT[i] / Mathf.Max(0.01f, c.absorbSeconds));
|
||||
b.localScale = scale0[i] * k;
|
||||
if (k <= 0f) { b.gameObject.SetActive(false); b.localScale = scale0[i]; phase[i] = 3; done++; WLOrbReturn.Absorbed++; }
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
for (int i = 0; i < checkers.Count; i++) if (checkers[i] != null) checkers[i].Off_OnlyThisObj_byHit = offs[i]; // 풀 재사용 대비 원래 값
|
||||
for (int i = 0; i < n; i++) if (balls[i] != null) balls[i].localScale = scale0[i];
|
||||
pb.m_Pierce = pierce0;
|
||||
WLOrbReturn.LastOutSeconds = tOut; WLOrbReturn.LastTotalSeconds = Time.time - t0;
|
||||
WLOrbReturn.LastLog = "구슬 " + n + " · 나감 " + c.outMeters + " m(" + tOut.ToString("F2") + " s) · 흡수 " + done + " · 전체 " + (Time.time - t0).ToString("F2") + " s";
|
||||
WLStaffEarth.OffOriginal(pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9da4d67f27d36374391e8b43935e442e
|
||||
|
|
@ -79,6 +79,7 @@ namespace WL.Combat.Weapon
|
|||
public int pierce = 0; // 1 = 관통
|
||||
public int mark = 0; // 1 = 과녁 표시(주력처럼)
|
||||
public float drawFraction = 0.8f; // #976 다시 당기는 시간 상한 = interval × 이 값(간격이 당김 동작 0.23 s 보다 짧으면 그만큼 빨리 당긴다)
|
||||
public int noExtra = 1; // #977 1 = 화살에 원본 스킬 부가 효과(703404 방어력 감소 디버프) 없음
|
||||
public string note = "";
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +136,12 @@ namespace WL.Combat.Weapon
|
|||
if (c.classes != null && c.classes.Length > 0 && System.Array.IndexOf(c.classes, ClassOf(pc)) < 0) return false;
|
||||
int n = Mathf.Max(1, m.volleys) * Mathf.Max(1, m.arrows);
|
||||
var list = new List<ProjectileData>(n);
|
||||
for (int i = 0; i < n; i++) { var d = new ProjectileData(); data.Copy(d); d.eStartPos = eProjectileStartPos.ShooterCenter; list.Add(d); }
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var d = new ProjectileData(); data.Copy(d); d.eStartPos = eProjectileStartPos.ShooterCenter;
|
||||
if (m.noExtra != 0) { d.e_SkillExtraType = eSkillExtraType.None; d.m_skillTypeConfigTable = null; d.SetSkillExtraType = false; } // #977 PD 「활 기본 스킬에 명중 된 적에게 발생하는 디버프를 제거」 — Actor.Check_Extra 가 None 이면 바로 돌아간다 · SetSkillExtraType 를 꺼야 ProjectileBase.Set 이 스킬 표 값으로 다시 넣지 않는다(1차 Play 실측 방어 감소 남음)
|
||||
list.Add(d);
|
||||
}
|
||||
var target = data.target;
|
||||
if (DSUtil.CheckNull(target) || target.IsDead()) target = pc.Get_Target();
|
||||
var run = pb.GetComponent<WLRapidShotRunner>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLShurikenRider.cs — 비수 기본 스킬(무자비한 일격) 경로 이펙트(Multiple Slashes 호) 위에 수리검을 여러 개 태운다 (#977 · 2026-10-24)
|
||||
//
|
||||
// PD 원문: 「비수의 "기본 스킬" 시전 시 Master Stylized Projectile 에셋의 첨부 된 스크린샷과 같은 수리검을 경로 이펙트에 다수 보이게 연출해줘.
|
||||
// (이때 이펙트 궤적의 색상을 기본 공격처럼 녹색 계열로 바꾸고, 투명도를 조금 부여해서 자연스럽게 구성해줘)」
|
||||
// ■ 수리검 = Resources/WL/Fx/WL_Fx_DaggerShuriken(MasterStylizedFX ShurikensHit 사본 · 녹색 소용돌이 ShurikenSlash + 흰 별 CoreWhite 만 · 반복 · 회전)
|
||||
// ■ 원본 Skill_BrutalSlash.Co_Update 가 베기 이펙트를 켜는 줄 다음 훅 1줄(Begin) → 그 투사체의 경로 층(layer) 입자 중 every 번째(randomSeed)마다
|
||||
// 수리검 1개를 붙여 매 LateUpdate 호의 가장자리(입자 위치 + 3D 회전 × 오른쪽 × 메시 반지름 × 크기 × rimFraction)로 — 호가 돌면 수리검이 호를 따라 돈다 · 입자가 사라지면 숨김
|
||||
// ■ 값 = Resources/WL/WLShurikenRider.json (C45) · 끄기 = enabled 0
|
||||
// 🔴 Debug.LogError 금지(원본 팝업).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.Combat.Weapon
|
||||
{
|
||||
[System.Serializable]
|
||||
public class WLShurikenRiderJson
|
||||
{
|
||||
public int enabled = 0;
|
||||
public string[] skills = new string[0];
|
||||
public int[] classes = new int[0];
|
||||
public string layer = "Multiple Slashes";
|
||||
public string prefab = "WL/Fx/WL_Fx_DaggerShuriken";
|
||||
public int every = 8; // 경로 입자 randomSeed % every == 0 인 것에만
|
||||
public int maxRiders = 12;
|
||||
public float riderScale = 0.12f;
|
||||
public float rimFraction = 1f; // 호 반지름 대비 자리(1 = 가장자리)
|
||||
public float maxSeconds = 2.5f;
|
||||
public string note = "";
|
||||
}
|
||||
|
||||
public static class WLShurikenRider
|
||||
{
|
||||
public const string ResourcesPath = "WL/WLShurikenRider";
|
||||
public static int Begun, MaxShown; public static string LastLog = "";
|
||||
static WLShurikenRiderJson s_cfg;
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; }
|
||||
|
||||
internal static WLShurikenRiderJson Cfg
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_cfg != null) return s_cfg;
|
||||
s_cfg = new WLShurikenRiderJson();
|
||||
var ta = Resources.Load<TextAsset>(ResourcesPath);
|
||||
if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; }
|
||||
try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; }
|
||||
return s_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>원본 스킬이 베기(경로) 이펙트를 켠 직후 훅 — 규칙에 맞으면 그 투사체에 수리검 러너를 붙인다.</summary>
|
||||
public static void Begin(ProjectileBase pb)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = Cfg; if (c.enabled == 0 || pb == null) return;
|
||||
if (c.skills != null && c.skills.Length > 0 && System.Array.IndexOf(c.skills, pb.GetType().Name) < 0) return;
|
||||
var pd = pb.Get_ProjectTileData(); int cls = pd != null && !DSUtil.CheckNull(pd.shooter) ? pd.shooter.Get_ID() : 0;
|
||||
if (c.classes != null && c.classes.Length > 0 && System.Array.IndexOf(c.classes, cls) < 0) return;
|
||||
ParticleSystem path = null;
|
||||
foreach (var ps in pb.GetComponentsInChildren<ParticleSystem>(true)) if (ps.name == c.layer) { path = ps; break; }
|
||||
if (path == null) { LastLog = "경로 층 없음 " + c.layer; return; }
|
||||
var run = pb.GetComponent<WLShurikenRiderRunner>(); if (run == null) run = pb.gameObject.AddComponent<WLShurikenRiderRunner>();
|
||||
run.Begin(path, c); Begun++;
|
||||
}
|
||||
catch (System.Exception ex) { LastLog = "실패 — " + ex.Message; }
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WLShurikenRiderRunner : MonoBehaviour
|
||||
{
|
||||
ParticleSystem _ps; WLShurikenRiderJson _c; ParticleSystem.Particle[] _buf = new ParticleSystem.Particle[256];
|
||||
readonly List<GameObject> _riders = new List<GameObject>(); readonly Dictionary<uint, int> _bySeed = new Dictionary<uint, int>();
|
||||
float _t0, _rim = 0.5f; bool _on;
|
||||
|
||||
public void Begin(ParticleSystem ps, WLShurikenRiderJson c)
|
||||
{
|
||||
_ps = ps; _c = c; _t0 = Time.time; _on = true; _bySeed.Clear();
|
||||
var r = ps.GetComponent<ParticleSystemRenderer>(); var m = r != null ? r.mesh : null;
|
||||
_rim = m != null ? Mathf.Max(m.bounds.extents.x, m.bounds.extents.y) : 0.5f; // 호 메시 반지름(입자 크기 1 기준)
|
||||
var p = Resources.Load<GameObject>(c.prefab);
|
||||
while (p != null && _riders.Count < c.maxRiders) { var g = Instantiate(p); g.SetActive(false); g.transform.localScale = Vector3.one * c.riderScale; _riders.Add(g); }
|
||||
if (p == null) WLShurikenRider.LastLog = "수리검 프리팹 없음 " + c.prefab;
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (!_on) return;
|
||||
if (_ps == null || !_ps.gameObject.activeInHierarchy || Time.time - _t0 > _c.maxSeconds) { Stop(); return; }
|
||||
int n = _ps.GetParticles(_buf); var alive = new HashSet<uint>(); int shown = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var p = _buf[i]; uint seed = p.randomSeed; if (_c.every > 1 && seed % (uint)_c.every != 0) continue;
|
||||
alive.Add(seed); int idx;
|
||||
if (!_bySeed.TryGetValue(seed, out idx)) { idx = FreeSlot(); if (idx < 0) continue; _bySeed[seed] = idx; }
|
||||
var g = _riders[idx]; bool fresh = !g.activeSelf; if (fresh) g.SetActive(true);
|
||||
var size = p.GetCurrentSize3D(_ps);
|
||||
var pos = p.position + Quaternion.Euler(p.rotation3D) * (Vector3.right * _rim * size.x * _c.rimFraction);
|
||||
var mv = pos - g.transform.position; // 투사체 이펙트라 진행 방향(앞 = +Z)으로 돌린다 — 꼬리가 지나온 쪽
|
||||
if (!fresh && mv.sqrMagnitude > 1e-6f) g.transform.rotation = Quaternion.LookRotation(mv);
|
||||
g.transform.position = pos;
|
||||
shown++;
|
||||
}
|
||||
var gone = new List<uint>(); foreach (var kv in _bySeed) if (!alive.Contains(kv.Key)) gone.Add(kv.Key);
|
||||
foreach (var s in gone) { _riders[_bySeed[s]].SetActive(false); _bySeed.Remove(s); }
|
||||
if (shown > WLShurikenRider.MaxShown) WLShurikenRider.MaxShown = shown;
|
||||
if (n == 0 && Time.time - _t0 > 0.3f) Stop();
|
||||
}
|
||||
|
||||
int FreeSlot() { for (int i = 0; i < _riders.Count; i++) if (!_bySeed.ContainsValue(i)) return i; return -1; }
|
||||
|
||||
void Stop() { _on = false; _bySeed.Clear(); foreach (var g in _riders) if (g != null) g.SetActive(false); WLShurikenRider.LastLog = "끝 · 최대 동시 " + WLShurikenRider.MaxShown; }
|
||||
void OnDisable() { Stop(); }
|
||||
void OnDestroy() { foreach (var g in _riders) if (g != null) Destroy(g); }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac34b727641b7c3468bb18d0899ded76
|
||||
Loading…
Reference in New Issue