MCIO Plugins MCIO Plugins
首页
赞助
无法下载? (opens new window)

人间工作P

我每天都好困… 最近在学习和进行 VOCALOID 创作
首页
赞助
无法下载? (opens new window)
  • PluginBase

  • Item-NBT-API

  • VectorDisplays

    • VectorDisplays 简介
    • 内嵌依赖
    • 控件定位
    • 动态添加元素
    • 使用案例
      • 显示二维码
      • 显示图片
      • 播放 Bad Apple!!
      • 贝塞尔曲线变速运动
      • 使用幽灵控件做准心悬停判定
  • 开发文档
  • VectorDisplays
2025-11-04
目录

使用案例

在这里存放一些 VectorDisplays 使用案例。这些案例可能需要最新开发版的 VectorDisplays 才能使用。

# 显示二维码

额外使用依赖库 top.mrxiaom:qrcode-encoder:1.0.0

java
public static void applyQRCode(Terminal<?> terminal, QRCode code) {
    int moduleCount = code.getModuleCount();
    double block = 2.0;
    double pos = -(moduleCount * block) / 2.0;
    for (int y = 0; y < moduleCount; y++) {
        for (int x = 0; x < moduleCount; x++) {
            if (!code.isDark(y, x)) continue;
            double posX = pos + x * block, posY = pos + y * block;
            terminal.addElement(new Label("qrcode_" + x + "_" + y), e -> {
                e.setEnabled(false);
                e.setAlign(EnumAlign.CENTER);
                e.setText("        "); // 玄学问题: 文本长度越长,精度越高;只有一个空格的时候精度堪忧
                e.setBackgroundColor(0xFFFFFFFF);
                e.setShadow(false);
                e.setFullBrightness();
                double oldWidth = HologramFont.getWidth(e.getHologram().getTextAsComponent());
                double oldHeight = HologramUtils.LINE_HEIGHT;
                e.setScaleX(HologramUtils.calculateScale(oldWidth, block));
                e.setScaleY(HologramUtils.calculateScale(oldHeight, block));
                e.setPos(posX, posY);
            });
        }
    }
}

# 显示图片

警告

VectorDisplays 1.0.1 版本暂未对数量非常庞大的悬浮字进行支持。
虽然后续的版本进行了支持,但尺寸过大的图片一定会占用多的带宽(即使是本地回环),让服务器暂时停止运行,并且会因为长期无响应导致你的服务器崩溃!
另外,玩家的客户端也无法承载非常庞大的悬浮字数量,可能会使得玩家的 FPS 降低至 0。

除非有特别需要,或者纯粹想装逼,请配合资源包的字体贴图来显示图片,而不是使用这种方法。

java
public static void applyImage(Terminal<?> terminal, BufferedImage image) {
    double width = 30.0; // 简单地进行等比缩放,宽度在界面上会显示多宽
    int imageWidth = image.getWidth(), imageHeight = image.getHeight();
    double pixelSize = width / imageWidth; // 计算单个像素点的尺寸
    // 图像居中
    double imageX = -pixelSize * imageWidth / 2;
    double imageY = -pixelSize * imageHeight / 2;
    // 提前算好缩放大小,省得在循环里面计算
    double oldWidth = HologramFont.getWidth(Component.text("        "));
    double oldHeight = HologramUtils.LINE_HEIGHT;
    float scaleX = HologramUtils.calculateScale(oldWidth, pixelSize);
    float scaleY = HologramUtils.calculateScale(oldHeight, pixelSize);
    // 按每一行扫描每一个像素,添加为一个 Label
    for (int y = 0; y < imageHeight; y++) {
        for (int x = 0; x < imageWidth; x++) {
            int color = image.getRGB(x, y);
            if (((color >> 24) & 0xFF) == 0) continue; // 忽略透明像素
            double posX = imageX + (x * pixelSize);
            double posY = imageY + (y * pixelSize);
            terminal.addElement(new Label("image_pixel_x" + x + "_y" + y), e -> {
                e.setEnabled(false);
                e.setAlign(EnumAlign.CENTER);
                e.setText("        ");
                e.setFullBrightness();
                e.setBackgroundColor(color);
                e.setShadow(false);
                e.setScaleX(scaleX);
                e.setScaleY(scaleY);
                e.setPos(posX, posY);
            });
        }
    }
}

# 播放 Bad Apple!!

使用文本展示实体播放 Bad Apple!! 坏苹果(开放源代码)【我的世界/Minecraft】 (opens new window)

# 贝塞尔曲线变速运动

使用类似于 CSS 中 cubic-bezier(a, b, c, d) 的贝塞尔曲线变速动画。

数值可以在 cubic-bezier.com (opens new window) 生成并预览。

