多的不说,先看代码:
//collideBoundingBox(碰撞检测/调整),输出的是三维向量Vec3
//p_20273_可以看作游戏还没处理碰撞前的位移
private Vec3 collide(Vec3 p_20273_) {
//获取实体碰撞箱,赋值给AABB
AABB aabb = this.getBoundingBox();
/*
VoxelShape和方块碰撞箱相关?
level应该是维度或者处理客户端与服务端通信相关的?
getEntityCollisions返回的是该实体移动后能碰到的,且能踩上去的特殊实体列表(将实体碰撞箱转为方块碰撞箱)
也就是将潜影贝和船这些玩家能踩上的实体当作方块处理
*/
List<VoxelShape> list = this.level().getEntityCollisions(this, aabb.expandTowards(p_20273_));
//位移等于0时,ve3d等于调整前位移;反之等于进行碰撞相关调整后的位移
Vec3 vec3 = p_20273_.lengthSqr() == 0.0 ? p_20273_ : collideBoundingBox(this, p_20273_, aabb, this.level(), list);
//判断进行碰撞调整前后的各个轴向的位移是否相等,也就是是否有碰撞
boolean flag = p_20273_.x != vec3.x;
boolean flag1 = p_20273_.y != vec3.y;
boolean flag2 = p_20273_.z != vec3.z;
//是否在Y轴负方向上发生碰撞
boolean flag3 = flag1 && p_20273_.y < 0.0;
//maxUpStep > 0 且 在地上或者在Y轴负方向上发生碰撞 且 在某个水平方向上发生碰撞
if (this.maxUpStep() > 0.0F && (flag3 || this.onGround()) && (flag || flag2)) {
//在Y轴负方向上发生碰撞,则将碰撞箱移动调整后的Y位移,反之为普通碰撞箱
AABB aabb1 = flag3 ? aabb.move(0.0, vec3.y, 0.0) : aabb;
//将aabb延伸调整前的水平位移以及maxUpStep,赋值给aabb2
AABB aabb2 = aabb1.expandTowards(p_20273_.x, (double)this.maxUpStep(), p_20273_.z);
//如果Y轴负方向上没有发生碰撞,将aabb2向下延伸1.0E-5
if (!flag3) {
//aabb2向下延伸1.0E-5F
aabb2 = aabb2.expandTowards(0.0, -1.0E-5F, 0.0);
}
//构造新列表,同时有能碰到的特殊实体(已经转为方块)和方块
List<VoxelShape> list1 = collectColliders(this, this.level, list, aabb2);
//调整后的y位移,你就用一次你单独拿出来干什么
float f = (float)vec3.y;
//返回走上这些list2内的方块时的stepHeight的数组(舍弃一些不合理的情况)
float[] afloat = collectCandidateStepUpHeights(aabb1, list1, this.maxUpStep(), f);
for (float f1 : afloat) {
//collideWithShapes也是碰撞调整,collideBoundingBox其实是调用了这个方法
//碰撞调整((调整前水平位移,竖直位移为stepHeight),aabb1,list1)
Vec3 vec31 = collideWithShapes(new Vec3(p_20273_.x, (double)f1, p_20273_.z), aabb1, list1);
//总之是vec31的水平位移大于vec3的水平位移
if (vec31.horizontalDistanceSqr() > vec3.horizontalDistanceSqr()) {
//两个碰撞箱的Y坐标向减
//应该就两种情况,-vec3.y或0
double d0 = aabb.minY - aabb1.minY;
//vec31竖直位移减少d0;
return vec31.add(0.0, -d0, 0.0);
}
}
}
return vec3;
} 可以看到,对于以前常见的 Blip setup,游戏现在会将玩家碰撞箱放在地上(aabb1),再将碰撞箱在水平方向延伸水平位移,在竖直位移上延伸 maxUpStep(aabb2),以此检测可能撞上的方块,接着逐一检测走上这些方块时的 stepHeight(舍去不合理的情况,比如大于maxUpStep时),随后尝试将 aabb1 用原先的水平位移并以 stepHeight 为竖直位移来移动玩家(vec31),只要这个新移动的水平位移大于原先的水平位移(vec3),就再将vec31的竖直位移减去 (aabb 的Y坐标 - aabb1的Y坐标)(在这个情形下,最终竖直位移就是 stepHeight-vec3.y),恰好把玩家放在方块上了,按理来说彻底解决了各种 Blip 的问题。
至于卡 1.8bc 又回来的问题,因为玩家起跳后并没有在 Y 轴发生碰撞,游戏选择将用于检测可能撞上的方块的碰撞箱 aabb2 向下延伸了 1.0E-5,而此时aabb2又是在地上的,导致玩家把地上的方块也给考虑进去了,因此就卡 1.8bc 了。
至于 MC-276267 是怎么回事,基本上可以确认是碰撞检测的问题,我个人也看不懂所以也无从下手(
希望有别的大佬可以研究一下(