让客户端拥有一个独一无二的皮肤——Mudlet UI 设计(一)

简介

UI(User Interface)作为一款软件中最直接与用户产生交互的组成,它的好坏、美丑时刻都对其使用者产生着或多或少的影响。而对于 MUD 这类游戏客户端,一款理想的、布局合理的、契合游戏主题的操作界面更能最大限度的辅助玩家,带给玩家更优秀的游戏体验。

目前主流的 MUD 客户端还是有很多的,各有优劣,在此就不作赘述。而其中允许玩家自定义操作界面并能提供丰富的接口函数以实现界面设计的非 Mudlet 莫属。

先来看看 Mudlet 的 UI 效果是什么样的,这里从 Mudlet 官方论坛中,选取了部分由外国玩家们实现的自定义界面。

比如这样的:file 或者这样的:file

概念

Mudlet 中的界面布局管理器被称作Geyser,它提供了多种元素的定义与编排函数以简化玩家的设计操作。

这些元素包括:

  • Container 一种不可见的布局对象,用于分割屏幕,调整界面元素的位置与分布
  • Label 用于放置图片或格式化文本的载体
  • MiniConsole 拥有更丰富的文本处理能力的小型窗口
  • UserWindow 拥有MiniConsole的所有功能,同时还可在其中嵌套其他如LabelsMiniConsoleGaugesMappers等元素
  • CommandLine 可用于创建自定义的输入栏,包括嵌套在MiniConsoleUserWindow中的附属栏位,或位于主窗体中的扩展输入栏
  • Gauge 用于创建血条,体力条等具有比例属性会伸缩变化的度量对象
  • HBox/VBox 特殊的容器对象,位于其中的元素将被水平或垂直对齐
  • Adjustable.Container 可调节大小并随意拖动位置的容器对象
  • Mapper 小地图窗口

布局与准备

接下来我们将尝试一步步设计自己的界面。首先,我们需要明确 Mudlet 有哪些区域,而我们即将设计的自定义界面位于哪个区域,又准备进一步规划哪些区域。

如图,我们将 Mudlet 先粗略的拆分为按钮栏、指令输入栏、功能状态栏以及最大最主要的输出显示区,而我们的自定义界面设计将主要在主显示区中实现。 file

首先,在 Mudlet 的脚本区中创建一个名为UI的脚本对象,并在其中进行初始化:

ui = ui or {}
ui.image = ui.image or getMudletHomeDir() .. "/images/"

这里定义了一个名为ui.image的变量,并将所有之后会用到的图像文件放到该路径所对应的目录下。

界面规划

先将显示区分割成如图几部分区域 file

  • 绿***域 - 计划放置一些功能按钮,角色基本信息甚至头像
  • 白***域 - 主要是放置游戏的标题、副标题等内容
  • 蓝***域 - 将作为小地图区域,可以结合地图功能显示角色当前位置和周边情况等信息
  • 红***域 - 准备作为游戏静态信息显示栏,比如聊天、技能、装备等不希望随主窗口内容滚动而被刷屏的信息

代码实现

调整主窗体的大小

主窗体主要用于显示从 MUD 服务器接收到的内容,其默认大小完全覆盖了屏幕中央的显示区版面,我们需要从中挤出一部分版面用于排布我们将要创建的元素。事实上,由于如今屏幕尺寸的增大、像素的增高,MUD 并不需要如此巨大的版面用于单纯的滚动内容显示,我们有足够的屏幕空间在满足摆放自定义元素的情况下仍然保证理想的 MUD 内容阅读效果。

function ui.setBorder() -- 设置输出显示栏边界
    -- 为了适应不同屏幕的尺寸与像素设置,我们依据百分比自动计算出适应的窗口边界值
    -- 获取主窗体尺寸。
    ui.main_width,ui.main_height = getMainWindowSize()

    -- 主窗体与顶部(按钮栏)的距离,这里将被用于放置游戏标题一类的横幅,高度不能设的太小
    ui.main_border_top = math.ceil(ui.main_height * 0.15)

    -- 主窗体与底部(指令栏)的距离
    ui.main_border_bottom = 0

    -- 主窗体与屏幕左边界的距离
    ui.main_border_left = math.ceil(ui.main_width * 0.1)

    -- 主窗体与屏幕右边界的距离
    ui.main_border_right = math.ceil(ui.main_width * 0.3)

    -- 设置主窗体边界
    setBorderSizes(
        ui.main_border_top,
        ui.main_border_right,
        ui.main_border_bottom,
        ui.main_border_left
    )
end

创建布局容器

接下来我们需要跟进之前的布局规划,为每个区域创建 Container,以作为后续元素添加的载体。

function ui.setLayout() -- 设置窗口布局
    -- 创建主容器
    main_container = Geyser.Container:new({
      name = "main_container",      -- 容器名
      x = 0, y = 0,                 -- 容器位置(以矩形左上角作为参照)
      width = "100%",               -- 容器宽度,可以用百分比表示也可以用数字代表像素位
      height = "100%",              -- 容器高度
    })

    -- 创建地图容器
    map_container = Geyser.Container:new({
      name = "map_container",
      x = ui.main_width - ui.main_border_right, y = 0,
      width = ui.main_border_right,
      height = "40%",
    }, main_container)

    -- 创建信息容器
    info_container = Geyser.Container:new({
      name = "info_container",
      x = ui.main_width - ui.main_border_right, y = "-58%",
      width = ui.main_border_right,
      height = "58%",
    }, main_container)
