原理 其实主要原理就在下面三张图中:



py脚本如下:
- import sys
- import math
- o = (0.5,4,-3.5)
- p = (0.5,8,6.5)
- g = -0.02
- f = 0.08
- t = 20
- dx = p[0] - o[0]
- dy = p[1] - o[1]
- dz = p[2] - o[2]
- x = f * dx / (1 - math.pow(1 - f, t))
- y = (f * dy - g * t) / (1 - math.pow(1 - f, t)) + g / f - g
- z = f * dz / (1 - math.pow(1 - f, t))
- print ("{Motion:[", x, ",", y, ",", z, "]}")
复制代码 |
原理上来讲很容易实现,所以本数据包主要内容体现在如何让计算保持一定精度,尤其是仅运用储存上限为2147483647的计分板运算
- 变量储存规则
介绍变量规则,以免一会儿大家看混淆
主要分为两类,常量和变量:
常量如物理常量'g'和'f',以及常数-1、0、1、10……储存在计分板"con"中;
变量主要是过程量'a'、'b'、'c'等等就不列举了。
三维变量中ox、oy、oz和tx、ty、tz还有m0、m1、m2因为与实体NBT存储有关,另开了计分板。
- 第一步:获取物理常量 (motionit:getparam)
原理是穷举,用到了实体标签:
例如tags/entity_types/mincart.json
- {
- "replace": false,
- "values": [
- "minecraft:boat",
- "minecraft:minecart",
- "minecraft:tnt_minecart",
- "minecraft:chest_minecart",
- "minecraft:furnace_minecart",
- "minecraft:hopper_minecart",
- "minecraft:spawner_minecart",
- "minecraft:command_block_minecart"
- ]
- }
复制代码 |
穷举的命令则是:
- # boat & minecart : g = -0.04, f = 0.05
- execute as @s[type=#motionit:minecart] run scoreboard players set g con -4
- execute as @s[type=#motionit:minecart] run scoreboard players set f con 5
复制代码 |
这里的'g'和'f'我们用一位整数替代两位小数。
- 第二步:获取1-(1-f)^t (motionit:pow/x)
原来想法是递归运算pow(),因为舍的位数太多,结果是运行不超过十次必得到0,因此舍弃了(仍保留在数据包中,函数为oppow.mcfunction和oppowc.mcfunction,毕竟方法是正确的)。
后来果断穷举了,因为f的值是恒定的常数,所以分为0、1、2、5四种情况穷举,脚本如下:
- import sys
- import math
- f = 0.01
- m = 0
- ml = 0
- tl = 0
- for t in range(1000):
- m = int((1-pow((1-f),t))*10000)
- if m != ml or t == 999:
- if tl == t - 1 : print("execute as @s[scores={t=%s}] run scoreboard players set p con %s" %(tl, ml))
- else : print("execute as @s[scores={t=%s..%s}] run scoreboard players set p con %s" %(tl, t, ml))
- ml = m
- tl = t
复制代码 |
- 第三步:计算坐标差 (motionit:relativeswitch、motionit:relativeconfirm)
motionit:relativeswitch:
- # distance rounding
- execute store result score x1 var run data get entity @s Pos[0] 1000
- execute store result score y1 var run data get entity @s Pos[1] 1000
- execute store result score z1 var run data get entity @s Pos[2] 1000
- scoreboard players operation @s m0 = @s tx
- scoreboard players operation @s m1 = @s ty
- scoreboard players operation @s m2 = @s tz
- scoreboard players operation x2 var = @s tx
- scoreboard players operation y2 var = @s ty
- scoreboard players operation z2 var = @s tz
- scoreboard players operation x2 var -= x1 var
- scoreboard players operation y2 var -= y1 var
- scoreboard players operation z2 var -= z1 var
- scoreboard players operation x2 var /= 1000 con
- scoreboard players operation y2 var /= 1000 con
- scoreboard players operation z2 var /= 1000 con
- scoreboard players operation x3 var = x2 var
- scoreboard players operation y3 var = y2 var
- scoreboard players operation z3 var = z2 var
- execute if score x2 var < 0 con run scoreboard players operation x2 var *= neg con
- execute if score y2 var < 0 con run scoreboard players operation y2 var *= neg con
- execute if score z2 var < 0 con run scoreboard players operation z2 var *= neg con
- # flexibly standardize decimal place format
- # calculate relatively to improve accuracy
- execute if score x2 var >= 10000 con run scoreboard players operation @s m0 = x3 var
- execute if score x2 var >= 1000 con if score x2 var < 10000 con run execute store result score x1 var run data get entity @s Pos[0] 10
- execute if score x2 var >= 1000 con if score x2 var < 10000 con run scoreboard players operation @s m0 /= 100 con
- execute if score x2 var >= 100 con if score x2 var < 1000 con run execute store result score x1 var run data get entity @s Pos[0] 100
- execute if score x2 var >= 100 con if score x2 var < 1000 con run scoreboard players operation @s m0 /= 10 con
- execute if score x2 var >= 10 con if score x2 var < 100 con run execute store result score x1 var run data get entity @s Pos[0] 1000
- execute if score x2 var >= 1 con if score x2 var < 10 con run execute store result score x1 var run data get entity @s Pos[0] 10000
- execute if score x2 var >= 1 con if score x2 var < 10 con run scoreboard players operation @s m0 *= 10 con
- execute if score x2 var < 1 con run execute store result score x1 var run data get entity @s Pos[0] 100000
- execute if score x2 var < 1 con run scoreboard players operation @s m0 *= 100 con
- execute if score y2 var >= 10000 con run scoreboard players operation @s m1 = y3 var
- execute if score y2 var >= 1000 con if score y2 var < 10000 con run execute store result score y1 var run data get entity @s Pos[1] 10
- execute if score y2 var >= 1000 con if score y2 var < 10000 con run scoreboard players operation @s m1 /= 100 con
- execute if score y2 var >= 100 con if score y2 var < 1000 con run execute store result score y1 var run data get entity @s Pos[1] 100
- execute if score y2 var >= 100 con if score y2 var < 1000 con run scoreboard players operation @s m1 /= 10 con
- execute if score y2 var >= 10 con if score y2 var < 100 con run execute store result score y1 var run data get entity @s Pos[1] 1000
- execute if score y2 var >= 1 con if score y2 var < 10 con run execute store result score y1 var run data get entity @s Pos[1] 10000
- execute if score y2 var >= 1 con if score y2 var < 10 con run scoreboard players operation @s m1 *= 10 con
- execute if score y2 var < 1 con run execute store result score y1 var run data get entity @s Pos[1] 100000
- execute if score y2 var < 1 con run scoreboard players operation @s m1 *= 100 con
- execute if score z2 var >= 10000 con run scoreboard players operation @s m2 = z3 var
- execute if score z2 var >= 1000 con if score z2 var < 10000 con run execute store result score z1 var run data get entity @s Pos[2] 10
- execute if score z2 var >= 1000 con if score z2 var < 10000 con run scoreboard players operation @s m2 /= 100 con
- execute if score z2 var >= 100 con if score z2 var < 1000 con run execute store result score z1 var run data get entity @s Pos[2] 100
- execute if score z2 var >= 100 con if score z2 var < 1000 con run scoreboard players operation @s m2 /= 10 con
- execute if score z2 var >= 10 con if score z2 var < 100 con run execute store result score z1 var run data get entity @s Pos[2] 1000
- execute if score z2 var >= 1 con if score z2 var < 10 con run execute store result score z1 var run data get entity @s Pos[2] 10000
- execute if score z2 var >= 1 con if score z2 var < 10 con run scoreboard players operation @s m2 *= 10 con
- execute if score z2 var < 1 con run execute store result score z1 var run data get entity @s Pos[2] 100000
- execute if score z2 var < 1 con run scoreboard players operation @s m2 *= 100 con
- # get difference
- scoreboard players operation @s m0 -= x1 var
- scoreboard players operation @s m1 -= y1 var
- scoreboard players operation @s m2 -= z1 var
- #tellraw @a ["",{"text":"x2 = "},{"score":{"name":"x2","objective":"var"},"color":"red"},{"text":", y2 = "},{"score":{"name":"y2","objective":"var"},"color":"blue"},{"text":", z2 = "},{"score":{"name":"z2","objective":"var"},"color":"green"}]
- #tellraw @a ["",{"text":"m0 = "},{"score":{"name":"@s","objective":"m0"},"color":"red"},{"text":", m1 = "},{"score":{"name":"@s","objective":"m1"},"color":"blue"},{"text":", m2 = "},{"score":{"name":"@s","objective":"m2"},"color":"green"}]
复制代码 |
先计算整数位的差值,根据差值的大小动态保留差值的位数,将差值限定到5位数(y=0是个特例)
motionit:relativeconfirm:
- # mark decimal places
- execute if score x2 var >= 10000 con run tag @s add acy0
- execute if score x2 var >= 1000 con if score x2 var < 10000 con run tag @s add acx1
- execute if score x2 var >= 100 con if score x2 var < 1000 con run tag @s add acx2
- execute if score x2 var >= 10 con if score x2 var < 100 con run tag @s add acx3
- execute if score x2 var >= 1 con if score x2 var < 10 con run tag @s add acx4
- execute if score x2 var < 1 con run tag @s add acx5
- execute if score y2 var >= 10000 con run tag @s add acy0
- execute if score y2 var >= 1000 con if score y2 var < 10000 con run tag @s add acy1
- execute if score y2 var >= 100 con if score y2 var < 1000 con run tag @s add acy2
- execute if score y2 var >= 10 con if score y2 var < 100 con run tag @s add acy3
- execute if score y2 var >= 1 con if score y2 var < 10 con run tag @s add acy4
- execute if score y2 var > 0 con if score y2 var < 1 con run tag @s add acy5
- execute if score y2 var = 0 con run tag @s add acy4
- execute if score z2 var >= 10000 con run tag @s add acz0
- execute if score z2 var >= 1000 con if score z2 var < 10000 con run tag @s add acz1
- execute if score z2 var >= 100 con if score z2 var < 1000 con run tag @s add acz2
- execute if score z2 var >= 10 con if score z2 var < 100 con run say 1
- execute if score z2 var >= 10 con if score z2 var < 100 con run tag @s add acz3
- execute if score z2 var >= 1 con if score z2 var < 10 con run tag @s add acz4
- execute if score z2 var < 1 con run tag @s add acz5
复制代码 |
上标签,表示保留多少位,以便于后续的赋值处理。
- 水平方向 (motionit:opx、motionit:opz)
以opx为例:
- # f * m0 / p
- scoreboard players operation a var = f con
- scoreboard players operation a var *= 1000 con
- tellraw @a ["",{"text":"p = "},{"score":{"name":"p","objective":"con"},"color":"yellow"}]
- tellraw @a ["",{"text":"m0 = "},{"score":{"name":"a","objective":"var"},"color":"yellow"}]
- scoreboard players operation a var *= @s m0
- scoreboard players operation a var /= p con
- scoreboard players operation @s m0 = a var
- #tellraw @a ["",{"text":"m0 = "},{"score":{"name":"a","objective":"var"},"color":"yellow"}]
复制代码 |
可以说就是把图中公式用四则运算表示了一遍。
- 竖直方向(motionit:opy)
- # f * m1 - g * t / p
- scoreboard players operation a var = f con
- scoreboard players operation a var *= @s m1
- scoreboard players operation b var = g con
- scoreboard players operation b var *= @s t
- execute if score y2 var >= 1000 con if score y2 var < 10000 con run scoreboard players operation b var *= 10 con
- execute if score y2 var >= 100 con if score y2 var < 1000 con run scoreboard players operation b var *= 100 con
- execute if score y2 var >= 10 con if score y2 var < 100 con run scoreboard players operation b var *= 1000 con
- execute if score y2 var >= 1 con if score y2 var < 10 con run scoreboard players operation b var *= 10000 con
- execute if score y2 var > 0 con if score y2 var < 1 con run scoreboard players operation b var *= 100000 con
- execute if score y2 var = 0 con run scoreboard players operation b var *= 10000 con
- scoreboard players operation a var -= b var
- scoreboard players operation a var /= p con
- scoreboard players operation a var *= 100 con
- #tellraw @a ["",{"text":"f * m1 - g * t / p = "},{"score":{"name":"c","objective":"var"},"color":"yellow"}]
- # g / f - g
- scoreboard players operation c var = g con
- scoreboard players operation c var *= 10000 con
- scoreboard players operation c var /= f con
- scoreboard players operation d var = g con
- scoreboard players operation d var *= 100 con
- scoreboard players operation c var -= d var
- # set
- scoreboard players operation a var += c var
- scoreboard players operation @s m1 = a var
- #tellraw @a ["",{"text":"g / f - g = "},{"score":{"name":"c","objective":"var"},"color":"yellow"}]
复制代码 |
除了表示公式外,还要协调位数,所以竖直方向处理更特殊,这边我就不解释怎么协调得了,看看就行。
- 总流程 (motionit:calculate)
- # avoid momentum loss
- data merge entity @s {NoGravity:1b}
- # get g & f
- execute as @s run function motionit:getparam
- # flexible accurancy
- # get mx/y/z
- execute as @s run function motionit:relativeswitch
- execute as @s run function motionit:relativeconfirm
- # exhaustive method to get constant : p = (1 - (1 - f) ^ t)
- execute if score f con = 0 con run function motionit:pow/0
- execute if score f con = 1 con run function motionit:pow/1
- execute if score f con = 2 con run function motionit:pow/2
- execute if score f con = 5 con run function motionit:pow/5
- # f * mx / p or f * mz / p
- execute as @s run function motionit:opx
- execute as @s run function motionit:opz
- # ( f * my - gt ) / p + g / f - g
- execute as @s run function motionit:opy
- scoreboard players set g con 0
- scoreboard players set f con 0
复制代码 |
把上面一套流程按顺序走了一遍,计算所得的Motion用(m0,m1,m2)表示。
- 赋值 (motionit:go)
- # assign values to motion
- execute as @s[tag=acx0] store result entity @s Motion[0] double 0.1 run scoreboard players get @s m0
- execute as @s[tag=acx1] store result entity @s Motion[0] double 0.01 run scoreboard players get @s m0
- execute as @s[tag=acx2] store result entity @s Motion[0] double 0.001 run scoreboard players get @s m0
- execute as @s[tag=acx3] store result entity @s Motion[0] double 0.0001 run scoreboard players get @s m0
- execute as @s[tag=acx4] store result entity @s Motion[0] double 0.00001 run scoreboard players get @s m0
- execute as @s[tag=acx5] store result entity @s Motion[0] double 0.000001 run scoreboard players get @s m0
- execute as @s[tag=acy0] store result entity @s Motion[1] double 1 run scoreboard players get @s m1
- execute as @s[tag=acy1] store result entity @s Motion[1] double 0.1 run scoreboard players get @s m1
- execute as @s[tag=acy2] store result entity @s Motion[1] double 0.01 run scoreboard players get @s m1
- execute as @s[tag=acy3] store result entity @s Motion[1] double 0.001 run scoreboard players get @s m1
- execute as @s[tag=acy4] store result entity @s Motion[1] double 0.0001 run scoreboard players get @s m1
- execute as @s[tag=acy5] store result entity @s Motion[1] double 0.00001 run scoreboard players get @s m1
- execute as @s[tag=acz0] store result entity @s Motion[2] double 0.1 run scoreboard players get @s m2
- execute as @s[tag=acz1] store result entity @s Motion[2] double 0.01 run scoreboard players get @s m2
- execute as @s[tag=acz2] store result entity @s Motion[2] double 0.001 run scoreboard players get @s m2
- execute as @s[tag=acz3] store result entity @s Motion[2] double 0.0001 run scoreboard players get @s m2
- execute as @s[tag=acz4] store result entity @s Motion[2] double 0.00001 run scoreboard players get @s m2
- execute as @s[tag=acz5] store result entity @s Motion[2] double 0.000001 run scoreboard players get @s m2
- # avoid momentum loss
- data merge entity @s {NoGravity:0b}
复制代码 |
还原位数,然后赋值给Motion。
这里涉及到失重,原因是为了修复一个莫名其妙的动量亏损。也就是说重力状态下,通过命令修改的Motion值会在第二刻突然减弱,而初始化生成实体时设定的Motion不受影响。
- UI
UI的具体细节就不讲了,射线等老技术自己翻翻源码也就明白了。
|