Skip to content

骑上去的一瞬间,你被抬高了多少?全实体“乘骑座位高度”探究

我吃大白菜

我吃大白菜

前言 ​

当你骑着马在原野上飞驰,或是骑着驴,忽然想cos一把倒骑毛驴的阿凡提;又或者,你手一痒敲了条命令,把自己塞到一只恶魂、一头凋灵、甚至一条末影龙身上时,你是否想过,在你“坐上去”的那一刻,你的身体,到底被抬到了多高的位置?

为什么要研究这个 ​

说实话,用途可能不大,但毕竟也算个小发现。我个人是把它用在动画实体的乘骑上。至于还能拿它玩出什么花样,就交给各位读者去开发了。

抬升高度是怎么算出来的 ​

游戏给每个实体都记了几个“挂点”,其中管乘客的那个叫 乘客点(PASSENGER):谁骑上来,就把谁放到这个点。它的缺省规则写在 EntityAttachment 里,没特别指定时,乘客点就落在身高的最顶端(AT_HEIGHT):

下面的 Java 都由 26.1.2 的反编译字节码还原。

public enum EntityAttachment {
    PASSENGER(Fallback.AT_HEIGHT),   // 谁骑我 → 缺省坐在我“身高顶端”
    VEHICLE  (Fallback.AT_FEET),     // 我骑谁 → 我的参考点在“脚底”
    NAME_TAG (Fallback.AT_HEIGHT), WARDEN_CHEST(Fallback.AT_CENTER);
}
enum Fallback {
    AT_FEET  { List<Vec3> create(float w, float h){ return List.of(Vec3.ZERO);          } },  // (0, 0,   0)
    AT_HEIGHT{ List<Vec3> create(float w, float h){ return List.of(new Vec3(0, h,   0)); } },  // (0, 身高, 0)
    AT_CENTER{ List<Vec3> create(float w, float h){ return List.of(new Vec3(0, h/2, 0)); } };
}

摆放乘客的逻辑在 Entity 里:先算出载体给的座位(载体位置 + 乘客点,而且乘客点会被载体的 scale 一起缩放),再减掉乘客自己的参考点:

public Vec3 getPassengerRidingPosition(Entity passenger) {
    return position().add(getPassengerAttachmentPoint(passenger, getDimensions(getPose()), getScale()));
}
protected void positionRider(Entity passenger, MoveFunction move) {
    Vec3 seat = getPassengerRidingPosition(passenger);      // 载体给的座位
    Vec3 self = passenger.getVehicleAttachmentPoint(this);  // 乘客自己的参考点(展示实体=脚底=0)
    move.accept(passenger, seat.x - self.x, seat.y - self.y, seat.z - self.z);
}

展示实体自己的参考点就在脚底(0),于是它正好落在载体的乘客点上。所以问题只剩一个:每种实体的乘客点到底是多少?

一部分怪没特别设,就用“身高顶端”(例如骷髅、村民)。但很多实体,不只是坐骑,连僵尸、尸壳这些普通怪也硬编码了自定义值。这个数写死在代码里,跟碰撞箱没有固定关系,甚至可能高过头顶。比如尸壳:

HUSK = register("husk", EntityType.Builder.of(Husk::new, MobCategory.MONSTER)
    .sized(0.6f, 1.95f)              // 碰撞箱:宽 0.6、高 1.95
    .eyeHeight(1.74f)
    .passengerAttachments(2.075f)    // ← 乘客坐 2.075,硬编码,比头顶高 0.125
    .ridingOffset(-0.7f)             // (这是“husk 骑别人”时的偏移,与“谁骑 husk”无关)
    .clientTrackingRange(8).notInPeaceful());

碰撞箱才 1.95 高,乘客点却写死成 2.075(比头顶高 0.125,多半是想让骑手“站”在头上、而不是陷进脑袋);僵尸同理是 2.0125。