java
public static void spawnWithBezier3(Terminal<?> terminal, Location loc) {
    // 动画机示例 https://cubic-bezier.com/#0,0,.58,1
    spawnWithBezier3(terminal, loc, Bezier3.cubicBezier(.0f, .0f, .58f, 1.0f));
}
public static void spawnWithBezier3(Terminal<?> terminal, Location loc, Bezier3 ani) {
    double distance = 3.0; // y轴移动距离
    long duration = 2000L; // 动画持续时间 (毫秒)
    TerminalManager manager = TerminalManager.inst();
    
    // 设置插值,使得悬浮字移动相对平滑
    for (EntityDisplay<?> display : Terminal.resolveAllEntityDisplay(terminal)) {
        display.setInterpolationDurationRotation(1);
    }

    // 位置计算
    World world = loc.getWorld();
    double x = loc.getX(), y = loc.getY(), z = loc.getZ();
    Function<Float, Location> func = v -> new Location(world, x, y + ((1.0 - v) * distance), z);
    terminal.setLocation(func.apply(0f));

    // 注册并生成悬浮字
    manager.spawn(terminal);

    // 通过异步定时器更新位置
    AtomicReference<IRunTask> task = new AtomicReference<>(null);
    task.set(manager.getPlugin().getScheduler().runTaskTimerAsynchronously(() -> {
        if (ani.getStartTime() == 0L) {
            // 初始化动画机时间
            ani.setStartTime(System.currentTimeMillis());
            ani.setDuration(duration);
        }
        // 更新位置
        terminal.setLocation(func.apply(ani.getPoint()[1]));
        // 若动画已结束,停止定时器
        if (ani.hasEnd() && task.get() != null) {
            task.get().cancel();
            task.set(null);
        }
    }, 2L, 1L));
}

# 使用幽灵控件做准心悬停判定

举个例子,我用蓝色、紫色这两个三角形组成了一个梯形的形状,但是我想要悬停事件和点击事件的范围都在灰色三角形内,要如何实现呢?

可以构建灰色三角形的控件实例,但不添加到 terminal 中,作为一个仅用于判定 hit test 的幽灵控件,如下所示

java
    private Triangle gt;
    private void createGhostTriangle() {
        // 创建幽灵三角形(ID 随便取)
        gt = new Triangle("ghost_triangle")
            // 输入三角形坐标 (顺时针)
            .setPos1(HologramUtils.toFloat(outerPoint2))
            .setPos2(HologramUtils.toFloat(outerPoint1))
            .setPos3(HologramUtils.toFloat(centerPoint))
            .configureStyle(style -> {
                // 不添加到 terminal 的话,这一步没有必要: 使得三角形完全透明
                style.setBackgroundColor(0);
            });
        // 需要绑定 terminal 才能计算坐标进行 hit test
        // 这个语句不会将 gt 添加到 terminal 中
        terminal.bindElement(gt);
        // 如有需要,使用以下语句来真正添加三角形到 terminal 中
        //terminal.addElement(gt);
    }

将 gt 的实例存起来,需要判定是否悬停的时候,执行

java
    // 如果返回值不为 null,即代表准心当前停留在幽灵三角形控件上面
    @Nullable
    Location hitTest(@NotNull Player player) {
        Location eyeLocation = HologramUtils.getEyeLocation(player);
        return HologramUtils.raytraceElement(terminal, null, gt, eyeLocation);
    }
    // 转换为 terminal 面板上的二维投影坐标,点击事件可能会用到
    @Nullable
    Point2D hitTest2d(@NotNull Player player) {
        Location point = hitTest(player);
        if (point != null) {
            return HologramUtils.getPoint(gt, point);
        } else {
            return null;
        }
    }

你可以重载 Terminal#onTimerTick(),然后进行 hit test,更新其它相关控件的背景颜色,变相实现扩展判定范围。

java
    @Override
    public void onTimerTick() {
        super.onTimerTick();

        for (Player player : terminal.getViewers()) {
            if (hitTest(player) != null) {
                // TODO: 更新其它控件背景颜色
            } else {
                // TODO: 更新其它控件背景颜色
            }
        }
    }

如果你需要点击这个区域执行代码,有两条线路

  • 真的将这个幽灵控件添加到 terminal 中,不过会额外多出一个玩家看不见的虚拟实体
  • 重载 Terminal#tryPerformClick(Player, Action),进行 hit test
java
    @Override
    public boolean tryPerformClick(Player player, Action action) {
        Point2D clickPos = hitTest2d(player)
        if (clickPos != null) {
            // TODO: 做点什么
            return true;
        }
        return super.tryPerformClick(player, action);
    }
上次更新: 2026/05/29, 06:25:34
动态添加元素

← 动态添加元素

使用主题 Vdoing | Copyright © 2018-2026 人间工作P | 到赞助页面支持我 | b02c69e

除非特别说明,本站点所有文章均以 CC BY-SA 协议授权

《我的世界》和《Minecraft》是微软公司和 Mojang Synergies AB 的商标,本站点与微软公司等没有从属关系。

  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式