1.10版本的时候就能利用船做到免穷举让实体前/后移动了,但是这样需要使用很多实体,效率并不是很高,使用起来也并不方便。并且这种方法只能做到在平面上移动,无法上下移动。那么,有没有更好的方法呢?
众所周知,两点确定一条直线,如果知道了实体面向的方向上的任意两点,那么就可以确定实体面对的方向。1.13的局部坐标可以很方便的做到这一点。将它转化为Motion值就可以让实体沿着面朝的方向移动了。
效果图:
也可以让盔甲架跳起来:
原理讲解:
- scoreboard objectives add click minecraft.used:minecraft.carrot_on_a_stick
- scoreboard objectives add coordinate1 dummy
- scoreboard objectives add coordinate2 dummy
复制代码
添加三个计分板,click用来触发(当然如果不用萝卜钓竿来触发的话这个计分板可以省略),coordinate1和coordinate2分别来记录实体前1格的坐标值和当前这一格的坐标值。
(以下所有指令均为高频)
- execute if entity @a[scores={click=1..100}] run tag @e[type=armor_stand] add move
复制代码
给盔甲架加上一个move标签,这里偷懒直接用萝卜钓竿来触发。这只是拿盔甲架来做一个演示,实际应用的时候tag后的选择器可以根据需要更改
- execute as @e[tag=move] at @s offset ^ ^ ^1 run summon area_effect_cloud ~ ~ ~ {CustomName:"destination"}
复制代码
在实体眼前1格的位置生成一个名为“destination”的药水云,用来确定实体方向
- execute as @e[tag=move] store result score @s coordinate1 run data get entity @e[limit=1,type=area_effect_cloud,name=destination] Pos[0] 100000
复制代码
将药水云的x坐标存到待移动实体的coordinate1计分板内,为保留精度,乘以100000倍。
- execute as @e[tag=move] store result score @s coordinate2 run data get entity @s Pos[0] 100000
复制代码
将待移动实体的x坐标存进自己的coordinate2计分板内,为保留精度,乘以100000倍
- execute as @e[tag=move] run scoreboard players operation @s coordinate1 -= @s coordinate2
复制代码
用待移动实体的coordinate1计分板减去coordinate2计分板
- execute as @e[tag=move] store result entity @s Motion[0] double 0.00001 run scoreboard players get @s coordinate1
复制代码
得到的值存到待移动实体的x方向Motion上,乘0.00001还原本来的倍数。如果需要将实体运动的速度调快或是调慢的话,就将这个数调大或是调小。
- execute as @e[tag=move] store result score @s coordinate1 run data get entity @e[limit=1,type=area_effect_cloud,name=destination] Pos[1] 100000
- execute as @e[tag=move] store result score @s coordinate2 run data get entity @s Pos[1] 100000
- execute as @e[tag=move] run scoreboard players operation @s coordinate1 -= @s coordinate2
- execute as @e[tag=move] store result entity @s Motion[1] double 0.00001 run scoreboard players get @s coordinate1
- execute as @e[tag=move] store result score @s coordinate1 run data get entity @e[limit=1,type=area_effect_cloud,name=destination] Pos[2] 100000
- execute as @e[tag=move] store result score @s coordinate2 run data get entity @s Pos[2] 100000
- execute as @e[tag=move] run scoreboard players operation @s coordinate1 -= @s coordinate2
- execute as @e[tag=move] store result entity @s Motion[2] double 0.00001 run scoreboard players get @s coordinate1
复制代码
与之前四条指令同样的方式处理y轴、z轴
- kill @e[name=destination]
- tag @e remove move
复制代码
清掉药水云,移除move标签,初始化
这种方式的另一个好处是用Motion移动代替了高频tp移动,总感觉以前一格格tp移动很不圆滑...并且还容易出bug,特别是对弓箭一类的实体用起来不太方便。于是在这个基础上稍加改进便做成了一把连弩:
不知道为什么箭会在面前卡一下,但其实是射出去的。
原理就是用玩家来做那个“待移动实体”,在面前生成一支箭,获取Motion值之后加到那个箭上。
感谢@pca006132 的优化,其实盔甲架的移动只需要7条指令,道理与前文相同,优化之处是如果把待移动实体的位置看为坐标原点,那么marker的位置就是实体的motion,这样就省去了两个计分板和坐标相减的过程。
指令:
- execute if entity @a[scores={click=1..100}] run tag @e[type=armor_stand] add move
- execute as @e[tag=move] offset 0.0 0.0 0.0 run tp @e[type=area_effect_cloud,name=marker] ^ ^ ^1
- execute as @e[tag=move] store result entity @s Motion[0] double 0.00001 run data get entity @e[limit=1,type=area_effect_cloud,name=marker] Pos[0] 100000
- execute as @e[tag=move] store result entity @s Motion[1] double 0.00001 run data get entity @e[limit=1,type=area_effect_cloud,name=marker] Pos[1] 100000
- execute as @e[tag=move] store result entity @s Motion[2] double 0.00001 run data get entity @e[limit=1,type=area_effect_cloud,name=marker] Pos[2] 100000
- scoreboard players set @a click 0
- tag @e remove move