猫史档案馆


[Arena]Dialog失业了?!~用gui平替dialog

用户:145a145a查看:13 回复:11 评论:13 创建时间:2023-08-01T10:14:53


效果展示: dao3.fun/play/97e51eed82267dc4a03e

使用的开源代码:

https://shequ.cod喵/mobile/community/552330

https://shequ.cod喵/mobile/community/549165

下面是代码

gui.ElementType = {//基本元素类型
    DIALOG: "dialog",
    GROUP: "group",
    LABEL: "label",
    BUTTON: "button",
    IMAGE: "image"
}
gui.DialogPositionType = {//对话框位置类型
    FULL_SCREEN: "full screen",
    LEFT: "left"
}
function getStringRealLength(str) {//获取字符串真实长度
    str = String(str);
    let count = 0;
    for (let char of str) {
        count += char.match(/[^\x00-\xff]/) ? 2 : 1;
    }
    return count;
}
function forceEndline(str, maxLength) {//字符串强制换行
    str = String(str);
    if (getStringRealLength(str) <= maxLength) return str;
    if (typeof str != "string") {
        str += "";
    }
    let resultArr = [];
    let piece = "";
    let length = 0
    for (let char of str) {
        if (char !== "\n") {
            length += char.match(/[^\x00-\xff]/) ? 2 : 1;
            piece += char;
        }
        if (length >= maxLength || char === "\n") {
            resultArr.push(piece);
            piece = "";
            length = 0;
        }
    }
    if (piece.length > 0) resultArr.push(piece);
    let result = resultArr.join("\n");
    return result;
}
gui.getScreenResolution = async function (entity) {//获取屏幕分辨率 https://shequ.cod喵/community/552330
    await gui.init(entity, {
        "": {
            display: true, data: `<dialog percentWidth="100" percentHeight="100" id="fullscreen"></dialog>`
        }
    });
    const screenWidth = await gui.getAttribute(entity, "#fullscreen", "width");
    const screenHeight = await gui.getAttribute(entity, "#fullscreen", "height");
    gui.remove(entity, "#fullscreen");
    return {
        width: screenWidth,
        height: screenHeight
    }
}
gui.data = function ([name, id, attributes, children]) {
    attributes.id = id;
    return {
        name: name,
        attributes: attributes,
        children: children ?
            children.map((v) => gui.data(v))
            :
            void 0
    };
}
gui.initDialog = async function (entity, position, title, content = "", options, color, canCopy = false) {//显示对话框
    if (!!(await gui.getAttribute(entity, "#dialogText", "id"))) {//禁止叠加
        throw `gui对话框无法叠加`;
    }
    content = forceEndline(content, 28);
    const screen = await gui.getScreenResolution(entity);
    const x = [screen.width / 2 - 90, 100][[gui.DialogPositionType.FULL_SCREEN, gui.DialogPositionType.LEFT].indexOf(position)];
    const contentEndlineNum = content.split("\n").length - 1;
    const startY = screen.height / 2.5 - ((canCopy + options.length) * 30 + contentEndlineNum * 15);
    const contentY = startY + contentEndlineNum * 16;
    let data = {
        "dialogText": {
            display: true,
            data: gui.data([
                gui.ElementType.GROUP, "dialogText", {
                    percentWidth: 100,
                    percentHeight: 100,
                    backgroundColor: position === gui.DialogPositionType.FULL_SCREEN ? "black" : "transparent"
                },
                [
                    [
                        gui.ElementType.LABEL, "dialogTitle",
                        {
                            text: title,
                            y: startY,
                            x: x + 100 - getStringRealLength(title) * 10,
                            fontSize: 40,
                            color: color,
                            height: 100,
                            width: 400
                        }
                    ],
                    [
                        gui.ElementType.LABEL, "dialogContent",
                        {
                            text: content,
                            y: contentY,
                            x: x - 100,
                            fontSize: 30,
                            color: color,
                            height: 200,
                            percentWidth: 100
                        }
                    ]
                ]
            ])
        }
    };
    if (canCopy) {
        data["dialogContentCopyButton"] = {
            display: true,
            bindings: [
                { action: "clipboardWrite", attributeName: `copyValue`, event: "click", targetSelector: `#dialogContentCopyButton` }
            ],
            data: gui.data([
                gui.ElementType.BUTTON,
                `dialogContentCopyButton`,
                {
                    text: "复制到剪切板",
                    y: contentY + 110 + contentEndlineNum * 16,
                    x: x,
                    color: color,
                    height: 40,
                    width: 200,
                    copyValue: content
                }
            ])
        }
    }
    for (let index = 0; index < options.length; index++) {
        data[`dialogOption${index}`] = {
            display: true,
            bindings: [
                { action: "sendMessage", messageName: `pressDialogOption${index}`, event: "click", selector: `#dialogOption${index}` }
            ],
            data: gui.data([
                gui.ElementType.BUTTON,
                `dialogOption${index}`,
                {
                    text: options[index],
                    y: contentY + 140 + contentEndlineNum * 16 + ((index + canCopy) * 50),
                    x: x,
                    color: color,
                    height: 40,
                    width: 200
                }
            ])
        };
        gui.init(entity, data);
    }
}
gui.removeDialog = async function (entity) {//移除对话框
    if (!!await gui.getAttribute(entity, "#dialogContentCopyButton", "text")) {
        await gui.remove(entity, "#dialogContentCopyButton");
    }
    for (let index = 0; !!(await gui.getAttribute(entity, `#dialogOption${index}`, "id")); index++) {
        await gui.remove(entity, `#dialogOption${index}`);
    }
    await gui.remove(entity, "#dialogText");
}
gui.cancelDialog = async function (entity) {//取消对话框
    await gui.removeDialog(entity);
    entity.player.guiDialogResolve(null);
}
GamePlayer.prototype.guiDialogResolve = null;
GamePlayer.prototype.guiDialogResult = null;
gui.dialog = async function (entity, title, content, options = ["确定"], canCopy = false) {//类似原生对话框的异步函数
    if (!!(await gui.getAttribute(entity, "#dialogText", "id"))) return;
    await gui.initDialog(entity, gui.DialogPositionType.FULL_SCREEN, title, content, options.concat(["关闭"]), "orange", canCopy);
    let dialogPromise = new Promise((resolve, reject) => {
        entity.player.guiDialogResolve = resolve;
    });
    return dialogPromise;
}
gui.onMessage(async ({ entity, name }) => {//结束对话框Promise
    if (name.startsWith("pressDialogOption")) {
        const index = name.slice(-1);
        const value = await gui.getAttribute(entity, `#dialogOption${index}`, "text");
        entity.player.guiDialogResult = value === "关闭" ? null : { index: index, value: value };
        await gui.removeDialog(entity);
        entity.player.guiDialogResolve(entity.player.guiDialogResult);
    }
});

