游戏UI右键菜单的实现优化

  RPG类端游里面右键菜单的应用场景是随处可见,比如好友,聊天栏玩家名字连接,队友,帮会成员等,不同的应用场景,右键菜单的功能项可能不同,比如:

在这里插入图片描述
  我参与过的一个项目的右键菜单是一个大杂烩的实现方案,有一张巨大的表,大概是这样的:

local ContextMenuRightClick =
{
	[1]={name = "加为好友", userdata = nil, func = "AddFriend", color = red},
	[2]={name = "申请组队", userdata = nil, func = "TeamRequest", color = yellow},
	[3]={name = "邀请组队", userdata = nil, func = "TeamInvited", color = blue},
	...
	[98]={name = "观察角色", userdata = nil, func = "ViewPlayer", color = red},
	[99]={name = "拉黑", userdata = nil, func = "Addblack", color = yellow},
	[100]={name = "跟随", userdata = nil, func = "TailFollow", color = blue},
	...
	[120]={name = "发送邮件", userdata = nil, func = "SendMail", color = blue},
	[121]={name = "私聊", userdata = nil, func = "ChatWith", color = yellow},
	...
}	

  接着有一个巨大的函数来统一处理右键菜单的逻辑:

-- playerid:目标玩家的id
-- pos:右键菜单在哪里显示
function ShowMenuForRightClick(playerid, pos)
    -- SelectedItems中的key是ContextMenuRightClick表里面的索引,value取01,表示是否显示对应的菜单项
	local SelectedItems = 
	{
		[1] = 0,
		[2] = 0,
		...
		[100] = 0,
		[101] = 0,
		...
		[121] = 0,
	}
	...
	-- 以下几乎是所有相关系统的各种复杂的判断逻辑,以检验各菜单功能项是否显示
	if 可以和他组队 then
		SelectedItems[*] = 1
    else
		SelectedItems[*] = 0
    end
    ...
	if 可以加他好友 then
		SelectedItems[*] = 1
    else
		SelectedItems[*] = 0
    end
    ...
    ShowContextMenu(pos, SelectedItems) -- 显示菜单
end

  然后在各应用场景,调用这个函数ShowMenuForRightClick(playerid, pos)

  该方案有以下弊端:

  ✘ 将所有应用场景中的右键菜单集中在一个庞大的核心函数中实现,各种不相干的业务逻辑混合在一起:队伍判断,帮会判断,师徒判断,好友判断等等,构建菜单的逻辑和应用层的业务逻辑紧密耦合在一起;

  ✘  这个核心函数会继续扩展到成千上万行;

  ✘  无法差异化处理不同应用场景的不同需求,比如有的场景中只需要显示业务相关的功能菜单,而不是无条件显示所有可能用到的功能菜单;

  ✘  参数固定为playerid,太过僵化;

  ✘  支持多级菜单比较困难;

  ✘  为一个新场景显示右键菜单,开发时间较长,先找到这个巨大的函数,然后找到具体判断逻辑的地方,小心翼翼地配置SelectedItems表;

  ✘  维护成本高,冗余,如果某个菜单项废弃不用了,则这个菜单项的key得保留,不能被新的功能项复用。

  我在第三次使用这个右键菜单系统时实在忍无可忍,自己动手撸了一个右键菜单的实现。我想象中的右键菜单是这样的:

在这里插入图片描述
  这是好友头像的右键菜单,很自然地,我在撸代码时,想这么配置好友菜单:

