Minecraft矢量珍珠炮理论与实践学习 - 笔记

施工中…🚧🚧🚧

写者自游玩Minecraft生电以来,一直想理论学习Minecraft生电领域的一座高塔——矢量珍珠炮。写者初识其时,无比震惊于其恢弘的工程外观,其规模程度与工程复杂度对于一个刚刚会做些简易刷铁机、刷石机的萌新来讲简直是天工造物;后又惊喜于其底层朴实无华的数学逻辑,想学习矢量珍珠炮的心情也愈发浓厚且坚定。因此,这篇博客写者想从理论出发,把对矢量珍珠炮的学习理解一点点搭建起来——既为记录,也为攀登这座生电高塔

in-game-demo

Image from BV1NC4y1x7WW

注:本文所述内容涉及游戏版本为1.13.2,所有内容仅用于个人学习

小知识

末影珍珠:可以投掷以传送使用者的物品。玩家投掷后,珍珠击中物体后会将玩家传送至珍珠落点

TNT:使用打火石点燃后可产生爆炸

矢量珍珠炮:以TNT为炸药,将末影珍珠发射到范围内任意方向、任意位置、误差低至几格的炮。通过矢量珍珠炮,玩家能够实现快速移动(超“光速”)的效果(可在几个gt内移动至上千格之外,甚至更远),从而大大节省玩家跑图时间

此处的“光速”指游戏中的光速,即实体运动的理论速度上限是16格/gt(320m/s)

In Minecraft the theoretical speed limit is known to be 320 m/s. One object has been known to break this law–projectiles.
在Minecraft中,实体的理论速度上限是320m/s。只有一种实体可以突破这个上限——投掷物。

——Xcom6000,译:Fallen_Breath

游戏内单位:

  • 1米 = 1格 = 16像素,若未写明单位,则单位默认为”米“
  • 1gt(游戏刻)= 0.05s

基础知识

1、末影珍珠

玩家投掷后会变为实体,称作掷出的末影珍珠

尺寸:0.25 × 0.25 × 0.25(长 × 宽 × 高)

运动形式:

掷出的末影珍珠以游戏刻(game tick)为单位进行离散运动。如末影珍珠x游戏刻时处于A位置,x+1游戏刻时处于B位置,在中间相隔的这1游戏刻中,末影珍珠的飞行不会“平滑”的从A运动到B,而是直接从A“跳”到B。此处的“跳”可理解为游戏通过计算得到:x时刻末影珍珠应处于A位置,x+1时刻应处于B位置

注:玩家投掷末影珍珠后看到的珍珠平滑的飞行归功于客户端渲染,实际依旧是离散运动

珍珠拦截:

为了传送到指定位置,需要在末影珍珠的飞行路径上放置方块拦截掷出的末影珍珠

这里有个反直觉的点需要注意:

假设掷出的末影珍珠(x - 1)gt处于A位置,(x)gt处于B位置,(x + 1)gt处于C位置。请问:若玩家想要传送到B位置,请问该在什么位置进行拦截?直觉告诉我们,应该要在B位置进行拦截。但,这是❌️的!

为什么?以下尝试分析:

类继承关系图:

1
2
3
Entity(实体类)
└─ EntityThrowable(投掷物基类)
└─ EntityEnderPearl(末影珍珠实体类)

重点关注net.minecraft.entity.projectile.EntityThrowable#tick函数,这个函数会按顺序实现以下功能:

  1. 记录当前这一gt的位置

  2. 方块射线检测

    检测当前这一gt位置与下一gt位置之间是否有方块阻挡

    endpearl-block-ray-trace
  3. 若有方块阻挡,将调用net.minecraft.entity.item.EntityEnderPearl#onImpact函数

    endpearl-onimpact

    将玩家传送至当前这一gt的位置

    endpearl-teleport

分析发现,珍珠传送是以当前这一gt所在位置为基准计算与下一gt之间是否有方块(非地狱门方块)阻挡,若有阻挡,则传送至当前这一gt所在位置。所以,若想要传送到当前这一gt所在位置,则需要在当前这一gt位置与下一gt位置之间放置方块,或是在下一gt位置放置方块阻挡珍珠的飞行

