作业

您所在的位置:网站首页 minecraft插件下载 作业

作业

2023-05-06 10:30| 来源: 网络整理| 查看: 265

60-我的世界创造营教程 > 2-客户端界面的制作 > 3-作业 搜索 # 作业

要求:依赖客户端Mod制作一个简易的菜单插件。

进入游戏自动生成一个在Hud界面上的菜单 服务器可以配置每个菜单按钮: 索引位置 图片、文本 点击后以玩家身份执行指令

示例图:

# Spigot插件

Spigot插件的逻辑较为简单,在玩家UI加载完成之后,向玩家客户端发送提前加载好的菜单配置文件即可。

配置文件格式:

button1: idx: 1 # 该按钮在菜单中的位置 texture: 'textures/items/apple' # 该按钮显示的贴图 text: '按钮1' # 该按钮下方的提示文本 commands: - 'say 点击了按钮1' # 点击后执行的玩家指令 button2: idx: 2 texture: 'textures/items/diamond_sword' text: '按钮2' commands: - 'say 点击了按钮2'

读取配置文件的代码不过多介绍,需要参考可以下载源码进行查看。

主类中包含了与客户端通讯的关键代码,供参考:

package me.zhanshi123.tutorialmenu; import com.neteasemc.spigotmaster.SpigotMaster; import me.zhanshi123.tutorialmenu.config.ConfigManager; import me.zhanshi123.tutorialmenu.config.MenuButtonConfig; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; public final class TutorialMenu extends JavaPlugin { private static TutorialMenu instance; private SpigotMaster spigotMaster; private final String NAMESPACE = "testMenu"; private final String SERVER_SYSTEM_NAME = "testMenuDev"; private final String CLIENT_SYSTEM_NAME = "testMenuBeh"; private final String CLIENT_UI_LOADED_EVENT = "ClientUiLoadedEvent"; private final String SERVER_MENU_EVENT = "ServerMenuEvent"; private final String CLIENT_MENU_CLICKED_EVENT = "ClientMenuClickedEvent"; public static TutorialMenu getInstance() { return instance; } @Override public void onEnable() { instance = this; ConfigManager.getInstance().loadConfig(); spigotMaster = (SpigotMaster) Bukkit.getPluginManager().getPlugin("SpigotMaster"); spigotMaster.listenForEvent(NAMESPACE, CLIENT_SYSTEM_NAME, CLIENT_UI_LOADED_EVENT, (player, map) -> spigotMaster.notifyToClient(player, NAMESPACE, SERVER_SYSTEM_NAME, SERVER_MENU_EVENT, ConfigManager.getInstance().getClientData())); spigotMaster.listenForEvent(NAMESPACE, CLIENT_SYSTEM_NAME, CLIENT_MENU_CLICKED_EVENT, (player, map) -> { int index = (int) map.get("index"); MenuButtonConfig menuButtonConfig = ConfigManager.getInstance().getMenuConfigs().get(index); if (menuButtonConfig == null) { getLogger().warning("玩家 " + player.getName() + " 发送了一个不正确的菜单数据"); return; } menuButtonConfig.dispatchCommand(player); }); } @Override public void onDisable() { } } # 客户端模组

创建一个命名空间为testMenu的插件,删除developer_mods文件夹之后,就可以先创建一个空白附加包,开始编辑菜单界面。

# 界面编辑

对于这种有序排列的界面,我们可以直接使用布局面板来自动给按钮排版。

新建一个布局面板,将其锚点都设置在左上方,并设置尺寸X为适应,修改排列方式为水平排布。

新建一个面板,命名为btn_tpl,作为按钮的模板。自行调整其尺寸,教程中设置为60x60。

在btn_tpl下新建一个按钮,这就是按钮本体。自行调整其尺寸,教程中设置为40x40。

在空间结构中展开界面button,找到button_label,它被用来显示按钮上的文本,将它的父锚点设置到下,子锚点设到上。这样它就会整个显示在按钮图片的下方。

最后将btn_tpl设置为隐藏。后面我们会把它作为模板来克隆别的按钮,添加到stack_panel中。

除了使用布局面板+克隆模板的方式来制作这种多按钮的界面。

还可以使用网格来实现。需要注意的是,网格的内容在Create生命周期的时候,有可能还没有被生成。

