今天,我发布了万象添补0.17.24。自从 7 月 17 日更新 0.17.22 以来,已经一个多月了,而在 8 月 18 日,我终于可以再次更新这个附加包了。 除了我在第 158 期闲聊帖中说的三个新命令以外,0.17.24 还有四项新功能,就是标题这四项。 我已经厌倦开发附加包了,现在让我加入一个物品我都感觉生疏。我对写作也提不起兴趣了,现在我的 dream5_exp 其实已经写到第八章了,但是我就是没有发出来第五、第六和第七章。好在我可以吃老本,就是看一看几年前的文字,现在我越发感到留下这些记录有多么了不起了。 不过最近几天,就像我突然对原版生存来了兴趣一样,我也突然又想做几个小功能了。
还是让我从头说起吧。很久以前,我看过一个用文本展示实体来制作显示屏的 Java 版定制模组。Java 版还有变换矩阵,可以把矩形的文本展示实体拉成普通的平行四边形,然后用三个平行四边形拼成三角形,有了三角形,就能渲染一切模型了。而且因为文本展示实体会面向玩家,还能制作曲面屏。那个视频中,给我留下最深刻印象的就是数字模拟的海浪了,其实就是很多正弦波叠加成的曲面。后来,我又在纪念碑谷中看到了低多边形风格的海面。 但是很可惜,原视频是带模组的 Java 版,基岩版当然做不到,而且就连还原纪念碑谷的海面也做不到,至少我没有找到让它流畅运行起来的办法。不过原视频里颜色选择器的三维交互还是激发了我的灵感。 有一天上午,我突然想起什么,对 AI 说: 阅读 https://projectxero.top/sapi/classes/server.Player.html https://projectxero.top/sapi/classes/server.TextPrimitive.html https://projectxero.top/sapi/classes/server.PrimitiveShapesManager.html
每个属性和方法,简单一句话总结其功能
当时我的想法是,做一个三维悬浮交互式菜单。我看过一个把方块当成显示屏使的可交互操作系统的视频,但是显然,性能堪忧的手机不允许我这么搞。很长时间里,我一直想做那种全息投影式的页面,它们就那样悬浮在空间中,我们可以很方便地交互。要是做好了,或许能奇迹般地绕过 UI 自定义的限制。我最初想解决的是各种卡片的排布问题,但是这还是太复杂了,就看一个合适地放置所有结构的命令有多复杂,我就能感到全息菜单一定是个滔天巨坑,我会把很多时间都砸进细节里,热情最终会被磨灭。 2026 年 8 月 15 日上午 10 点的我想到这些之后,决定暂时抛弃这个项目。但是没过一会儿,我又决定继续做下去。现在我说不准选择轮的灵感是从哪里来的,但是我绝对受了 JSON UI 中 selection_wheel 这个控件类型名称的影响,还有动物井里的一种类似的玩具。 现在我想,我一定在某个地方看到过这样的选择轮,但是它就这样出现在我的脑海里。于是我开始写整个功能最初的构想,这通常是一段毫无逻辑的文本,因为接下来我要让 AI 帮我做出方案。当时我写了下面这段话: 现在我想做一个高级的悬浮文本滚轮选择器。具体原理就是,首先获取玩家的眼睛位置,作为一个球的中心,球的半径是 2,然后根据玩家的视线向量与球面的交点、球在世界空间中的最高点和最低点,这三个点作一个圆,而选择器的选项元素——基元文本,就排列在这个圆上。为了让玩家能选择到,我们规定,在圆上截取一段圆弧,每个选项都占据圆弧的一段长度,而玩家正在看向的那个元素也就是焦点元素,占据的长度比其他元素大。圆弧应该是玩家从低头到抬头这个过程中能聚焦的那段,即圆的玩家面向的那半部分。对于每段长度,我们都在那里生成一个基元文本。基元文本默认自动面向玩家,如果将它的 scale 设为 3.75,则它的高度正好是一个方块高,即球半径的一半。根据选项的多少,我们可以动态调整文本元素的高度和它分配到的圆弧上的长度。但是总体上说,未聚焦的文本的总高度,和聚焦的文本的总高度,比例应该是固定的,比如 15:1。我们一次只能聚焦一个元素,即距离玩家视线向量与球面交点最近的那个元素。如果元素太多,我们可以根据玩家最近聚焦过的元素,动态调整要显示的元素,而当玩家抬头看向球面顶点或低头看向底部时,滚动选项列表,而滚动的加速度与玩家视线与球面交点与顶点的距离成反比。 现在,评估上面这个方案,让它更加有逻辑,系统性,同时,如果有设计不合理的地方或者逻辑漏洞,需要指出来,而不是胡编乱造。
它这么杂乱,我已经不想再看了。总之,经过几轮迭代之后,我成功让 AI 说出了一个完整的方案,接下来就是让它把代码写出来了。这样得到的代码通常是不能用的,需要我全部读一遍,搞清楚它们在做什么,然后结合测试结果修改。 我最不愿意做的就是和旋转角度有关的项目,为了弄对那些旋转,我凭直觉做了一些计算,大概就是拿 90 度减去偏航角的度数,我也不知道这样为什么行,但是它既然行了,那就不能再动了。我最初不想把选择轮做成环绕的样式,只想让玩家看到的部分出现选项,但是全都渲染出来就是简单,不需要考虑视锥什么的。之前我做过一个命令,它可以把玩家看不见的方块偷偷替换掉,那次我就没搞明白相关原理。 结果很简单,当天 13 点以前我就把视频录好,发出去了。 这个选择轮我玩了好久,我发现音效才是 UX(用户体验)的灵魂,只要加入咔哒声,整个轮子的质感都上升了一层,而且缓动动画的运用也为它增色不少。一开始,玩家选中选项会让它的文字变成金色,但是后来我把它改成了动态颜色,看起来好多了。 这个小玩意有用吗?有,但不多,很难想到什么需要大量选项的场景。但是做出来就是很好玩,于是我开始了第二个项目。
这又是一个从视频中获得的灵感。别人刷视频浪费时间,我刷视频虽然也浪费时间,但是有时候还能从中获得一些创意,用在这些小项目上。 什么?你说这些项目也是浪费时间?? ... 不会说可以不说!
总之,我曾经看过一个视频,它大概教我怎么用 css 写一个超级酷炫的聚焦框,它的样式就像结构空位一样,鼠标移动到一个元素上,它就自动包裹住这个元素,而且还能根据元素的大小来动态调整框的大小。因为元素是有实际面积的,焦点框看起来就像是磁吸在元素上一样,非常好玩。后来我又看了一些 AB 柴,“害”客的形象更是加深了我对焦点选框的印象,于是我要把磁吸选框做出来。 我再次打开 AI 对话框,有了上一个项目,它可以参考上次的实现方式。当然,我依旧对它说了一大堆废话: 现在要仿照它写一个方块和实体选择器。已知现在我们使用 DebugBox 代替基元文本来实现聚焦功能,未聚焦的元素不再处理,只实现焦点的聚焦功能,具体表现为,玩家对准方块时,立方体形状的焦点吸附到方块上;玩家对准实体时,立方体形状的焦点变形为实体的碰撞箱大小,吸附到实体上。 玩家对象有 player.getBlockFromViewDirection({ maxDistance: 16, includeLiquidBlocks: false }); 方法,返回一个射线碰撞对象;这个对象上有 block 属性,这是玩家看向的方块,若为 undefined 则玩家没有看向方块。若存在,则可以获取这个方块的 location 属性,是 {x, y, z} 对象,表示方块一个角落的位置。这个位置在每个轴上加 1,就得到了这个方块另一个角落的位置。这两个顶点组成的立方体,称为基。对于基的三个轴,每个轴上,它的两侧都扩展 delta = +0.05 格,这样构造出的三个立方体就是玩家的焦点,它需要用 DebugBox 被渲染出来。 玩家对象上有 player.getEntitiesFromViewDirection({ maxDistance: 16, includeLiquidBlocks: false }); 返回看向的实体的数组,可能为 undefined,若未定义则玩家没有看向实体。若存在,则取第一个元素(这是玩家看向的最近的实体),它有 entity 属性,表示实体。实体上有 getAABB() 方法,返回实体的碰撞箱,这是一个 AABB 对象,即 {center, extent}。这也是实体的基,应该和方块的基一样对待。 玩家没有聚焦的时候,他们的焦点框默认是一个单位灰色半透明立方体。只要代码检测到玩家正在看向方块或实体,就将焦点框吸附到方块或实体上,此时一个立方体分裂为三个,同时按照参考中的插值动画处理,颜色变为动态改变的颜色。一旦停止聚焦,玩家的焦点又恢复未激活的灰色状态。检测到开始聚焦 / 不再聚焦的时候,应该播放声音。代码处理时,可以一直保留三个 DebugBox,焦点未激活时它们重合在一起,不透明度比较低,焦点激活时它们充当上文提到的三个立方体框。另外,在未激活的时候,这些框应该根据玩家的速度向量而旋转(把速度的变化映射到旋转角度上)。player.getVelocity() 返回速度向量,DebugBox 有 rotation 属性,接收 {x, y, z} 欧拉角。具体映射方式自行实现。在焦点选框激活的时候,旋转角度自动通过插值动画回到 0, 0, 0。
这次的实现就非常简单,甚至比上次还简单。因为磁吸焦点线框的核心就是通过玩家的视线检测方块与实体,这正是 WAILA(我猜它的全称是 What am I looking at,我在看什么)还有 Jade 这样的模组的核心,也是原版内置 API 提供的功能。因为线框的绘制、变色、变形与缓动非常简单,这个功能很快就做好了。最初我还想通过速度旋转线框,给它一点高级感,但是后来我发现直接把玩家的旋转角度映射到线框上才是最立竿见影的选择。 它当然也要配上高级音效,可惜我不是音效师。虽然我做不出高级音效,但是原版游戏可是内置了一堆一堆的神秘音效,总有一款适合你。这次我就挑准了试炼刷怪笼、不祥之物生成器和重生锚,它们都有泛用性很强的音效,我在玩原版命令的人那里经常听到。好在 Wiki 能试听音效,这真是最方便的功能了,我找不到合适的 fsb 播放器,就靠 Wiki 试听。最后虽然没找到完美适配的音效,但是从原版里找合适音效,就像大海捞针,沙里淘金,能找到凑合的就不错了。 焦点磁吸线框真是太简单了,我很快完成了开发,又发了一期视频。
写到这里,时间已经是 22:35 了,已经熬夜这么久,我要赶快睡觉了。后面两个功能下次再聊吧,它们花了我不少时间和心思,但是作为发出去的视频,不如前面两个效果好。只能说,能做出内含 99% 创意和 1% 技术的作品,我还是挺荣幸的。 |