FriendMenu =
{
	{name = "申请组队", color = yellow, func = "TeamRequest", check = "CanTeamTo"},
	{name = "邀请组队", color = yellow, func = "TeamInvited", check = "CanTeamIn"},
	{name = "私   聊", color = blue, func = "ChatWith"},
	{name = "拉   黑", color = red, func = "Addblack"},
	{name = "移   入", color = green,
		func = -- 点击“移入”弹出二级菜单,这个功能由UI的菜单系统支持,所以func可以直接配置为一个表
	    {
	  	    {name = "同学", color = blue, func = "Move2Classmate"},  -- 同学分组
	  	    {name = "同事", color = yellow, func = "Move2Colleague"},  -- 同事分组
	    }
	}
}

  配置表中的func字段是点击菜单的回调函数,如果菜单项有子菜单,则func是一个含有子菜单的表,这样的菜单项点击没有实际意义,仅仅是展开或隐藏子菜单,这个功能一般由UI系统(比如CEGUI)自带的功能支持,子表的结构和自身的结构完全相同,构成递归嵌套的多级菜单。
  check字段是一个过滤函数,返回true和false,用来决定这个功能项是否应该显示出来。比如当右键某个好友时,他已经在别的队伍里了,是无法邀请他重新组队的,则CanTeamIn应该返回false,那么“邀请组队”功能项就可以不显示出来;而我还是可以申请组队进入他的队伍,CanTeamTo应该返回true,那么“申请组队”功能项就应该显示出来。

  首先针对这个配置表,写一个构建菜单的函数(为了支持子菜单,需要递归):

-- menu:菜单的UI控件对象
-- menuItems:菜单的功能项
-- ...:各应用场景提供的额外参数,在回调func或check时,传入
function MakeMenuTree(menu, menuItems, ...)
    for key, value in menuItems do
        local n = key
        local item = value
        if not item.check or _G[item.check](arg, item) then -- 如果该菜单项需要显示
            if item.name ~= nil and item.name ~= "" then
                local menuItem = nil -- 菜单的UI控件对象
                if gGuiWindowMgr:isWindowPresent(menu:GetName()) then
                    menuItem = gGuiWindowMgr:getWindow(menu:GetName())
                else
                    menuItem = gGuiWindowMgr:createWindow("Look/MenuItem", menu:GetName())
                end                
                -- menu:AddItem检测功能项是否有子菜单
                if type(item.func) == 'table' then
                    local subMenu = Menu:Create(nil) -- 子菜单的位置不用指定
                    menuItem:setPopupMenu(subMenu:GetMenu())
                    MakeMenuTree(subMenu, item.func, unpack(arg)) -- 递归子菜单
                else
	                -- 回调函数的头两个参数是UI系统的菜单项对象和鼠标点击事件对象,以支持更精细的控制
                    menuItem:subscribe("Clicked",
                                      function(e) _G[item.func](menuItem, e, arg) end)
                end
                menuItem:setText(item.name) -- 功能名
                menuItem:setProperty("NormalTextColour", item.color) -- 颜色
                menu:AddItem(menuItem)
            end
        end
    end
end

  然后提供一个供各个应用场景调用的接口:

-- pos:右键菜单在哪里显示
-- menuItems:菜单项配置表
-- ...:各应用场景提供自己需要的参数,在回调func或check时,传入
function ShowRightClickMenu(pos, menuItems, ...)    
    if table.getn(menuItems) > 0 then
        local menu = Menu:Create(pos)
        MakeMenuTree(menu, menuItems, unpack(arg))
        menu:Show()
    end
end

各应用场景配置好自己的右键菜单(表),在右键点击时,用位置,配置的菜单表以及额外的参数(比如角色id,帮会id之类的)调用ShowRightClickMenu即可,例如好友右键菜单:ShowRightClickMenu(pos, FriendMenu, playerid)

  就是这么简单!原方案的缺陷统统没有了,比较而言,新方案有了以下几个优点:

  ✔  核心函数极为简单,菜单的构建独立于应用层的业务逻辑,只负责构建右键菜单树;

  ✔  无论有多少应用场景,核心函数不用再修改了,代码就这么几十行;

  ✔  各应用场景独立配置各自的右键菜单,颜色、过滤,都可以差异化定制;

  ✔  配置结构与显示布局基本对应,“所见即所得”;

  ✔  可灵活传参;

  ✔  轻松支持多级菜单;

  ✔  为一个新场景显示右键菜单,几分钟搞定,没有需要耗费脑力去额外理解的东西;

  ✔  维护成本可以忽略不计

  事实上,撸出这个右键菜单机制后,客户端代码中上百处的原右键菜单很快都切换到新方案,旧的方案慢慢被束之高阁,无人问津了。

  本文核心就两个字:解耦!除此以外,也没什么了。