ldc  #1121  // float 1.95f     ← sized 的高
invokevirtual EntityType$Builder.sized:(FF)
ldc  #947   // float 1.74f
invokevirtual EntityType$Builder.eyeHeight:(F)
iconst_1; newarray float; dup; iconst_0
ldc  #1335  // float 2.075f    ← 塞进 passengerAttachments 的值
fastore
invokevirtual EntityType$Builder.passengerAttachments:([F)

反过来,坐骑常让你坐进身体里:马的乘客点只有 1.44375,比 1.6 的马背还低(你是坐进鞍里)。另外有 9 个实体(马 / 驴 / 羊驼 / 骆驼 / 鸡 / 狐狸 / 青蛙 / 海龟 / 狼 / 劫掠兽 / 快乐恶魂)用的是 Vec3(0, 座位Y, 前后偏移) 的写法,座位高是第一个 Y:

HORSE = register("horse", EntityType.Builder.of(Horse::new, MobCategory.ANIMAL)
    .sized(1.3964844f, 1.6f).eyeHeight(1.52f)
    .passengerAttachments(1.44375f));               // 单值:坐 1.44375

WOLF = register("wolf", EntityType.Builder.of(Wolf::new, MobCategory.ANIMAL)
    .sized(0.6f, 0.85f).eyeHeight(0.68f)
    .passengerAttachments(new Vec3(0.0, 0.81875, -0.0625)));  // Y=0.81875 才是座位高,-0.0625 是前后偏移

(灾厄村民传的是空乘客点,属特殊情况,表里按“坐头顶”近似。矿车 0.1875 几乎贴轨道、骆驼是前后双座,也都各自写死)。

当你骑上去,你的脚就被挪到 载体位置 + 座位高度 × scale。总结出来就是,玩家被抬的高度 = 那个载体的“座位高度”。剩下的就是把每种实体的这个数字读出来。

常见实体的座位高度 ​

单位是方块(scale=1)。★ = 游戏单独设的自定义座位,其余 = “坐头顶”(等于身高)。

载体座位高度备注
末影龙 ender_dragon ★3.00坐龙背
监守者 warden ★3.15
恶魂 ghast ★4.06全场最高
铁傀儡 iron_golem2.70坐头顶
骆驼 camel ★2.375双座
女巫 witch ★2.26
尸壳 husk ★2.075
僵尸 zombie ★2.0125和尸壳略有不同!
骷髅 skeleton1.99坐头顶
村民 villager1.95坐头顶
马 horse ★1.44375坐进鞍里,比马背低
驴 donkey ★1.11阿凡提就坐这么高
羊驼 llama ★1.37
牛 cow ★1.37
猪 pig ★0.87胡萝卜钓竿骑的那位
狼 wolf ★0.82
蜘蛛 spider ★0.765蜘蛛骑士
鸡 chicken ★0.70鸡骑士就是蹲这儿
船 boat ★0.5625坐得很低,双座
矿车 minecart ★0.1875几乎贴着轨道

全实体座位高度总表 ​

下面是26.1版本中所有能确定数值的实体(157 个,含飞行物/掉落物等一切有乘客点的实体)。按高度从高到低。0(无碰撞) = 标记/展示实体这类没有体积的,乘客坐在原点。

点开查看完整表格
实体 id座位高度
giant12.0
ghast4.0625
wither3.5
warden3.15
ender_dragon3.0
enderman2.80625
iron_golem2.7
creaking2.7
wither_skeleton2.4
camel2.375
camel_husk2.375
elder_guardian2.350625
witch2.2625
ravager2.2625
zombie_villager2.125
sniffer2.09375
husk2.075
zombie2.0125
drowned2.0125
piglin2.0125
piglin_brute2.0125
zombified_piglin2.0125
stray1.99
skeleton1.99
bogged1.99
parched1.99
armor_stand1.975
villager1.95
wandering_trader1.95
vindicator1.95
pillager1.95
evoker1.95
illusioner1.95
snow_golem1.9
blaze1.8
player1.8
mannequin1.8
breeze1.77
strider1.7
happy_ghast1.7
creeper1.7
zoglin1.49375
hoglin1.49375
horse1.44375
polar_bear1.4
llama1.37
trader_llama1.37
cow1.36875
mooshroom1.36875
zombie_horse1.31875
skeleton_horse1.31875
panda1.25
shulker1.2375
sheep1.2375
mule1.2125
nautilus1.1375
zombie_nautilus1.1375
goat1.1125
donkey1.1125
dragon_fireball1.1125
tnt0.98
falling_block0.98
fireball0.98
copper_golem0.98
guardian0.975
bat0.9
pig0.86875
wolf0.81875
squid0.8
glow_squid0.8
evoker_fangs0.8
spider0.765
vex0.7375
chicken0.7
pufferfish0.7
armadillo0.65
ocelot0.6375
fox0.6375
rabbit0.6
dolphin0.6
bee0.6
allay0.6
boat(各木种/竹筏,含运输船)0.5625
turtle0.55625
slime0.52
magma_cube0.52
cat0.5125
cave_spider0.5
arrow / spectral_arrow / trident0.5
item_frame / glow_item_frame / painting / leash_knot0.5
experience_orb / area_effect_cloud0.5
parrot0.4625
axolotl0.42
salmon / tropical_fish0.4
frog0.375
phantom0.3375
wither_skull / wind_charge / breeze_wind_charge / small_fireball / shulker_bullet0.3125
cod / tadpole0.3
egg / snowball / ender_pearl / splash_potion / lingering_potion0.25
experience_bottle / eye_of_ender / firework_rocket / fishing_bobber0.25
item / llama_spit / ominous_item_spawner / end_crystal0.25
silverfish0.2375
endermite0.2375
minecart(各类)0.1875
lightning_bolt0.0625
marker / item_display / block_display / text_display / interaction0(无碰撞)

结语 ​

骑上去能抬多高这个问题,以前我一直搞不懂到底是个什么规则。今日心血来潮翻了翻源代码,方才恍然大悟。用途嘛,前面也说了,可能真不大。但能把它挖清楚,这过程本身也挺有成就感的。至于这些数字往后能被谁、拿去玩出点什么,就交给屏幕前的你了。

Powered by Vitepress and Github Pages