🏃 移动(Move)#

#bs.move:help

Move entities along a velocity vector, with collision handling.

../../_images/move.png

唯有变化才是永恒。

—赫拉克利特(Heraclitus)

观看演示


🔧 函数#

你可以在下方找到此模块中的所有可用函数。


应用速度#

#bs.move:apply_vel {scale:<scaling>,with:{}}

在处理碰撞的同时,根据实体的速度分数进行传送。λ 分数仅在回调执行期间可用(on_*)。

输入:

执行 as <实体>:要移动的实体。

分数 @s bs.vel.[x,y,z]:标准速度向量。

函数宏

  • 参数

    • scale: 输出的缩放系数。

    • with: 碰撞设置。

      • blocks:实体是否应与方块碰撞(默认:true)。 可以是碰撞箱提供器(例如 function #bs.hitbox:callback/get_block_collision)。

      • entities:实体是否应与其他实体碰撞(默认:false)。 可以是选择器标签(通常通过 /tag 分配),出于性能考虑推荐使用。

      • ignored_blocks: 要忽略的方块(默认:#bs.hitbox:can_pass_through)。

      • ignored_entities:要忽略的实体类型(默认:#bs.hitbox:intangible)。 不适用于具有自定义碰撞箱的实体。

      • on_collision:碰撞发生时运行的命令。 用于解决碰撞(默认:function #bs.move:callback/bounce)。

Lambda 表达式:

分数 $move.hit_face bs.lambda:被击中的边界盒的面:5 是东,4 是西,3 是南,2 是北,1 是顶,0 是底。

分数 $move.hit_flag bs.lambda:相交边界盒的标志,-1 表示实体。

分数 $move.vel.[x,y,z] bs.lambda:碰撞调整后规范坐标中的剩余速度。

输出:

状态:实体根据其速度分数被传送。

#bs.move:apply_local_vel {scale:<scaling>,with:{}}

实验性

始终优先使用标准版本。基数之间的持续转换可能导致精度损失,有时会造成不可预测的行为。

如果需要向某个方向「发射」实体,仍可将速度设置为局部向量,并在使用 #bs.move:apply_vel 之前运行 #bs.move:local_to_canonical

使用局部坐标系,根据实体的速度分数进行传送,同时处理碰撞。λ 分数仅在回调执行期间可用(on_*)。

输入:

执行 as <实体>:要移动的实体。

分数 @s bs.vel.[x,y,z]:局部速度向量。

函数宏

  • 参数

    • scale: 输出的缩放系数。

    • with: 碰撞设置。

      • blocks:实体是否应与方块碰撞(默认:true)。 可以是碰撞箱提供器(例如 function #bs.hitbox:callback/get_block_collision)。

      • entities:实体是否应与其他实体碰撞(默认:false)。 可以是选择器标签(通常通过 /tag 分配),出于性能考虑推荐使用。

      • ignored_blocks: 要忽略的方块(默认:#bs.hitbox:can_pass_through)。

      • ignored_entities:要忽略的实体类型(默认:#bs.hitbox:intangible)。 不适用于具有自定义碰撞箱的实体。

      • on_collision: 当碰撞时运行的命令,用来解决碰撞问题(默认: function #bs.move:callback/bounce)。

Lambda 表达式:

分数 $move.hit_face bs.lambda:被击中的边界盒的面。

分数 $move.hit_flag bs.lambda:相交边界盒的标志,-1 表示实体。

分数 $move.vel.[x,y,z] bs.lambda:碰撞调整后规范坐标中的剩余速度。

输出:

状态:实体根据其局部速度分数被传送。

什么是边界盒?

边界框是一个简单的矩形框,环绕物体(或物体的一部分),帮助游戏确定其位置和接触对象。例如,Minecraft 中的一组楼梯使用两个边界框:一个用于下台阶,一个用于上台阶。

自定义碰撞箱

Bookshelf 支持多种 hitbox 类型,以实现精准控制。方块可使用自定义 hitbox 提供器。实体支持三种类型:dynamicbakedcustom

示例:根据速度分数移动立方体(block_display)(使用交互实体作为碰撞箱):

# Once
summon minecraft:block_display ~ ~ ~ {block_state:{Name:"stone"},teleport_duration:3,transformation:[1f,0f,0f,-0.5f,0f,1f,0f,0f,0f,0f,1f,-0.5f,0f,0f,0f,1f],Passengers:[{id:"minecraft:interaction",width:1f,height:1f}]}
scoreboard players set @e[type=minecraft:block_display] bs.vel.x 100
scoreboard players set @e[type=minecraft:block_display] bs.vel.y 20
scoreboard players set @e[type=minecraft:block_display] bs.vel.z 50

# In a loop
execute as @e[type=minecraft:block_display] run function #bs.move:apply_vel {scale:0.001,with:{}}

# Choose between multiple collision behaviors
execute as @e[type=minecraft:block_display] run function #bs.move:apply_vel {scale:0.001,with:{on_collision:"function #bs.move:callback/bounce"}}
execute as @e[type=minecraft:block_display] run function #bs.move:apply_vel {scale:0.001,with:{on_collision:"function #bs.move:callback/damped_bounce"}}
execute as @e[type=minecraft:block_display] run function #bs.move:apply_vel {scale:0.001,with:{on_collision:"function #bs.move:callback/slide"}}
execute as @e[type=minecraft:block_display] run function #bs.move:apply_vel {scale:0.001,with:{on_collision:"function #bs.move:callback/stick"}}

性能提示

虽然此系统没有设置具体限制,但需要注意性能受实体的速度和大小的影响。

贡献者:Aksiome


标准转局部#

#bs.move:canonical_to_local

将标准速度(使用相对坐标系)转换为局部速度(使用局部坐标系)。

输入:

执行 rotated as <entity>rotated <h> <v>:用于转换的旋转。

分数 @s bs.vel.[x,y,z]:要转换的速度。

输出:

分数 @s bs.vel.[x,y,z]:转换后的速度。

什么是局部速度?

与相对速度(标准)不同,此参考系考虑实体的旋转。因此,当父实体旋转时,子实体围绕它旋转。对熟悉 Minecraft 命令的人来说,局部坐标可通过 ^ 符号使用。

贡献者:Aksiome


局部转标准#

#bs.move:local_to_canonical

将局部速度(使用局部坐标系)转换为标准速度(使用相对坐标系)。

输入:

执行 rotated as <entity>rotated <h> <v>:用于转换的旋转。

分数 @s bs.vel.[x,y,z]:要转换的速度。

输出:

分数 @s bs.vel.[x,y,z]:转换后的速度。

什么是局部速度?

与相对速度(标准)不同,此参考系考虑实体的旋转。因此,当父实体旋转时,子实体围绕它旋转。对熟悉 Minecraft 命令的人来说,局部坐标可通过 ^ 符号使用。

贡献者:Aksiome


设置运动#

#bs.move:set_motion {scale:<scaling>}

使用速度分数设置实体的运动(Motion)NBT。

输入:

执行 as <实体>:要移动的实体。

分数 @s bs.vel.[x,y,z]:速度向量。

函数宏

  • 参数

    • scale: 输出的缩放系数。

输出:

状态:运动被应用到给定实体。

示例:根据速度分数移动猪:

# Once
summon minecraft:pig ~ ~ ~
scoreboard players set @e[type=minecraft:pig] bs.vel.x 50
scoreboard players set @e[type=minecraft:pig] bs.vel.y 25
scoreboard players set @e[type=minecraft:pig] bs.vel.z 0

# In a loop
execute as @e[type=minecraft:pig] run function #bs.move:set_motion {scale:0.001}

贡献者:Aksiome


👁️ 谓词#

你可以在下方找到此模块中的所有可用谓词。


有速度?#

bs.move:has_vel

确定实体是否有非零速度分数。

贡献者:Aksiome


🎓 自定义碰撞#

此模块允许你根据特定需求自定义碰撞行为。


通过修改 on_collision 输入参数,你可以自由指定碰撞时触发的函数。不过,自行处理碰撞比较复杂,因此 Bookshelf 提供了多个预定义函数:

#bs.move:callback/bounce

实体将在碰撞表面反弹。

#bs.move:callback/damped_bounce

实体速度在每次反弹时减少2。

#bs.move:callback/slide

实体将粘附并沿碰撞表面滑动。

#bs.move:callback/stick

实体将停止并粘附在碰撞表面上。

工作原理#

当发生碰撞时,系统使用速度和该边界框的标志来追踪被击中的边界框。你可以修改:

  • @s bs.vel.[x,y,z]:将在下一个游戏刻应用的速度。

  • $move.vel.[x,y,z] bs.lambda:回退到碰撞时刻后剩余的速度。

创建自定义行为时无需直接处理局部速度;向量会在碰撞处理前后自动转换。

速度缩放

剩余速度值以缩放整数的形式存储,但缩放系数可随时变更,并且这不破坏兼容性。

为了确保稳定性,请保持计算操作和缩放系数无关。

最简单的碰撞处理是停止移动。

#bs.move:callback/stick

# set all components to 0 to cancel the movement
execute store result score $move.vel.x bs.lambda run scoreboard players set @s bs.vel.x 0
execute store result score $move.vel.y bs.lambda run scoreboard players set @s bs.vel.y 0
execute store result score $move.vel.z bs.lambda run scoreboard players set @s bs.vel.z 0

对于滑动,我们需要取消被阻挡的轴上的速度,并继续行进剩余距离。

#bs.move:callback/slide

# set a component to 0 depending on the surface that was hit.
execute if score $move.hit_face bs.lambda matches 4..5 store result score $move.vel.x bs.lambda run scoreboard players set @s bs.vel.x 0
execute if score $move.hit_face bs.lambda matches 0..1 store result score $move.vel.y bs.lambda run scoreboard players set @s bs.vel.y 0
execute if score $move.hit_face bs.lambda matches 2..3 store result score $move.vel.z bs.lambda run scoreboard players set @s bs.vel.z 0

标记和标签#

标记和标签让你控制实体如何与多个重叠的边界框交互,例如,允许穿过流体形状,同时停在固体形状处。

  • 每个边界框都有一个数值 flag1248)。

  • 当实体进入一个边界框时,它会收到标签 bs.move.flag.<flag>,这可以防止在具有相同标志的边界框内重复碰撞。一旦实体不再位于任何具有相同标志的边界框内,该标签就会被移除。

在使用处理流体的 碰撞箱提供器 时,标记特别有用。例如,下面是积水楼梯的响应方式:

  1. 楼梯有两种类型的边界框:

    • 流体(水)带标志 2

    • 固体(楼梯本身)带标志 1

  2. 实体进入水中:

    • 触发 on_collision

    • 我们可以选择保留沿碰撞轴的速度。

    • 实体收到 bs.move.flag.2

    • 当此标签激活时,与其他水方块或流体形状的碰撞不会发生任何作用,因此实体在流体中平滑移动。

  3. 实体击中楼梯的固体部分:

    • 再次触发 on_collision

    • 这次我们反转速度(弹跳)。

    • 没有设置标签,因此与其他固体形状的碰撞正常处理。

    • 实体按预期停止或弹开,如同正常的固体碰撞。

如果你需要自定义碰撞方面的帮助,可以在我们的 Discord 服务器 上提问!


💬 这对你有帮助吗?

欢迎在下方留下你的问题和反馈!