Ammo.js — это JavaScript-порт физического движка Bullet, скомпилированный в WebAssembly или asm.js с помощью Emscripten. Библиотека распространяется в виде одного или нескольких файлов:
ammo.js — asm.js-версия;ammo.wasm.js + ammo.wasm.wasm —
WebAssembly-версия;ammo.min.js).При подключении через CDN чаще всего используется готовая сборка WebAssembly, так как она обеспечивает значительно более высокую производительность по сравнению с asm.js.
Наиболее распространённые CDN для подключения библиотек:
CDN позволяют подключить библиотеку без установки через npm и без локального хранения файлов проекта. Это особенно удобно для:
<script>Минимальный вариант подключения через jsDelivr:
<script src="https://cdn.jsdelivr.net/npm/ammo.js"></script>
Однако важно учитывать, что Ammo.js инициализируется асинхронно. В
отличие от большинства библиотек, глобальный объект Ammo
становится доступен не сразу.
Современная версия возвращает Promise, поэтому корректное использование выглядит следующим образом:
<script src="https://cdn.jsdelivr.net/npm/ammo.js"></script>
<script>
Ammo().then(function (AmmoLib) {
// AmmoLib — инициализированный API
const collisionConfig = new AmmoLib.btDefaultCollisionConfiguration();
console.log("Ammo.js успешно загружен");
});
</script>
Сборка WebAssembly требует:
.wasm-файлаВсе эти операции происходят асинхронно. Поэтому попытка использовать
Ammo напрямую без then() приведёт к
ошибке.
Фиксация версии критична для стабильности учебных и продакшен-проектов.
Пример подключения определённой версии через jsDelivr:
<script src="https://cdn.jsdelivr.net/npm/ammo.js@0.0.10/builds/ammo.wasm.js"></script>
Фиксирование версии защищает от:
Иногда CDN не автоматически находит .wasm-файл. В этом
случае требуется явно указать путь:
<script>
Ammo({
locateFile: function (path) {
return "https://cdn.jsdelivr.net/npm/ammo.js@0.0.10/builds/" + path;
}
}).then(function (AmmoLib) {
console.log("WASM загружен");
});
</script>
locateFileФункция locateFile переопределяет путь к вспомогательным
файлам (в частности .wasm). Без неё браузер будет искать
файл относительно текущего HTML-документа.
При работе в среде с поддержкой ES6-модулей подключение через CDN возможно динамическим импортом:
<script type="module">
import AmmoModule from "https://cdn.jsdelivr.net/npm/ammo.js@0.0.10/builds/ammo.wasm.js";
AmmoModule().then((AmmoLib) => {
const world = new AmmoLib.btDiscreteDynamicsWorld();
console.log(world);
});
</script>
Важно учитывать, что не все CDN корректно отдают сборки как ES-модули. В некоторых случаях потребуется использовать версию, совместимую с UMD.
Корректная инициализация определяется наличием ключевых классов:
Ammo().then(function (AmmoLib) {
if (AmmoLib.btVector3) {
console.log("Physics API доступен");
}
});
Если btVector3 отсутствует, значит:
.wasm-файл (CORS).WebAssembly-файл должен:
application/wasm,CDN обычно корректно настраивают эти параметры, но при проксировании или нестандартных настройках сервера могут возникнуть ошибки:
WebAssembly.instantiate(): incorrect MIME type
В таком случае рекомендуется:
В связке с трёхмерной графикой часто используется Three.js. Порядок подключения имеет значение:
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ammo.js@0.0.10/builds/ammo.wasm.js"></script>
После загрузки обе библиотеки могут использоваться совместно внутри
Ammo().then().
Важно понимать, что:
При подключении через обычный <script> библиотека
добавляет фабричную функцию Ammo в глобальный scope:
window.Ammo
После инициализации API передаётся в callback. Рекомендуется сохранять ссылку:
let AmmoLib;
Ammo().then(function (lib) {
AmmoLib = lib;
});
Это предотвращает повторные вызовы фабрики и лишние аллокации памяти.
CDN может отдавать asm.js-версию при неправильной конфигурации. Отличия:
| Параметр | asm.js | WebAssembly |
|---|---|---|
| Скорость | ниже | значительно выше |
| Размер | больше | меньше |
| Поддержка | устаревшая | современная |
Для реальных физических симуляций рекомендуется использовать только WASM-сборку.
Ammo is not definedПричины:
<script> подключён после кода,then()const world = new Ammo.btDiscreteDynamicsWorld(); // Ошибка
Ammo ещё не инициализирован.
Ammo().then(...)
Ammo().then(...)
Каждый вызов создаёт новый экземпляр модуля. Это приводит к увеличению потребления памяти.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ammo.js CDN</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/ammo.js@0.0.10/builds/ammo.wasm.js"></script>
<script>
Ammo().then(function (AmmoLib) {
const collisionConfig = new AmmoLib.btDefaultCollisionConfiguration();
const dispatcher = new AmmoLib.btCollisionDispatcher(collisionConfig);
const broadphase = new AmmoLib.btDbvtBroadphase();
const solver = new AmmoLib.btSequentialImpulseConstraintSolver();
const world = new AmmoLib.btDiscreteDynamicsWorld(
dispatcher,
broadphase,
solver,
collisionConfig
);
world.setGravity(new AmmoLib.btVector3(0, -9.8, 0));
console.log("Физический мир создан");
});
</script>
</body>
</html>
Несмотря на удобство, существуют ограничения:
Для крупных проектов предпочтительнее установка через npm и сборка через bundler (Webpack, Vite, Rollup).
Подключение через CDN остаётся оптимальным способом быстрого старта, прототипирования и учебной разработки, позволяя сосредоточиться на работе с физическим API без настройки инфраструктуры сборки.