Cannon.js — это библиотека для симуляции физики в JavaScript, ориентированная на создание реалистичных взаимодействий объектов в 3D-пространстве. Центральным элементом является мир (World), который управляет телами (Bodies), их коллизиями и взаимодействиями с внешними силами.
Создание мира начинается с инициализации объекта
CANNON.World и задания глобальных параметров, таких как
гравитация:
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0); // гравитация по оси Y
world.broadphase = new CANNON.NaiveBroadphase(); // простой алгоритм broadphase
world.solver.iterations = 10; // точность решения столкновений
Для тел используется CANNON.Body, который принимает
массу, форму (Shape) и начальные параметры позиции и ориентации. Формы
бывают разнообразные: Box, Sphere,
Plane, ConvexPolyhedron.
const groundBody = new CANNON.Body({
mass: 0, // статическое тело
shape: new CANNON.Plane(),
position: new CANNON.Vec3(0, 0, 0)
});
world.addBody(groundBody);
Рейкастинг — это метод определения пересечения луча с объектами в мире. Он часто используется для детектирования поверхности под персонажем, проверки видимости, прицеливания и других взаимодействий.
В Cannon.js рейкастинг осуществляется через CANNON.Ray.
Луч имеет начальную точку (from),
конечную точку (to) и ряд параметров для
точного контроля:
collisionFilterMask — какие группы объектов
проверять;skipBackfaces — игнорировать обратные стороны
объектов;mode — режим работы: ANY,
CLOSEST, ALL.const ray = new CANNON.Ray(fromVec3, toVec3);
ray.intersectWorld(world, {
mode: CANNON.Ray.ALL,
skipBackfaces: true
});
Метод intersectWorld возвращает информацию о
столкновениях:
hasHit — было ли пересечение;hitPointWorld — координаты точки контакта;hitNormalWorld — нормаль поверхности в точке
пересечения;body — тело, с которым произошло пересечение.Для персонажа, управляемого от первого лица, требуется постоянная проверка наличия земли под ногами. Основные шаги:
Пример:
function checkGround(playerBody) {
const origin = new CANNON.Vec3(
playerBody.position.x,
playerBody.position.y,
playerBody.position.z
);
const down = new CANNON.Vec3(0, -1, 0);
const rayLength = 1.1; // чуть больше половины роста персонажа
const ray = new CANNON.Ray(origin, origin.vadd(down.scale(rayLength)));
const result = new CANNON.RaycastResult();
ray.intersectWorld(world, {
collisionFilterMask: -1,
skipBackfaces: true,
result: result
});
if (result.hasHit) {
return {
onGround: true,
hitPoint: result.hitPointWorld,
hitNormal: result.hitNormalWorld
};
} else {
return { onGround: false };
}
}
CANNON.Ray.CLOSEST для
проверки только ближайшего столкновения повышает производительность,
если не нужны все объекты под лучом.skipBackfaces = true
предотвращает ложные срабатывания на обратной стороне плоских
объектов.Для более точного контроля движения персонажа полезно анализировать нормаль поверхности:
const groundInfo = checkGround(playerBody);
if (groundInfo.onGround) {
const slopeAngle = Math.acos(groundInfo.hitNormal.dot(new CANNON.Vec3(0, 1, 0)));
if (slopeAngle < Math.PI / 4) {
// можно ходить
} else {
// крутой склон — ограничение движения
}
}
Такой подход позволяет корректно обрабатывать наклонные поверхности и предотвращать «проваливание» персонажа.
Рейкастинг от первого лица должен вызываться в каждой итерации обновления мира:
function update(deltaTime) {
world.step(deltaTime);
const groundStatus = checkGround(playerBody);
playerBody.onGro und = groundStatus.onGround;
// обработка движения
if (playerBody.onGround) {
// нормальная ходьба
} else {
// падение или прыжок
}
}
Сочетание рейкастинга с физическим телом позволяет реализовать естественное движение персонажа и точное детектирование поверхности, что критично для платформеров и игр от первого лица.
Если под персонажем находятся движущиеся платформы или объекты, нужно учитывать скорость и направление объекта, чтобы корректно синхронизировать позицию персонажа с поверхностью. Для этого при пересечении лучом динамического тела можно применять смещение:
if (groundInfo.onGround && groundInfo.body.mass > 0) {
playerBody.position.vadd(groundInfo.body.velocity.scale(deltaTime), playerBody.position);
}
Это предотвращает «прыжки» и расхождения между визуальной и физической позициями персонажа.
Метод рейкаста в Cannon.js обеспечивает точное детектирование земли и других поверхностей, позволяя создавать реалистичное движение от первого лица с корректной обработкой наклонов, динамических объектов и коллизий.