MC弓箭自动瞄准

Hi,我是想射死一只蝙蝠的其实,然而minecraft的手感实在太差了(才不是我菜呢),因此今天我们就将利用datapack做一个弓箭的辅助瞄准,能够预判目标走位以及弹道下坠,最终效果如图。(第一箭空了,因为蝙蝠实在太蛇皮啦!)

我们拿Tag——话说"Tag"这个词还有"#"这个符号被s.bmj赋予的意义太多了——hacker表示神仙,target表示被瞄准的目标,marker表示玩家鼠标要瞄的地方。先来做一个最简单的吧:

  1. # spgoding_hacker:_init/init
  2. # 首先把下面要用到的变量全部定义,以后就不提了,可以不看这部分,都是dummy没什么特别的。
  3. # 储存target的motion
  4. scoreboard objectives add xMotion dummy
  5. scoreboard objectives add yMotion dummy
  6. scoreboard objectives add zMotion dummy
  7. # 储存target位置
  8. scoreboard objectives add xTarget dummy
  9. scoreboard objectives add yTarget dummy
  10. scoreboard objectives add zTarget dummy
  11. # 储存hacker位置
  12. scoreboard objectives add xHacker dummy
  13. scoreboard objectives add yHacker dummy
  14. scoreboard objectives add zHacker dummy
  15. # 储存marker位置
  16. scoreboard objectives add xMarker dummy
  17. scoreboard objectives add yMarker dummy
  18. scoreboard objectives add zMarker dummy
  19. # 储存距离
  20. scoreboard objectives add xDistance dummy
  21. scoreboard objectives add zDistance dummy
  22. scoreboard objectives add d dummy
  23. # 储存marker的变化距离
  24. scoreboard objectives add xDelta dummy
  25. scoreboard objectives add yDelta dummy
  26. scoreboard objectives add zDelta dummy
  27. # 常数
  28. scoreboard objectives add value dummy
  29. scoreboard players set c1 value 1
  30. scoreboard players set c10000 value 10000
  31. scoreboard players set c200 value 200
  32. # 临时变量
  33. scoreboard objectives add tmp dummy
  34. # modules
  35. function spgoding_hacker:sqrt/init

复制代码

  1. # spgoding_hacker:tick
  2. # 给你要瞄准的东西加target
  3. # 这里比较偷懒,正经使用时小心锁上火球之类的东西…
  4. tag @e[type=!player,type=!area_effect_cloud,type=!item,type=!arrow] add target
  5. # 确保有一个marker
  6. execute unless entity @e[tag=marker] run summon area_effect_cloud ~ ~ ~ {Tags:["marker"],Duration:2147483647}
  7. # 获取离hacker最近的target的坐标,放大1000倍
  8. # 当然很容易溢出【摊手,我能怎么办,我也很绝望
  9. execute at @p[tag=hacker] store result score @s xTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[0] 1000
  10. execute at @p[tag=hacker] store result score @s yTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[1] 1000
  11. execute at @p[tag=hacker] store result score @s zTarget run data get entity @e[sort=nearest,tag=target,limit=1] Pos[2] 1000
  12. # 计算出marker的位置
  13. # x坐标:
  14. scoreboard players operation @p[tag=hacker] xMarker = @p[tag=hacker] xTarget
  15. # y坐标:
  16. scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
  17. # z坐标
  18. scoreboard players operation @p[tag=hacker] zMarker = @p[tag=hacker] zTarget
  19. # 改变marker位置
  20. # 为啥不直接tp? 这不是为咱后面做准备嘛
  21. execute store result entity @e[tag=marker,limit=1] Pos[0] double 0.001 run scoreboard players get @p[tag=hacker] xMarker
  22. execute store result entity @e[tag=marker,limit=1] Pos[1] double 0.001 run scoreboard players get @p[tag=hacker] yMarker
  23. execute store result entity @e[tag=marker,limit=1] Pos[2] double 0.001 run scoreboard players get @p[tag=hacker] zMarker
  24. # 让hacker锁定marker
  25. 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坐标,达到玩家准心提高的效果。

  1. # 添加以下命令
  2. # 获取hacker的坐标,放大1000倍
  3. execute store result score @p[tag=hacker] xHacker run data get entity @p[tag=hacker] Pos[0] 1000
  4. execute store result score @p[tag=hacker] yHacker run data get entity @p[tag=hacker] Pos[1] 1000
  5. execute store result score @p[tag=hacker] zHacker run data get entity @p[tag=hacker] Pos[2] 1000
  6. # 计算target与hacker的水平距离(垂直距离呢?那抛物线太玄学了,我们不考虑。假设玩家和目标接近同一水平面。)
  7. # 计算原理:d=√[(x ^2-x^2)^2+(z^2-z^2)^2]
  8. # 下面是计算xDistance^2
  9. scoreboard players operation @p[tag=hacker] xDistance = @p[tag=hacker] xTarget
  10. scoreboard players operation @p[tag=hacker] xDistance -= @p[tag=hacker] xHacker
  11. scoreboard players operation @p[tag=hacker] xDistance *= @p[tag=hacker] xDistance
  12. # 下面计算zDistance^2
  13. scoreboard players operation @p[tag=hacker] zDistance = @p[tag=hacker] zTarget
  14. scoreboard players operation @p[tag=hacker] zDistance -= @p[tag=hacker] zHacker
  15. scoreboard players operation @p[tag=hacker] zDistance *= @p[tag=hacker] zDistance
  16. # 下面算出d
  17. scoreboard players operation @p[tag=hacker] d = @p[tag=hacker] xDistance
  18. scoreboard players operation @p[tag=hacker] d += @p[tag=hacker] zDistance
  19. # 开根号与今天的教程无关,所以spgoding_hacker:sqrt/calculate的
  20. # 内容就不放了,开根号部分大家可以看chyx dalao的讲解,很详细XD:www.bilibili.com/av17932394
  21. # 不知有没有不用开根号的方法?或许我做得太麻烦了,求指点~
  22. scoreboard players operation @p[tag=hacker] sqrtInput = @p[tag=hacker] d
  23. execute as @p[tag=hacker] run function spgoding_hacker:sqrt/calculate
  24. scoreboard players operation @p[tag=hacker] d = @p[tag=hacker] sqrtOutput
  25. # 根据d我们可以算出准心要抬高的距离
  26. # 根据测试,大约每20格,需要抬高准心1格,即
  27. # deltaY = d / 20 * 1 (这其实不很准确,你有更精确的数值/方法可以替换)
  28. # cXX 是玩家假名,其值在_init/init里已经设置为XX
  29. # 所以为什么是c200?我也不知道啊(摊手)瞎加零试出来的#run反正能用
  30. scoreboard players operation @p[tag=hacker] yDelta = @p[tag=hacker] d
  31. scoreboard players operation @p[tag=hacker] yDelta /= c200 value
  32. scoreboard players operation @p[tag=hacker] yDelta *= c1 value
  33. # 计算出marker的位置
  34. # x, z坐标不变,y坐标:
  35. scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
  36. scoreboard players operation @p[tag=hacker] yMarker += @p[tag=hacker] deltaY
  37. # “改变marker位置”开始命令不变,不再赘述