### 回答1: 要优化Zabbix的UI界面,可以从以下几个方面着手: 1. 界面布局优化:重新设计和调整界面的布局,让主要的功能和操作更加易于使用和访问。可以考虑采用响应式设计,使界面能够适应不同大小的屏幕和设备。 2. 用户体验改进:提高用户界面的交互性和友好性,使用户能够更快速、方便地完成操作。可以减少不必要的点击和步骤,优化表单填写和选择的方式,引入自动补全和预填功能等。 3. 数据可视化:通过图表、图形和仪表盘等方式,将监控数据以直观形式展示,帮助用户更轻松地理解和分析数据。可以支持自定义报表和图表样式,满足不同用户的需求。 4. 主题和样式定制:允许用户根据自己的喜好和需求,自定义Zabbix的界面主题和样式。可以提供多种预设的主题选择,或者支持用户导入自定义的主题样式。 5. 模块化设计:将界面划分为多个模块,每个模块负责不同的功能和任务。通过模块化设计,可以更方便地扩展和定制界面,使用户能够根据自己的需求自由选择需要的功能模块。 6. 响应速度优化:通过优化代码和改进数据查询和加载方式,提高界面的响应速度和性能。可以采用异步加载和局部刷新等技术,减少不必要的数据传输和页面刷新,提升用户体验。 通过以上这些优化措施,可以使Zabbix的UI界面更加易用、美观和高效,提升用户的工作效率和满意度。同时,还应不断收集用户反馈,进行改进和升级,以适应不断变化的需求和技术发展。 ### 回答2: 要优化Zabbix的UI界面,可以从以下几个方面进行改进: 1. 提升用户体验:简化界面布局,减少冗余信息,使得用户能够更快捷地找到需要的功能和信息。增加各类操作的按钮和快捷入口,方便用户进行常用操作。 2. 增加可配置性:提供更多的界面配置选项,使得用户能够根据自己的需求进行个性化设置。例如,可以增加可拖拽的小组件,用户可以根据自己的偏好将常用的监控项和图表放置在合适的位置。 3. 支持自定义主题:提供不同的主题选择,让用户可以根据自己的审美选择适合自己的UI风格,提升界面的美观度。 4. 增加可视化功能:在监控项和图表展示方面,加入更多的图表类型和可视化效果,例如折线图、柱状图、饼图等,让用户能够更直观地了解和分析监控数据。 5. 提供更高效的操作方式:引入快捷键、右键菜单等操作方式,提高用户操作的效率和便捷性。 6. 提供更多的定制化选项:允许用户自定义仪表盘和报表的内容和布局,方便用户根据自己的需求进行个性化展示。 通过以上的优化措施,可以让Zabbix的UI界面更加直观、美观,并提高用户的使用体验和工作效率。 ### 回答3: 要优化Zabbix的UI界面,可以采取以下措施: 1. 界面布局优化:通过调整布局,使得不同功能和模块更加清晰、易于理解和操作。可以根据用户使用的频率和重要性对界面元素进行重新排序和分组,以提高用户的使用效率。 2. 界面美化:改善界面的视觉效果,优化颜色、字体、图标等设计元素,使整体界面更加美观、舒适、符合用户的审美。可以采用现代化的设计风格,提供更加直观、简洁的界面。 3. 响应式设计:对于不同的屏幕尺寸和设备,应该自适应地调整界面布局和元素大小,以确保用户在不同设备上都能有良好的使用体验。可以使用响应式设计技术来实现这一点。 4. 自定义界面:提供一些自定义选项,让用户根据自己的需求和喜好来调整界面的外观和布局。例如,用户可以自定义模块的显示和隐藏、界面颜色主题等。 5. 快捷操作:在界面中加入一些常用操作的快捷方式,以减少用户的操作步骤和时间。例如,可以加入一键刷新、一键搜索等功能,方便用户快速完成操作。 6. 清晰的反馈和提示:在界面中给出清晰明确的反馈和提示信息,帮助用户正确理解和使用功能。例如,通过图标、颜色、文字等方式来表示状态、进度和错误信息。 通过以上优化措施,可以提升Zabbix的UI界面的易用性、美观性和用户体验,从而更好地满足用户的需求和期望。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值