摄像机区域的架构改动
This commit is contained in:
181
Assets/_Game/Scripts/Editor/Combat/WeaponHitBoxWizard.cs
Normal file
181
Assets/_Game/Scripts/Editor/Combat/WeaponHitBoxWizard.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using BaseGames.Combat;
|
||||
using BaseGames.Player;
|
||||
|
||||
namespace BaseGames.Editor.Combat
|
||||
{
|
||||
/// <summary>
|
||||
/// 向导:一键生成武器 HitBox Prefab(W-10)。
|
||||
/// 菜单:BaseGames / Create / Weapon HitBox Prefab
|
||||
///
|
||||
/// 生成路径规范:Assets/_Game/Prefabs/Weapons/WPN_{weaponId}_HitBox.prefab
|
||||
/// Prefab 结构:
|
||||
/// [WPN_{weaponId}_HitBox] ← WeaponHitBoxInstance
|
||||
/// ├── [HitBox_Ground] ← Collider2D(IsTrigger, 形状可选) + HitBox, Layer=PlayerHitBox
|
||||
/// ├── [HitBox_Up]
|
||||
/// ├── [HitBox_Down]
|
||||
/// └── [HitBox_Air]
|
||||
/// </summary>
|
||||
public class WeaponHitBoxWizard : ScriptableWizard
|
||||
{
|
||||
private const string OutputFolder = "Assets/_Game/Prefabs/Weapons";
|
||||
|
||||
/// <summary>每个方向可选的 Collider 形状。</summary>
|
||||
public enum ColliderShape
|
||||
{
|
||||
[Tooltip("BoxCollider2D — 矩形,适合水平/垂直扫击")]
|
||||
Box,
|
||||
[Tooltip("CapsuleCollider2D — 胶囊体,适合刺击或弧形")]
|
||||
Capsule,
|
||||
[Tooltip("PolygonCollider2D(菱形默认点)— 适合不规则斩击")]
|
||||
Polygon,
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Create/Weapon HitBox Prefab", priority = 200)]
|
||||
public static void Open() =>
|
||||
DisplayWizard<WeaponHitBoxWizard>("Weapon HitBox Prefab 向导", "创建");
|
||||
|
||||
[Tooltip("武器唯一 ID,如 SkyBlade。Prefab 将命名为 WPN_{weaponId}_HitBox")]
|
||||
public string weaponId = "";
|
||||
|
||||
[Header("包含哪些攻击方向")]
|
||||
public bool includeGround = true;
|
||||
public bool includeUp = true;
|
||||
public bool includeDown = true;
|
||||
public bool includeAir = true;
|
||||
|
||||
[Header("每个方向的 Collider 形状")]
|
||||
[Tooltip("Ground / 落地攻击的碰撞体形状")]
|
||||
public ColliderShape groundShape = ColliderShape.Box;
|
||||
[Tooltip("Up / 上挑攻击的碰撞体形状")]
|
||||
public ColliderShape upShape = ColliderShape.Capsule;
|
||||
[Tooltip("Down / 下砸攻击的碰撞体形状")]
|
||||
public ColliderShape downShape = ColliderShape.Box;
|
||||
[Tooltip("Air / 空中攻击的碰撞体形状")]
|
||||
public ColliderShape airShape = ColliderShape.Capsule;
|
||||
|
||||
// ── 向导回调 ──────────────────────────────────────────────────────────
|
||||
|
||||
private void OnWizardUpdate()
|
||||
{
|
||||
isValid = !string.IsNullOrWhiteSpace(weaponId);
|
||||
helpString = isValid
|
||||
? $"将创建:{OutputFolder}/WPN_{weaponId}_HitBox.prefab"
|
||||
: "请输入 weaponId(武器唯一 ID,如 SkyBlade)。";
|
||||
}
|
||||
|
||||
private void OnWizardCreate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(weaponId))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "weaponId 不能为空。", "确认");
|
||||
return;
|
||||
}
|
||||
|
||||
string prefabName = $"WPN_{weaponId}_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("[WeaponHitBoxWizard] 未找到 Physics Layer 'PlayerHitBox',子节点 Layer 将设为 Default。");
|
||||
hitBoxLayer = 0;
|
||||
}
|
||||
|
||||
// ── 构建 Prefab ────────────────────────────────────────────────
|
||||
var root = new GameObject(prefabName);
|
||||
var instance = root.AddComponent<WeaponHitBoxInstance>();
|
||||
var so = new SerializedObject(instance);
|
||||
|
||||
void AddDirection(bool enabled, string nodeName, string fieldName, ColliderShape shape)
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
var child = new GameObject(nodeName);
|
||||
child.transform.SetParent(root.transform, false);
|
||||
child.layer = hitBoxLayer;
|
||||
|
||||
AddCollider(child, shape);
|
||||
|
||||
var hb = child.AddComponent<HitBox>();
|
||||
var prop = so.FindProperty(fieldName);
|
||||
if (prop != null)
|
||||
prop.objectReferenceValue = hb;
|
||||
}
|
||||
|
||||
AddDirection(includeGround, "HitBox_Ground", "_hitBoxGround", groundShape);
|
||||
AddDirection(includeUp, "HitBox_Up", "_hitBoxUp", upShape);
|
||||
AddDirection(includeDown, "HitBox_Down", "_hitBoxDown", downShape);
|
||||
AddDirection(includeAir, "HitBox_Air", "_hitBoxAir", airShape);
|
||||
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(root, assetPath);
|
||||
Object.DestroyImmediate(root);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
if (prefab != null)
|
||||
{
|
||||
EditorScaffoldUtils.PingAndSelect(prefab);
|
||||
Debug.Log($"[WeaponHitBoxWizard] 已创建:{assetPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[WeaponHitBoxWizard] Prefab 保存失败:{assetPath}");
|
||||
}
|
||||
}
|
||||
|
||||
// ── 辅助:按形状添加 2D 碰撞体 ────────────────────────────────────────
|
||||
|
||||
private static void AddCollider(GameObject go, ColliderShape shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case ColliderShape.Box:
|
||||
{
|
||||
var c = go.AddComponent<BoxCollider2D>();
|
||||
c.isTrigger = true;
|
||||
c.size = new Vector2(1f, 0.5f);
|
||||
break;
|
||||
}
|
||||
case ColliderShape.Capsule:
|
||||
{
|
||||
var c = go.AddComponent<CapsuleCollider2D>();
|
||||
c.isTrigger = true;
|
||||
c.size = new Vector2(0.5f, 1f);
|
||||
break;
|
||||
}
|
||||
case ColliderShape.Polygon:
|
||||
{
|
||||
var c = go.AddComponent<PolygonCollider2D>();
|
||||
c.isTrigger = true;
|
||||
// 默认菱形点(0.5 × 0.5 单位)
|
||||
c.SetPath(0, new Vector2[]
|
||||
{
|
||||
new( 0f, 0.3f),
|
||||
new( 0.5f, 0f ),
|
||||
new( 0f, -0.3f),
|
||||
new(-0.5f, 0f ),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user