复制代码

现在,我们的准心会根据hacker与target的位置而预判弹道下坠啦。但即使如此,这个挂也只适用于即时命中的弹道武器,很遗憾minecraft vanilla里也没有这种东西。


为了让弓表现得更好,我们可以预判target的走位。原理:根据d,估计出箭到达target的时间;由时间与motion估计出target的位移(显然这是不准确的,但可以保证命中率),由位移计算出marker应当在的位置。

  1. # spgoding_hacker:tick
  2. # 加入以下代码:
  3. # 获取离hacker最近的target的Motion,放大1000倍
  4. 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
  5. 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
  6. 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
  7. # 下面我们预判一下target的走位
  8. # 首先估计一下箭到达target的时间tmp(懒得改名了,就tmp了):
  9. scoreboard players operation @p[tag=hacker] tmp = @p[tag=hacker] d
  10. # 这里的c15000完全是经验之谈【逃
  11. scoreboard players operation @p[tag=hacker] tmp /= c15000 value
  12. # 然后根据tmp和Motion估计一下位移
  13. scoreboard players operation @p[tag=hacker] xDelta = @p[tag=hacker] xMotion
  14. scoreboard players operation @p[tag=hacker] xDelta *= @p[tag=hacker] tmp
  15. scoreboard players operation @p[tag=hacker] zDelta = @p[tag=hacker] zMotion
  16. scoreboard players operation @p[tag=hacker] zDelta *= @p[tag=hacker] tmp
  17. # 计算出marker的位置
  18. # x坐标:
  19. scoreboard players operation @p[tag=hacker] xMarker = @p[tag=hacker] xTarget
  20. scoreboard players operation @p[tag=hacker] xMarker += @p[tag=hacker] xDelta
  21. # y坐标(命令未改动):
  22. scoreboard players operation @p[tag=hacker] yMarker = @p[tag=hacker] yTarget
  23. scoreboard players operation @p[tag=hacker] yMarker += @p[tag=hacker] yDelta
  24. # z坐标
  25. scoreboard players operation @p[tag=hacker] zMarker = @p[tag=hacker] zTarget
  26. scoreboard players operation @p[tag=hacker] zMarker += @p[tag=hacker] zDelta

复制代码

现在,已经是一个完美的辅助瞄准了……吗?并不是,minecraft vanilla里的弓箭有扩散,距离远了以后并不能保证命中率。同时距离过远,target的运动不可预测,这该怎么办呢?


古人曾经说过,

打得准不如接得准

因此,我们可以使用以下一句终极命令,我就用它来结束今天的教程:

  1. #spgoding_hacker:final_tick
  2. execute at @p[tag=hacker] run teleport @e[tag=target,limit=1,sort=nearest] ^ ^ ^1

复制代码

发表评论

您必须 登录 才能发表留言!