Hi,我是想射死一只蝙蝠的其实,然而minecraft的手感实在太差了(才不是我菜呢),因此今天我们就将利用datapack做一个弓箭的辅助瞄准,能够预判目标走位以及弹道下坠,最终效果如图。(第一箭空了,因为蝙蝠实在太蛇皮啦!)
我们拿Tag——话说"Tag"这个词还有"#"这个符号被s.bmj赋予的意义太多了——hacker表示神仙,target表示被瞄准的目标,marker表示玩家鼠标要瞄的地方。先来做一个最简单的吧:
- # spgoding_hacker:_init/init
- # 首先把下面要用到的变量全部定义,以后就不提了,可以不看这部分,都是dummy没什么特别的。
- # 储存target的motion
- scoreboard objectives add xMotion dummy
- scoreboard objectives add yMotion dummy
- scoreboard objectives add zMotion dummy
- # 储存target位置
- scoreboard objectives add xTarget dummy
- scoreboard objectives add yTarget dummy
- scoreboard objectives add zTarget dummy
- # 储存hacker位置
- scoreboard objectives add xHacker dummy
- scoreboard objectives add yHacker dummy
- scoreboard objectives add zHacker dummy
- # 储存marker位置
- scoreboard objectives add xMarker dummy
- scoreboard objectives add yMarker dummy
- scoreboard objectives add zMarker dummy
- # 储存距离
- scoreboard objectives add xDistance dummy
- scoreboard objectives add zDistance dummy
- scoreboard objectives add d dummy
- # 储存marker的变化距离
- scoreboard objectives add xDelta dummy
- scoreboard objectives add yDelta dummy
- scoreboard objectives add zDelta dummy
- # 常数
- scoreboard objectives add value dummy
- scoreboard players set c1 value 1
- scoreboard players set c10000 value 10000
- scoreboard players set c200 value 200
- # 临时变量
- scoreboard objectives add tmp dummy
- # modules
- function spgoding_hacker:sqrt/init
复制代码
- # spgoding_hacker:tick
- # 给你要瞄准的东西加target
- # 这里比较偷懒,正经使用时小心锁上火球之类的东西…
- tag @e[type=!player,type=!area_effect_cloud,type=!item,type=!arrow] add target
- # 确保有一个marker
- execute unless entity @e[tag=marker] run summon area_effect_cloud ~ ~ ~ {Tags:["marker"],Duration:2147483647}
- # 获取离hacker最近的target的坐标,放大1000倍
- # 当然很容易溢出【摊手,我能怎么办,我也很绝望
- execute at @p[tag=hacker] store result score @s xTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[0] 1000
- execute at @p[tag=hacker] store result score @s yTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[1] 1000
- execute at @p[tag=hacker] store result score @s zTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[2] 1000
- # 计算出marker的位置
- # x坐标:
- scoreboard players operation @p[tag=hacker] xMarker = @p[tag=hacker] xTarget
- # y坐标:
- scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
- # z坐标
- scoreboard players operation @p[tag=hacker] zMarker = @p[tag=hacker] zTarget
- # 改变marker位置
- # 为啥不直接tp? 这不是为咱后面做准备嘛
- execute store result entity @e[tag=marker,limit=1] Pos[0] double 0.001 run scoreboard players get @p[tag=hacker] xMarker
- execute store result entity @e[tag=marker,limit=1] Pos[1] double 0.001 run scoreboard players get @p[tag=hacker] yMarker
- execute store result entity @e[tag=marker,limit=1] Pos[2] double 0.001 run scoreboard players get @p[tag=hacker] zMarker
- # 让hacker锁定marker
- execute as @p[tag=hacker] at @s anchored eyes if entity @e[tag=target,sort=nearest,limit=1] run tp @s ~ ~ ~ facing entity @e[tag=marker,limit=1] eyes
复制代码
reload,然后使用/tag add @s hacker把自己变成神仙,弄几只动物,你就发现准心会锁着离你最近的target了。但现在这个辅助瞄准只适合即时命中且无重力的这类武器,可惜mc vanilla里并没有这种东西存在。远距离我们的辅助瞄准根本没用,因此我们做一些更改。
首先使其能够预判弹道下坠。原理:根据target与hacker之间的距离,改变marker的y坐标,达到玩家准心提高的效果。
- # 添加以下命令
- # 获取hacker的坐标,放大1000倍
- execute store result score @p[tag=hacker] xHacker run data get entity @p[tag=hacker] Pos[0] 1000
- execute store result score @p[tag=hacker] yHacker run data get entity @p[tag=hacker] Pos[1] 1000
- execute store result score @p[tag=hacker] zHacker run data get entity @p[tag=hacker] Pos[2] 1000
- # 计算target与hacker的水平距离(垂直距离呢?那抛物线太玄学了,我们不考虑。假设玩家和目标接近同一水平面。)
- # 计算原理:d=√[(x ^2-x^2)^2+(z^2-z^2)^2]
- # 下面是计算xDistance^2
- scoreboard players operation @p[tag=hacker] xDistance = @p[tag=hacker] xTarget
- scoreboard players operation @p[tag=hacker] xDistance -= @p[tag=hacker] xHacker
- scoreboard players operation @p[tag=hacker] xDistance *= @p[tag=hacker] xDistance
- # 下面计算zDistance^2
- scoreboard players operation @p[tag=hacker] zDistance = @p[tag=hacker] zTarget
- scoreboard players operation @p[tag=hacker] zDistance -= @p[tag=hacker] zHacker
- scoreboard players operation @p[tag=hacker] zDistance *= @p[tag=hacker] zDistance
- # 下面算出d
- scoreboard players operation @p[tag=hacker] d = @p[tag=hacker] xDistance
- scoreboard players operation @p[tag=hacker] d += @p[tag=hacker] zDistance
- # 开根号与今天的教程无关,所以spgoding_hacker:sqrt/calculate的
- # 内容就不放了,开根号部分大家可以看chyx dalao的讲解,很详细XD:www.bilibili.com/av17932394
- # 不知有没有不用开根号的方法?或许我做得太麻烦了,求指点~
- scoreboard players operation @p[tag=hacker] sqrtInput = @p[tag=hacker] d
- execute as @p[tag=hacker] run function spgoding_hacker:sqrt/calculate
- scoreboard players operation @p[tag=hacker] d = @p[tag=hacker] sqrtOutput
- # 根据d我们可以算出准心要抬高的距离
- # 根据测试,大约每20格,需要抬高准心1格,即
- # deltaY = d / 20 * 1 (这其实不很准确,你有更精确的数值/方法可以替换)
- # cXX 是玩家假名,其值在_init/init里已经设置为XX
- # 所以为什么是c200?我也不知道啊(摊手)瞎加零试出来的#run反正能用
- scoreboard players operation @p[tag=hacker] yDelta = @p[tag=hacker] d
- scoreboard players operation @p[tag=hacker] yDelta /= c200 value
- scoreboard players operation @p[tag=hacker] yDelta *= c1 value
- # 计算出marker的位置
- # x, z坐标不变,y坐标:
- scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
- scoreboard players operation @p[tag=hacker] yMarker += @p[tag=hacker] deltaY
- # “改变marker位置”开始命令不变,不再赘述
复制代码
现在,我们的准心会根据hacker与target的位置而预判弹道下坠啦。但即使如此,这个挂也只适用于即时命中的弹道武器,很遗憾minecraft vanilla里也没有这种东西。
为了让弓表现得更好,我们可以预判target的走位。原理:根据d,估计出箭到达target的时间;由时间与motion估计出target的位移(显然这是不准确的,但可以保证命中率),由位移计算出marker应当在的位置。
- # spgoding_hacker:tick
- # 加入以下代码:
- # 获取离hacker最近的target的Motion,放大1000倍
- execute as @p[tag=hacker] at @s store result score @s xMotion run data get entity @e[sort=nearest,tag=target,limit=1] Motion[0] 1000
- execute as @p[tag=hacker] at @s store result score @s yMotion run data get entity @e[sort=nearest,tag=target,limit=1] Motion[1] 1000
- execute as @p[tag=hacker] at @s store result score @s zMotion run data get entity @e[sort=nearest,tag=target,limit=1] Motion[2] 1000
- # 下面我们预判一下target的走位
- # 首先估计一下箭到达target的时间tmp(懒得改名了,就tmp了):
- scoreboard players operation @p[tag=hacker] tmp = @p[tag=hacker] d
- # 这里的c15000完全是经验之谈【逃
- scoreboard players operation @p[tag=hacker] tmp /= c15000 value
- # 然后根据tmp和Motion估计一下位移
- scoreboard players operation @p[tag=hacker] xDelta = @p[tag=hacker] xMotion
- scoreboard players operation @p[tag=hacker] xDelta *= @p[tag=hacker] tmp
- scoreboard players operation @p[tag=hacker] zDelta = @p[tag=hacker] zMotion
- scoreboard players operation @p[tag=hacker] zDelta *= @p[tag=hacker] tmp
- # 计算出marker的位置
- # x坐标:
- scoreboard players operation @p[tag=hacker] xMarker = @p[tag=hacker] xTarget
- scoreboard players operation @p[tag=hacker] xMarker += @p[tag=hacker] xDelta
- # y坐标(命令未改动):
- scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
- scoreboard players operation @p[tag=hacker] yMarker += @p[tag=hacker] yDelta
- # z坐标
- scoreboard players operation @p[tag=hacker] zMarker = @p[tag=hacker] zTarget
- scoreboard players operation @p[tag=hacker] zMarker += @p[tag=hacker] zDelta
复制代码
现在,已经是一个完美的辅助瞄准了……吗?并不是,minecraft vanilla里的弓箭有扩散,距离远了以后并不能保证命中率。同时距离过远,target的运动不可预测,这该怎么办呢?
古人曾经说过,
打得准不如接得准
因此,我们可以使用以下一句终极命令,我就用它来结束今天的教程:
- #spgoding_hacker:final_tick
- execute at @p[tag=hacker] run teleport @e[tag=target,limit=1,sort=nearest] ^ ^ ^1
复制代码