Unity MyFramework 用法说明(六):使用 FrameSystem 管理全局快捷键

前面已经完成了 UI 和业务流程的基本使用。这一篇以实际项目中的 GameHotKeyManager 为例,介绍如何用 FrameSystem 统一管理快捷键。

项目地址:

github.com/ZHOURUIH/My...

一、为什么快捷键适合使用 FrameSystem

快捷键系统需要长期存在,并在每帧检测输入。它不属于某个界面,也不属于某个 SceneProcedure,因此适合继承 FrameSystem

实际项目中的 GameHotKeyManager 同时管理:

bash 复制代码
移动、技能和普通攻击
快捷栏物品
拾取和 NPC 操作
召唤兽控制
界面打开和关闭

本篇只保留 UI 快捷键部分,方便理解基本用法。

二、定义快捷键功能

快捷键不要直接用 KeyCode 作为业务标识,而是先定义功能编号:

bash 复制代码
public class HOT_KEY_ACTION
{
	public const int NONE = 0;
	public const int OPEN_MYSLEF_VIEW = 1001;
	public const int OPEN_BACKPACK = 1002;
	public const int OPEN_FRIEND = 1003;
	public const int OPEN_GAME_SETTING = 1010;
	public const int OPEN_MISSION_PANEL = 1011;
}

业务逻辑检测的是 OPEN_BACKPACK,而不是直接检测 KeyCode.Keypad1

这样后续修改按键,或者允许玩家自定义键位时,不需要修改具体业务代码。

三、创建 GameHotKeyManager

创建文件:

bash 复制代码
Assets/Scripts/HotFix/GameHotKeyManager/GameHotKeyManager.cs

基础结构如下:

bash 复制代码
using System;
using System.Collections.Generic;
using UnityEngine;
using static GBR;

public class GameHotKeyManager : FrameSystem
{
	protected Dictionary<int, Type> mKeyToUI = new(); // 快捷键功能到界面类型
	protected Dictionary<Type, int> mUIToKey = new(); // 界面类型到快捷键功能

	public override void init()
	{
		base.init();

		setUIHotKey<UIMyselfView>(
			HOT_KEY_ACTION.OPEN_MYSLEF_VIEW,
			KeyCode.Keypad0,
			"角色面板");

		setUIHotKey<UIBackpack>(
			HOT_KEY_ACTION.OPEN_BACKPACK,
			KeyCode.Keypad1,
			"背包");

		setUIHotKey<UIFriend>(
			HOT_KEY_ACTION.OPEN_FRIEND,
			KeyCode.Keypad2,
			"好友");

		setUIHotKey<UIGameSetting>(
			HOT_KEY_ACTION.OPEN_GAME_SETTING,
			KeyCode.Keypad9,
			"设置");

		setUIHotKey<UIMissionPanel>(
			HOT_KEY_ACTION.OPEN_MISSION_PANEL,
			KeyCode.KeypadPeriod,
			"任务");
	}
}

这里没有直接打开界面,只是建立三者之间的关系:

bash 复制代码
快捷键功能编号
    ↕
默认 KeyCode
    ↕
LayoutScript 类型

四、注册普通快捷键

先提供一个普通快捷键注册函数:

bash 复制代码
protected void setHotKey(int mapping, KeyCode key, string name)
{
	mKeyMappingSystem.setKeyMapping(mapping, key, name);
	mKeyMappingSystem.setDefaultKeyMapping(mapping, key);
}

两次设置的用途不同:

bash 复制代码
setKeyMapping           设置当前使用的按键
setDefaultKeyMapping    保存默认按键

保存默认按键后,设置界面可以提供"恢复默认键位"功能。

五、注册 UI 快捷键

UI 快捷键在普通快捷键基础上,还要记录对应的界面类型:

bash 复制代码
protected void setUIHotKey<T>(int mapping, KeyCode key, string name)
	where T : LayoutScript
{
	setHotKey(mapping, key, name);

	mKeyToUI.Add(mapping, typeof(T));
	mUIToKey.Add(typeof(T), mapping);
}

mKeyToUI 用于按下快捷键后查找界面。

mUIToKey 用于界面查询自己的快捷键名称。

六、每帧检测快捷键

重写 update,统一处理界面的打开和隐藏:

bash 复制代码
public override void update(float elapsedTime)
{
	base.update(elapsedTime);

	if (!FrameUtility.isWindows())
	{
		return;
	}

	foreach (var item in mKeyToUI)
	{
		if (!mKeyMappingSystem.isMappingKeyCurrentDown(item.Key))
		{
			continue;
		}

		GameLayout layout = mLayoutManager.getLayout(item.Value);
		if (layout == null || !layout.isVisible())
		{
			LT.LOAD(item.Value);
		}
		else
		{
			LT.HIDE(item.Value);
		}
	}
}