end

设置背景贴图

因为容器是不可见的,它只是一个载体,用来限定其中元素的显示边界,所以无法填充颜色或者图片。要实现背景色或墙纸的功能,我们需要在容器中放入其他可见的元素。对于一般的颜色或图片填充的需求,可以使用 Label 元素来实现。

function ui.setWallpaper() -- 设置背景墙纸
    -- 创建左边标签
    wallpaper_left = Geyser.Label:new({
        name = "wallpaper_left",    -- 标签名
        x = 0, y = 0,               -- 标签位置(以矩形左上角作为参照)
        width = ui.main_border_left,   -- 标签宽度
        height = "100%",            -- 标签高度
    }, main_container)              -- 属于主容器中的元素

    -- 设置左边墙纸样式
    wallpaper_left:setStyleSheet([[
        background-image: url(]]..ui.image.."wallpaper.png"..[[);
        background-repeat: repeat-xy;
        background-position: top left;
        background-origin: margin;
    ]])

    -- 创建右边标签
    wallpaper_right = Geyser.Label:new({
        name = "wallpaper_right",
        x = -ui.main_border_right, y = 0,
        width = ui.main_border_right,
        height = "100%",
    }, main_container)

    -- 设置右边墙纸样式
    wallpaper_right:setStyleSheet([[
        background-image: url(]]..ui.image.."wallpaper.png"..[[);
        background-repeat: repeat-xy;
        background-position: top right;
        background-origin: margin;
    ]])

    -- 创建顶边标签
    wallpaper_top = Geyser.Label:new({
        name = "wallpaper_top",
        x = 0, y = 0,
        width = "100%",
        height = ui.main_border_top,
    }, main_container)

    -- 设置顶边墙纸样式
    wallpaper_top:setStyleSheet([[
        background-image: url(]]..ui.image.."wallpaper.png"..[[);
        background-repeat: repeat-xy;
        background-position: top left;
        background-origin: margin;
    ]])
end

出于美观的考虑,我们可以增加一些装饰,元素同样以标签的形式创建

function ui.setDecoration() -- 设置装饰元素
    -- 在上方增添浮云
    cloud1 = Geyser.Label:new({
        name = "cloud1",
        x = "10%", y = 0,
        width = "90%",
        height = ui.main_border_top,
    }, main_container)

    cloud1:setStyleSheet([[
        background-image: url(]]..ui.image.."cloud1.png"..[[);
        background-repeat: no-repeat;
        background-position: top left;
        background-origin: margin;
    ]])

    cloud2 = Geyser.Label:new({
        name = "cloud2",
        x = 0, y = 0,
        width = "60%",
        height = ui.main_border_top,
    }, main_container)

    cloud2:setStyleSheet([[
        background-image: url(]]..ui.image.."cloud2.png"..[[);
        background-repeat: no-repeat;
        background-position: bottom right;
        background-origin: margin;
    ]])

    cloud3 = Geyser.Label:new({
        name = "cloud3",
        x = "65%", y = 0,
        width = "35%",
        height = ui.main_border_top,
    }, main_container)

    cloud3:setStyleSheet([[
        background-image: url(]]..ui.image.."cloud3.png"..[[);
        background-repeat: no-repeat;
        background-position: bottom left;
        background-origin: margin;
    ]])

    -- 在左侧增添竹叶
    banboo = Geyser.Label:new({
        name = "banboo",
        x = 0, y = "10%",
        width = ui.main_border_left,
        height = "90%",
    }, main_container)

    banboo:setStyleSheet([[
        background-image: url(]]..ui.image.."banboo.png"..[[);
        background-repeat: no-repeat;
        background-position: top left;
        background-origin: margin;
    ]])

    -- 在右侧增添山峰
    montain = Geyser.Label:new({
        name = "montain",
        x = -ui.main_border_right, y = 0,
        width = ui.main_border_right,
        height = "100%",
    }, main_container)

    montain:setStyleSheet([[
        background-image: url(]]..ui.image.."montain.png"..[[);
        background-repeat: no-repeat;
        background-position: bottom right;
        background-origin: margin;
    ]])

    -- 增加标题文字
    banner = Geyser.Label:new({
        name = "banner",
        x = ui.main_border_left, y = 0,
        width = ui.main_width - ui.main_border_left - ui.main_border_right,
        height = ui.main_border_top,
    }, main_container)

    banner:setStyleSheet([[
        background-image: url(]]..ui.image.."banner.png"..[[);
        background-repeat: no-repeat;
        background-position: center;
        background-origin: margin;
    ]])
end

最后,我们创建一个load ui的别名,方便我们快捷的将更新设置加载到当前界面

ui.setBorder()
ui.setLayout()
ui.setWallpaper()
ui.setDecoration()

到此,一个基础的 Mudlet 界面美化算是成型了。当然,要想界面元素更丰富,功能更多样,还有很多界面设置需要增加,其中包括地图栏、信息窗、状态条、功能按钮等等。这些我们都将在后续逐一补充完善。

让我们看看到目前为止的成果吧: file

这里提供一些链接可以免费下载图像和文字元素,这对我们设计出符合自己期望的界面很有帮助。

对这方面熟悉的当然也可以自己去网上搜集各种资源,甚至自己通过制图软件创作。

京ICP备13031296号-4