使用方法(dts)

gui.dialog(entity:GamePlayerEntity,title:string,content:string,options:Array<string>,?canCopy:Boolean):Promise<GameSelectDialogResponse|null>
gui.cancelDialog(entity:GamePlayerEntity):Promise<void>

部分是现写的,可能不标准

如果有错误或遗漏一会回帖补充

欢迎反馈bug和优化


回复

上一页1 页 / 共 1下一页
145a145a

title不能太长,最多一行

cancopy为true会显示一个按钮,点了会复制content

两种position:

left是在左边,透明

full_screen是全屏,黑色背景

调用所有方法必须加await

点赞0


评论


无极玄天无极玄天

GUI用多了会崩啊awa

点赞2


评论


𝙲ℴ𝗌𝔦𝒹ₑ𝑟𝙲ℴ𝗌𝔦𝒹ₑ𝑟

要不要加上jsdoc()

点赞1


评论


145a145a

顶 

点赞0


评论


马云编程猫马云编程猫

况且GUI在聊天区聊天时,会发生偏移;还有一些手机版玩家因为屏幕分辨率比较小,一些内容是看不到的,所以GUI只能说和dialog各有利弊

点赞3


评论


伴只狗头伴只狗头

前排

点赞0


评论


yee剑走天下yee剑走天下

收藏(

点赞0


评论


145a145a

帖中的是旧版本,这是最新版本

1.3版本更新

链接: netcut.cn/p/278c07fd9aedc2a3

1.减小content字号

2.更流畅了

3.防止出现由于玩家还在加载产生的bug

点赞0


评论


乐大王的小号2乐大王的小号2

闻到了气味()

点赞0


评论


ZNS_哪吒ZNS_哪吒

收藏()

点赞0


评论


ray_crazyray_crazy

dialog就不该出现,弹出来影响游玩,萌新写dialog代码嵌套一大堆

点赞1


评论