Files
zeling_v2/Assets/_Game/Scripts/Editor/Skills/SkillHitBoxWizard.cs

128 lines
5.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO;
using UnityEditor;
using UnityEngine;
using BaseGames.Combat;
namespace BaseGames.Editor.Skills
{
/// <summary>
/// 向导:一键生成技能 HitBox PrefabW-11
/// 菜单BaseGames / Create / Skill HitBox Prefab
///
/// 生成路径规范Assets/_Game/Prefabs/Skills/SKL_{skillId}_HitBox.prefab
/// Prefab 结构(以 hitBoxCount=1 为例):
/// [SKL_{skillId}_HitBox] ← SkillHitBoxInstance (_hitBoxes 自动赋值)
/// └── [HitBox_0] ← PolygonCollider2D(IsTrigger) + HitBox, Layer=PlayerHitBox
/// </summary>
public class SkillHitBoxWizard : ScriptableWizard
{
private const string OutputFolder = "Assets/_Game/Prefabs/Skills";
[MenuItem("BaseGames/Create/Skill HitBox Prefab", priority = 201)]
public static void Open() =>
DisplayWizard<SkillHitBoxWizard>("Skill HitBox Prefab 向导", "创建");
[Tooltip("技能唯一 ID如 SkySlash。Prefab 将命名为 SKL_{skillId}_HitBox")]
public string skillId = "";
[Tooltip("多段伤害时可设置 >1每段一个 HitBox 子节点)")]
[Range(1, 4)]
public int hitBoxCount = 1;
// ── 向导回调 ──────────────────────────────────────────────────────────
private void OnWizardUpdate()
{
isValid = !string.IsNullOrWhiteSpace(skillId);
helpString = isValid
? $"将创建:{OutputFolder}/SKL_{skillId}_HitBox.prefab{hitBoxCount} 个 HitBox"
: "请输入 skillId技能唯一 ID如 SkySlash。";
}
private void OnWizardCreate()
{
if (string.IsNullOrWhiteSpace(skillId))
{
EditorUtility.DisplayDialog("错误", "skillId 不能为空。", "确认");
return;
}
string prefabName = $"SKL_{skillId}_HitBox";
string assetPath = $"{OutputFolder}/{prefabName}.prefab";
string fullPath = Path.Combine(
Path.GetDirectoryName(Application.dataPath)!,
assetPath.Replace('/', Path.DirectorySeparatorChar));
if (File.Exists(fullPath))
{
if (!EditorUtility.DisplayDialog("已存在",
$"{assetPath}\n\n该 Prefab 已存在,是否覆盖?",
"覆盖", "取消"))
return;
}
EditorScaffoldUtils.EnsureFolder(OutputFolder);
int hitBoxLayer = LayerMask.NameToLayer("PlayerHitBox");
if (hitBoxLayer < 0)
{
Debug.LogWarning("[SkillHitBoxWizard] 未找到 Physics Layer 'PlayerHitBox',子节点 Layer 将设为 Default。");
hitBoxLayer = 0;
}
// ── 构建 Prefab ────────────────────────────────────────────────
var root = new GameObject(prefabName);
var instance = root.AddComponent<SkillHitBoxInstance>();
var so = new SerializedObject(instance);
var hbRefs = new HitBox[hitBoxCount];
for (int i = 0; i < hitBoxCount; i++)
{
var child = new GameObject($"HitBox_{i}");
child.transform.SetParent(root.transform, false);
child.layer = hitBoxLayer;
// PolygonCollider2D 默认菱形1×0.5),策划在 Scene 中调整具体形状
var poly = child.AddComponent<PolygonCollider2D>();
poly.isTrigger = true;
poly.SetPath(0, new Vector2[]
{
new(-0.5f, -0.25f), new(0.5f, -0.25f),
new(0.5f, 0.25f), new(-0.5f, 0.25f),
});
hbRefs[i] = child.AddComponent<HitBox>();
}
// 将 HitBox[] 赋值给 _hitBoxes
var arrayProp = so.FindProperty("_hitBoxes");
if (arrayProp != null && arrayProp.isArray)
{
arrayProp.arraySize = hitBoxCount;
for (int i = 0; i < hitBoxCount; i++)
arrayProp.GetArrayElementAtIndex(i).objectReferenceValue = hbRefs[i];
so.ApplyModifiedPropertiesWithoutUndo();
}
else
{
Debug.LogWarning("[SkillHitBoxWizard] 未找到 SkillHitBoxInstance._hitBoxes 字段,请手动赋值。");
}
var prefab = PrefabUtility.SaveAsPrefabAsset(root, assetPath);
Object.DestroyImmediate(root);
AssetDatabase.Refresh();
if (prefab != null)
{
EditorScaffoldUtils.PingAndSelect(prefab);
Debug.Log($"[SkillHitBoxWizard] 已创建:{assetPath}");
}
else
{
Debug.LogError($"[SkillHitBoxWizard] Prefab 保存失败:{assetPath}");
}
}
}
}