综上,正确答案是在B到C之间或在C处放置方块进行拦截

2、TNT

点燃后会变为实体,称作被激活的TNT

尺寸:

  • TNT方块:1 × 1 × 1(长 × 宽 × 高)
  • 被激活的TNT:0.98 × 0.98 × 0.98(长 × 宽 × 高)

爆炸中心:假设被激活的TNT实体坐标为(0, 0, 0),则其爆炸中心为(0, 0.06125, 0)。注:0.06125米 = 0.98/16米 = 0.98像素

爆炸威力:P = 4

爆炸伤害半径:r = 2 × P

爆炸接触率:α(对于矢量珍珠炮,默认置1)。TNT爆炸时会从爆炸中心向外发射破坏射线,爆炸接触率指射线路径上没有被任何方块碰撞箱阻挡的射线占全部射线的百分比

爆炸击退“力”:此“力”非现实中的力,应理解为动量,在游戏中也指速度(单位:米/gt)
注:表示实体到爆炸中心的距离

代入以上几个参数,可得:

即无遮挡情况下,一个TNT对末影珍珠提供的速度为Δv=F,则n个TNT可对末影珍珠提供的速度为Δv=n×F

3、实体运动

速度: = 。当前实体的速度,表示实体下一游戏刻在x、y、z轴上的移动距离和方向,即空间向量

坐标:Position(x, y, z)。当前实体在x、y、z轴上的坐标,即空间坐标

重力加速度:a(单位:米/),实体下一gt速度的变化量。末影珍珠的重力加速度为-0.03

“阻力”f:实体速度要乘的一个常数,用来模拟阻力以对实体速度进行衰减,含水平方向“阻力”与竖直方向“阻力”。末影珍珠的水平方向“阻力”与竖直方向“阻力”均为0.99

速度与坐标的计算

看net.minecraft.entity.projectile.EntityThrowable#tick:

endpearl-movement

分析发现,坐标与速度的计算为两个递推公式

翻译:

  • (x, y, z)表示空间坐标。x、z为水平方向,y为竖直方向
  • t+1时刻的坐标=t时刻的坐标+t时刻的速度
  • t+1时刻的速度=t时刻的速度×0.99且y轴速度还需再减去0.03

一般方程

将递推公式化为一般方程(推导过程看似复杂,实际上只涉及到递推和等比求和,并不难)

well-well-well
X、Z轴水平方向

速度:

坐标:
又故

Y轴竖直方向

速度:

坐标:
又故

整理,得:

,轴水平方向上:轴竖直方向上:

  • —水平方向初坐标,—竖直方向初坐标
  • —水平方向初速度,—竖直方向初速度

通过上述一般方程,若能知道空间内末影珍珠的初速度、初坐标,则我们可求得末影珍珠接下来每一gt的坐标


只需定位末影珍珠即可知道其初坐标,那初速度呢?

对初速度的计算,核心原理在于矢量计算。在矢量珍珠炮中,是通过大量的TNT爆炸赋予末影珍珠初速度的,想要计算初速度的大小与方向,需以TNT与末影珍珠在空间中的相对位置关系为基础进行矢量推演,进而建立计算方程

为避免内容混杂,考虑从二维平面开始(即假设一切过程都是在二维平面发生),然后再到三维空间

一、二维平面

如图,通过如下摆放TNT,末影珍珠可获得z轴正向90°的发射角度范围(-45°~45°);同理,若以末影珍珠为中心将TNT摆放位置旋转90°、180°、270°,则末影珍珠可获得平面内360°无死角的发射方向

注意:一般来讲,TNT与末影珍珠的连线与水平坐标轴的夹角需是严格的45°

d:TNT爆炸中心距末影珍珠实体坐标的距离
m、n:TNT数量

horizontal-pearl-and-tnt

