Files
2026-07-13 11:44:25 +08:00

237 lines
6.9 KiB
C#
Raw Permalink 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.
#if UNITY_EDITOR && ENABLE_INPUT_SYSTEM
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
namespace XericLibrary.Runtime.Blueprint.Editor
{
/// <summary>
/// 蓝图 InputAction 模板生成器。
/// 右键 Project 窗口 → Xeric Library / Input Action Template / BlueprintAction
/// 即可创建预设 InputActionAsset,内含蓝图所有的 Actions 和绑定。
/// </summary>
public static class BlueprintInputActionTemplate
{
private const string MenuPath = "Assets/Create/Xeric Library/Input Action Template/BlueprintAction";
private const string DefaultFileName = "BlueprintActions";
[MenuItem(MenuPath, priority = 1100)]
public static void CreateBlueprintInputActionAsset()
{
var asset = ScriptableObject.CreateInstance<InputActionAsset>();
var map = asset.AddActionMap(BlueprintInputConstants.MapName);
var binding = InputBinding.MaskByGroup("Keyboard&Mouse");
var gamepadBinding = InputBinding.MaskByGroup("Gamepad");
// ── 指针位置 ──
map.AddAction(
BlueprintInputConstants.Point,
type: InputActionType.Value,
binding: "<Mouse>/position",
interactions: null,
processors: null,
groups: binding.ToString());
// ── 滚轮 ──
map.AddAction(
BlueprintInputConstants.ScrollWheel,
type: InputActionType.Value,
binding: "<Mouse>/scroll",
interactions: null,
processors: null,
groups: binding.ToString());
// ── 左键 ──
map.AddAction(
BlueprintInputConstants.LeftClick,
type: InputActionType.Button,
binding: "<Mouse>/leftButton",
interactions: null,
processors: null,
groups: binding.ToString());
// ── 右键 ──
map.AddAction(
BlueprintInputConstants.RightClick,
type: InputActionType.Button,
binding: "<Mouse>/rightButton",
interactions: null,
processors: null,
groups: binding.ToString());
// ── 中键 ──
map.AddAction(
BlueprintInputConstants.MiddleClick,
type: InputActionType.Button,
binding: "<Mouse>/middleButton",
interactions: null,
processors: null,
groups: binding.ToString());
// ── Shift ──
map.AddAction(
BlueprintInputConstants.Shift,
type: InputActionType.Button,
binding: "<Keyboard>/leftShift",
interactions: null,
processors: null,
groups: binding.ToString());
// ── Ctrl ──
map.AddAction(
BlueprintInputConstants.Ctrl,
type: InputActionType.Button,
binding: "<Keyboard>/leftCtrl",
interactions: null,
processors: null,
groups: binding.ToString());
// ── Alt ──
map.AddAction(
BlueprintInputConstants.Alt,
type: InputActionType.Button,
binding: "<Keyboard>/leftAlt",
interactions: null,
processors: null,
groups: binding.ToString());
// ── Pan(平移:方向键 + Shift+滚轮 → 水平, Alt+滚轮 → 垂直)──
var panAction = map.AddAction(
BlueprintInputConstants.Pan,
type: InputActionType.Value,
binding: null); // 多个 composite,需手动绑定
// 键盘方向键 Vector2
var kbCompositeIndex = panAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/upArrow")
.With("Down", "<Keyboard>/downArrow")
.With("Left", "<Keyboard>/leftArrow")
.With("Right", "<Keyboard>/rightArrow");
ApplyGroupToLastBindings(panAction, binding.ToString());
// 手柄左摇杆
panAction.AddCompositeBinding("2DVector")
.With("Up", "<Gamepad>/leftStick/up")
.With("Down", "<Gamepad>/leftStick/down")
.With("Left", "<Gamepad>/leftStick/left")
.With("Right", "<Gamepad>/leftStick/right");
ApplyGroupToLastBindings(panAction, gamepadBinding.ToString());
// ── Zoom(缩放:滚轮 + Ctrl热键)──
var zoomAction = map.AddAction(
BlueprintInputConstants.Zoom,
type: InputActionType.Value);
zoomAction.AddCompositeBinding("1DAxis")
.With("Positive", "<Mouse>/scroll/up")
.With("Negative", "<Mouse>/scroll/down");
ApplyGroupToLastBindings(zoomAction, binding.ToString());
// Ctrl 组合(多一层)
zoomAction.AddCompositeBinding("1DAxis")
.With("Positive", "<Keyboard>/ctrl")
.With("Negative", "<Keyboard>/ctrl");
ApplyGroupToLastBindings(zoomAction, binding.ToString());
// ── FocusHomeCtrl + H)──
map.AddAction(
BlueprintInputConstants.FocusHome,
type: InputActionType.Button,
binding: "<Keyboard>/h",
interactions: null,
processors: null,
groups: binding.ToString());
// ── UndoCtrl + Z)──
map.AddAction(
BlueprintInputConstants.Undo,
type: InputActionType.Button,
binding: "<Keyboard>/z",
interactions: null,
processors: null,
groups: binding.ToString());
// ── RedoCtrl + Y)──
map.AddAction(
BlueprintInputConstants.Redo,
type: InputActionType.Button,
binding: "<Keyboard>/y",
interactions: null,
processors: null,
groups: binding.ToString());
// ── NavigateParentTab)──
map.AddAction(
BlueprintInputConstants.NavigateParent,
type: InputActionType.Button,
binding: "<Keyboard>/tab",
interactions: null,
processors: null,
groups: binding.ToString());
// 保存资产 —— .inputactions 文件需以 JSON 文本形式写入,
// 再由 AssetDatabase.ImportAsset 触发 InputActionImporter 解析。
string folderPath = GetSelectedFolderPath();
string assetPath = AssetDatabase.GenerateUniqueAssetPath(
Path.Combine(folderPath, $"{DefaultFileName}.inputactions"));
string json = asset.ToJson();
System.IO.File.WriteAllText(assetPath, json);
AssetDatabase.ImportAsset(assetPath);
AssetDatabase.SaveAssets();
var imported = AssetDatabase.LoadAssetAtPath<InputActionAsset>(assetPath);
EditorGUIUtility.PingObject(imported);
Debug.Log($"[Blueprint] InputAction 模板已创建: {assetPath}");
}
/// <summary>
/// 将 action 最后一个 binding(及所有 composite part)的 groups 设为指定值。
/// </summary>
private static void ApplyGroupToLastBindings(InputAction action, string groups)
{
int count = action.bindings.Count;
int compositeStart = -1;
for (int i = count - 1; i >= 0; i--)
{
if (action.bindings[i].isComposite)
{
compositeStart = i;
break;
}
}
if (compositeStart < 0) return;
for (int i = compositeStart; i < count; i++)
action.ChangeBinding(i).WithGroup(groups);
}
/// <summary>
/// 获取当前选中的 Project 窗口文件夹路径。
/// </summary>
private static string GetSelectedFolderPath()
{
string path = "Assets";
var selected = Selection.activeObject;
if (selected != null)
{
string assetPath = AssetDatabase.GetAssetPath(selected);
if (!string.IsNullOrEmpty(assetPath))
{
if (AssetDatabase.IsValidFolder(assetPath))
return assetPath;
return Path.GetDirectoryName(assetPath);
}
}
return path;
}
}
}
#endif