处理规则很简单:

bash 复制代码
界面未加载       加载并显示
界面已经隐藏     重新显示
界面正在显示     隐藏界面

这里使用快捷键功能编号检测输入:

bash 复制代码
mKeyMappingSystem.isMappingKeyCurrentDown(item.Key)

而不是:

bash 复制代码
Input.GetKeyDown(KeyCode.Keypad1)

因此玩家修改键位以后,这段逻辑不需要变化。

七、让界面显示自己的快捷键

为界面提供一个查询函数:

bash 复制代码
public string getKeyName(Type layoutType)
{
	int mapping = mUIToKey.get(layoutType);
	return mKeyMappingSystem.getKeyMappingName(mapping);
}

界面中可以直接显示当前快捷键:

bash 复制代码
using static GBR;

public class UIBackpack : LayoutScript
{
	protected myUGUIText mHotKey;

	public override void onGameState()
	{
		base.onGameState();

		string keyName = mGameHotKeyILRManager.getKeyName(GetType());
		mHotKey.setText("(" + keyName + ")");
	}
}

如果玩家修改了背包快捷键,下次打开背包时显示的按键名称也会同步变化。

八、添加全局引用

GBR 中添加管理器引用:

bash 复制代码
public class GBR
{
	public static GameHotKeyManager mGameHotKeyILRManager;

	// 其他 FrameSystem
}

需要使用它的代码只需添加:

bash 复制代码
using static GBR;

然后通过 mGameHotKeyILRManager 访问。

九、注册 FrameSystem

打开:

bash 复制代码
Assets/Scripts/HotFix/Game/GameHotFix.cs

initFrameSystem 中注册:

bash 复制代码
protected override void initFrameSystem()
{
	registeFrameSystem<GameHotKeyManager>((com) =>
	{
		mGameHotKeyILRManager = com;
	});
}

注册完成后,框架会自动调用它的:

bash 复制代码
init
lateInit
update
willDestroy
destroy

不需要创建单例 MonoBehaviour,也不需要单独编写一个节点负责调用 Update

十、继续扩展其他快捷键

普通游戏操作也可以使用同一套映射:

bash 复制代码
public override void init()
{
	base.init();

	setHotKey(HOT_KEY_ACTION.MOVE_LEFT, KeyCode.A, "向左移动");
	setHotKey(HOT_KEY_ACTION.MOVE_RIGHT, KeyCode.D, "向右移动");
	setHotKey(HOT_KEY_ACTION.PICK, KeyCode.X, "拾取");
	setHotKey(HOT_KEY_ACTION.NORMAL_ATTACK, KeyCode.Z, "普攻");

	setUIHotKey<UIBackpack>(
		HOT_KEY_ACTION.OPEN_BACKPACK,
		KeyCode.Keypad1,
		"背包");
}

检测拾取快捷键:

bash 复制代码
if (mKeyMappingSystem.isMappingKeyCurrentDown(HOT_KEY_ACTION.PICK))
{
	CmdGlobalPickGold.execute(
		mObjectItemManager.getItemInRange(
			getMyself().getPosition(),
			PICK_RANGE));
}

UI 快捷键和战斗快捷键共用 KeyMappingSystem,但具体业务仍然可以分别处理。

十一、总结

创建全局快捷键系统的步骤是:

这套设计把"业务功能"和"实际按键"分离开来,既能统一管理所有快捷键,也方便后续实现键位修改、恢复默认设置和快捷键文本显示。

相关推荐
_zhourui_h_21 小时前
Unity MyFramework 用法说明(五):使用 GameScene 和 SceneProcedure 管理业务流程
unity3d·游戏开发
_zhourui_h_1 天前
Unity MyFramework 用法说明(四):使用 UGUIGenerator 自动生成 UI 代码
unity3d
SmalBox2 天前
【节点】[EvaluateFoamData节点]原理解析与实际应用
unity3d·游戏开发·图形学
_ZHOURUI_H_2 天前
MyFramework: 同样是 Unity 游戏开发框架,和 HTFramework 的设计取向有什么不同?(下)
unity·游戏引擎·游戏开发·游戏ui·手游开发
SmalBox3 天前
【节点】[ComputeVertexPosition节点]原理解析与实际应用
unity3d·游戏开发·图形学
孟无岐3 天前
LayaAir IDE 插件开发入门:用 TypeScript 给编辑器加一个自己的面板
typescript·游戏开发·工程化·编辑器扩展·layaair·ide 插件
SmalBox4 天前
【节点】[ScleraUVLocation节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox5 天前
【节点】[ScleraLimbalRing节点]原理解析与实际应用
unity3d·游戏开发·图形学
UWA5 天前
资源回收“两头堵”:RUUA调了会卡,不调内存又涨
性能优化·memory·游戏开发