那TNT爆炸后,末影珍珠的初速度如何计算?(注:这里的初速度指末影珍珠在静止状态——假定的理想情况,受到TNT爆炸加速)

1、分析

如图

horizontal-velocity-vector-analysis

记左侧为第1组TNT(数量为n),右侧为第2组TNT(数量为m)。F为单个TNT对末影珍珠提供的动量

第1组TNT对末影珍珠提供的动量为,分解得:

  • x轴:
  • z轴:

第2组TNT对末影珍珠提供的动量为,分解得:

  • x轴:
  • z轴:

对、进行向量合成,可得两组TNT对末影珍珠提供的初速度为,且:

  • ⭐x轴:

  • ⭐z轴:


至此便求得了x轴与z轴的水平方向初速度


为了观感,先将这个式子稍微改下:


其中其中

结合上述四个由前文推导得到的方程,我们便可以实现:已知TNT数量求末影珍珠落点,最终方程为:

啰嗦一下,对“已知TNT数量求末影珍珠落点”,需分清方程中的常量与变量:

x轴方向上:

  • 常量:
    • n、m:TNT数量
    • d:TNT实体爆炸中心距末影珍珠初坐标的距离
    • :末影珍珠在x轴上的初位置
  • 变量:
    • t:时刻,表示第几gt。此处意指末影珍珠在不被拦截的情况下,第t游戏刻的位置
  • 因变量:
    • x:x轴坐标

z轴方向同理

2、💥重点:已知末影珍珠落点求TNT数量

若已知末影珍珠落点(x,z)

以x轴方向为例,根据方程

  • 已知量:(x轴落点)、(x轴初位置)、t(想要在第几gt到达)、(TNT实体爆炸中心与珍珠实体坐标的距离)
  • 未知数:、

数学告诉我们,一个方程无法唯一的求解两个未知数,得要两个方程。怎么办?让我们接着前面的图继续分析

如下图所示:

horizontal-final-velocity-vector-analysis

其中,θ为末影珍珠速度方向与其发射范围对称轴的夹角

至此,我们终于见到了这个最基本的公式(个人觉得理论意义大于实践意义)

这个式子表明:通过控制两组TNT的数量(n,m),我们可以获得发射范围内几乎所有射出角。即前文所述“末影珍珠可获得平面内360°无死角的发射方向”没瞎说

注意!末影珍珠在受到TNT爆炸后获得初速度后,后续的移动方向也是沿着方向。那么,若落点为,则落点相对于末影珍珠初坐标的偏移也满足

horizontal-velocity-displacement

即

变换一下,可得

变换过程:

第二个方程有了!联立求解

求解过程:
由式,得:由式,得:式代入式,得:注:;可消去将回代式求得:
另,也可联立z轴方向上的轨迹方程:

最终n、m求得的结果是同样的

至此,我们便可得到已知末影珍珠落点求TNT数量的最终方程:

啰嗦一下,对“已知末影珍珠落点求TNT数量”,需分清方程中的常量与变量:

  • 常量:
    • Δx:末影珍珠落点与x轴初位置的偏移
    • Δz:末影珍珠落点与z轴初位置的偏移
    • d:TNT实体爆炸中心距末影珍珠初坐标的距离
  • 变量:
    • t:时刻,表示第几gt。此处意指想要末影珍珠在第几游戏刻到达目的地,例如t=1时,表明我们想要通过式子求得末影珍珠只需花费1gt便可到达目的地所要花费的TNT数量
  • 因变量:
    • n、m:TNT数量

3、总结

经过一系列方程推导,我们便求得了二维平面内,矢量珍珠炮的计算方程:

公式 用途

已知TNT数量求末影珍珠落点

已知末影珍珠落点求TNT数量

接下来进一步讨论三维空间中关于由TNT爆炸所提供,末影珍珠初速度的计算,毕竟Minecraft不是2D游戏。从而最终求得“已知TNT数量求末影珍珠落点”、“已知末影珍珠落点求TNT数量”两个重要问题的计算方程

dancing-cat

二、三维空间