需要监听GridComponentSizeChangedClientEvent (opens new window),在其数量由0变为其他的时候,才能对网格下的控件进行操作。

# 界面逻辑

将刚刚编辑好的文件,复制到对应的客户端资源testMenu/resource_packs/testMenuResource/ui处。

接下来编辑UiDef,修改screen的值为刚刚编辑的json文件。

UIData = { UIDef.MenuScreen: { "cls": "testMenuScript.ui.test_menu_screen.MenuScreen", "screen": "test_menu.main", "isHud": 1 } }

客户端界面初始化完成后,加载UiMgr,并向服务器通知。

def OnUiInitFinished(self, args): logger.info("%s OnUiInitFinished", MenuConst.ClientSystemName) self.mUIMgr.Init(self) self.NotifyToServer("ClientUiLoadedEvent", {})

监听来自服务器的ServerMenuEvent事件,并通过mUIMgr获取ScreenNode实例,调用SetData方法来设置来自服务端的数据。

def __init__(self, namespace, systemName): ClientSystem.__init__(self, namespace, systemName) self.mUIMgr = uiMgr.UIMgr() self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), MenuConst.UiInitFinishedEvent, self, self.OnUiInitFinished) self.ListenForEvent(MenuConst.ModName, MenuConst.ServerSystemName, "ServerMenuEvent", self, self.OnServerMenu) def OnServerMenu(self, args): print "OnServerMenu", args if self.mUIMgr: self.mUIMgr.GetUI(UIDef.MenuScreen).SetData(args["data"]) else: print "UIMgr还没有加载!"

编写MenuScreen的SetData方法,通过传入的数据来克隆按钮。并给按钮添加回调。

Clone (opens new window)具体参数见文档。

# -*- coding: utf-8 -*- import mod.client.extraClientApi as clientApi from testMenuScripnuConst import ModName, ClientSystemName ScreenNode = clientApi.GetScreenNodeCls() class MenuScreen(ScreenNode): """ Menu """ def __init__(self, namespace, name, param): ScreenNode.__init__(self, namespace, name, param) self.mStackPanel = "/stack_panel" self.mTemplate = "/btn_tpl" print '==== %s ====' % 'init MenuScreen' # Create函数是继承自ScreenNode,会在UI创建完成后被调用 def Create(self): print '==== %s ====' % 'MenuScreen Create' def OnBtnClick(self, args): print args["ButtonPath"] path = args["ButtonPath"] # 路径为 /stack_panel/btn_x/button buttonId = int(path[path.rindex("_") + 1:path.index("/button")]) # 截取路径中的x,它就是按钮的索引 clientApi.GetSystem(ModName, ClientSystemName).NotifyToServer("ClientMenuClickedEvent", {"index": buttonId}) # 发送给服务器 def SetData(self, data): data = sorted(data, key=lambda x: x["index"]) # 对按钮顺序进行排序 for btn in data: newName = "btn_{}".format(btn["index"]) # 把按钮对应的index存在路径中,后面按钮点击时,根据路径判断是哪个按钮 self.Clone(self.mTemplate, self.mStackPanel, newName) newPath = self.mStackPanel + "/" + newName self.GetBaseUIControl(newPath).SetVisible(True) # 设置可见 newPath += "/button" btnControl = self.GetBaseUIControl(newPath).asButton() btnControl.AddTouchEventParams({"isSwallow": True}) # 先开启按钮回调功能 btnControl.SetButtonTouchUpCallback(self.OnBtnClick) # 再设置按钮回调函数 # 按钮的贴图有3个,分别对应默认、按下、悬浮。这里三个都设置。 self.GetBaseUIControl(newPath + "/default").asImage().SetSprite(btn["texture"]) self.GetBaseUIControl(newPath + "/pressed").asImage().SetSprite(btn["texture"]) self.GetBaseUIControl(newPath + "/hover").asImage().SetSprite(btn["texture"]) self.GetBaseUIControl(newPath + "/button_label").asLabel().SetText(btn["text"]) # 设置按钮下的文本 # 效果展示

# 代码下载

Spigot插件:点我 (opens new window)

客户端模组:点我 (opens new window)

← 界面逻辑的编写 中国版特效的使用 →



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3