Для работы с визуализацией физических тел через Canvas 2D сначала необходимо создать базовую сцену Oimo.js. Ключевые элементы включают мир (World), тела (RigidBody) и геометрии (Shape).
import * as OIMO from "oimo";
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2, // 1 = brute force, 2 = sweep & prune
worldscale: 1,
random: true,
info: false
});
Параметр timestep определяет шаг симуляции,
iterations — количество итераций решения столкновений,
broadphase отвечает за алгоритм предварительной проверки
столкновений.
Для добавления тел используется конструктор RigidBody:
const box = world.add({
type: "box",
size: [2, 2, 2],
pos: [0, 10, 0],
move: true,
density: 1
});
Здесь type задаёт форму тела, size —
размеры, pos — начальное положение, move
указывает на подвижность объекта, density влияет на
массу.
DebugDraw в Oimo.js позволяет визуализировать все физические объекты и их столкновения в удобной форме. Для интеграции с Canvas 2D необходимо создать специальный класс отрисовки.
class DebugDraw2D {
constructor(canvas, world) {
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.world = world;
}
clear() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
draw() {
this.clear();
const bodies = this.world.getRigidBodies();
for (let i = 0; i < bodies.length; i++) {
this.drawBody(bodies[i]);
}
}
drawBody(body) {
const shapes = body.shapes;
for (let i = 0; i < shapes.length; i++) {
this.drawShape(shapes[i], body);
}
}
drawShape(shape, body) {
const pos = shape.getPosition();
const size = shape.getHalfExtents ? shape.getHalfExtents() : [1,1,1];
this.ctx.save();
this.ctx.translate(pos[0] + this.canvas.width/2, -pos[1] + this.canvas.height/2);
this.ctx.fillStyle = "rgba(0,150,255,0.5)";
if(shape.type === "box") {
this.ctx.fillRect(-size[0], -size[1], size[0]*2, size[1]*2);
} else if(shape.type === "sphere") {
this.ctx.beginPath();
this.ctx.arc(0, 0, size[0], 0, Math.PI*2);
this.ctx.fill();
}
this.ctx.restore();
}
}
Ключевые моменты реализации:
clear() — очищает канвас перед каждой отрисовкой.drawBody() — проходит по всем телам сцены и вызывает
drawShape().drawShape() — визуализирует разные типы геометрий:
коробки, сферы и при необходимости другие формы.Для правильного отображения необходимо запускать цикл обновления физики и рендеринга.
const canvas = document.getElementById("canvas");
const debugDraw = new DebugDraw2D(canvas, world);
function animate() {
requestAnimationFrame(animate);
world.step();
debugDraw.draw();
}
animate();
world.step() обновляет физическую симуляцию с учётом
текущего времени, после чего debugDraw.draw() визуализирует
все тела.
DebugDraw можно расширить для отображения контактных точек и векторов силы:
drawContacts() {
const contacts = this.world.getContacts();
this.ctx.strokeStyle = "red";
contacts.forEach(contact => {
const pos = contact.position;
this.ctx.beginPath();
this.ctx.arc(pos[0] + this.canvas.width/2, -pos[1] + this.canvas.height/2, 2, 0, Math.PI*2);
this.ctx.stroke();
});
}
Это позволяет наблюдать реальные точки соприкосновения объектов, что особенно полезно при отладке сложных взаимодействий.
Для адаптации под размеры окна удобно использовать масштабирование и центровку:
this.ctx.translate(this.canvas.width/2, this.canvas.height/2);
this.ctx.scale(10, -10);
translate смещает центр координат в центр окна.scale увеличивает видимые размеры объектов и
инвертирует ось Y, чтобы верхняя часть канваса соответствовала
положительной координате Y в физическом мире.Гравитацию задают через параметры мира:
const world = new OIMO.World({
gravity: [0, -9.8, 0]
});
Для динамических объектов важно указывать move: true.
При необходимости можно создавать падающие коробки и
шары, наблюдая их столкновения через DebugDraw:
for(let i = 0; i < 5; i++) {
world.add({
type: "sphere",
size: [1],
pos: [i*2-4, 20, 0],
move: true,
density: 1
});
}
Отрисовка будет автоматически обновляться при каждом шаге симуляции, демонстрируя физическое поведение объектов.
Canvas позволяет выделять объекты разными цветами для удобства отладки:
this.ctx.fillStyle = shape.type === "box" ? "rgba(0,150,255,0.5)" : "rgba(255,100,0,0.5)";
Прозрачность позволяет видеть наложение объектов и их взаимное пересечение, а различие цветов помогает различать типы тел.
Использование DebugDraw с Canvas 2D в Oimo.js обеспечивает наглядную отладку физической симуляции, позволяет визуализировать объекты, столкновения и силы, а также тестировать поведение сложных динамических сцен. Правильное масштабирование и трансформация канваса делают работу с 2D-представлением интуитивной и наглядной.