关于地面-bug#
Data: 2025-12-25 04:55:05
先是强制回到天上
// 1. 强制重置位置 (回到安全点)
k.mainVPlayer.body.position.set(0, 100, 0);
// 2. 归零速度 (非常重要,否则下一帧继续炸)
k.mainVPlayer.body.velocity.set(0, 0, 0);
k.mainVPlayer.body.angularVelocity.set(0, 0, 0);
k.mainVPlayer.body.force.set(0, 0, 0);
k.mainVPlayer.body.torque.set(0, 0, 0);
// 3. 修复旋转
k.mainVPlayer.body.quaternion.set(0, 0, 0, 1);然后移除原来的那个,重新添加一遍:
// 1. 获取物理世界引用 (通过主角或者旧地面都能拿到)
var world = k.mainVPlayer.body.world || k.groundObj.body.world;
// 2. 备份旧地面的碰撞掩码 (非常重要,否则新地面接不住主角)
var oldGroup = k.groundObj.body.collisionFilterGroup;
var oldMask = k.groundObj.body.collisionFilterMask;
var oldMaterial = k.groundObj.body.material;
// 3. 从世界中移除旧地面
world.removeBody(k.groundObj.body);
console.log("旧地面已移除。碰撞组:", oldGroup, "碰撞掩码:", oldMask);
// 1. 创建新的 Box 形状 (参数是半长宽高)
// 我们先做一个 100x100 的安全平台,厚度保持 6 (半高 3)
var newSafeShape = new CANNON.Box(new CANNON.Vec3(50, 3, 50));
// 2. 创建新的物理体
var newGroundBody = new CANNON.Body({
mass: 0, // 静态
position: new CANNON.Vec3(0, -2.5, 0), // 保持原位置 Y
shape: newSafeShape,
material: oldMaterial // 沿用旧材质
});
// 3. 恢复碰撞分组 (关键!)
newGroundBody.collisionFilterGroup = oldGroup;
newGroundBody.collisionFilterMask = oldMask;
// 4. 添加到世界
world.addBody(newGroundBody);
// 5. 将新体重新挂载到 k 对象,防止报错
k.groundObj.body = newGroundBody;
console.log("新建的安全地面已生成 (100x100)。");(并非这个!)目前的原因分析,可能是 我的拼写错误!
cannonDefaultContactMaterial。
现在暂时的恢复代码为(我也不知道是否有效):
(function() {
console.clear();
console.group("🛡️ 物理引擎终极修复程序");
const world = k.world;
const player = k.mainVPlayer.body;
// ==========================================
// 1. 环境清洗:彻底消灭所有重叠/幽灵地面
// ==========================================
console.log("🧹 正在清理所有疑似地面的物体...");
const bodiesToRemove = [];
world.bodies.forEach(b => {
// 逻辑:只要是静止的(mass=0) 且不是主角 且位置在 Y=0 附近
// 统统视为“嫌疑地面”进行删除
if (b.mass === 0 && b !== player && Math.abs(b.position.y) < 5) {
bodiesToRemove.push(b);
}
});
bodiesToRemove.forEach(b => world.removeBody(b));
console.log(`✅ 已移除 ${bodiesToRemove.length} 个旧地面/残留物体。`);
// ==========================================
// 2. 核心修复:切换最稳健的检测算法
// ==========================================
// NaiveBroadphase 虽然性能普通,但在直接操作 position 时最不容易出错
if (world.broadphase.constructor.name !== "NaiveBroadphase") {
world.broadphase = new CANNON.NaiveBroadphase();
console.log("✅ Broadphase 已切换为 Naive 模式 (防穿透/防NaN)。");
}
// ==========================================
// 3. 材质排雷:修复潜在的 friction: 100 问题
// ==========================================
// 无论之前怎么设置,强制把世界默认材质改回安全值
world.defaultContactMaterial.friction = 0.3;
world.defaultContactMaterial.restitution = 0.0;
console.log("✅ 世界默认材质已修正 (Friction: 0.3, Restitution: 0.0)。");
// 创建隔离材质(双重保险)
const matPlayer = new CANNON.Material("safe_player");
const matGround = new CANNON.Material("safe_ground");
const matContact = new CANNON.ContactMaterial(matPlayer, matGround, {
friction: 0.3, // 标准摩擦
restitution: 0.0, // 无弹力 (防止震荡)
contactEquationStiffness: 1e8, // 硬度强
contactEquationRelaxation: 3
});
world.addContactMaterial(matContact);
// ==========================================
// 4. 重建地面:唯一的、纯净的 Plane
// ==========================================
const groundBody = new CANNON.Body({
mass: 0, // 静态
position: new CANNON.Vec3(0, 0.5, 0), // 表面高度
shape: new CANNON.Plane(),
material: matGround
});
// 旋转 Plane 让其面朝上 (Y+)
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
// 碰撞掩码:跟谁都撞
groundBody.collisionFilterGroup = 1;
groundBody.collisionFilterMask = -1;
world.addBody(groundBody);
// 更新全局引用
k.groundObj = {
name: 'SafePlane',
body: groundBody,
// 假参数,兼容旧逻辑
width: 99999, depth: 99999, height: 0
};
console.log("✅ 唯一标准 Plane 地面已创建 (Y=0.5)。");
// ==========================================
// 5. 主角归位与净化
// ==========================================
// 赋予新材质
player.material = matPlayer;
// 碰撞掩码:跟谁都撞
player.collisionFilterGroup = 1;
player.collisionFilterMask = -1;
// 重置物理状态 (清除 NaN 残留)
player.velocity.set(0, 0, 0);
player.angularVelocity.set(0, 0, 0);
player.force.set(0, 0, 0);
player.torque.set(0, 0, 0);
player.quaternion.set(0, 0, 0, 1); // 扶正
// 放到安全位置 (稍高一点自然下落)
player.position.set(0, 1.0, 0);
player.wakeUp();
console.log("✅ 主角已重置并投放。");
console.groupEnd();
console.log("%c🎉 物理世界修复完毕!现在您可以安全测试了。", "color: green; font-weight: bold; font-size: 14px;");
})();