diff --git a/M/4.0/игра.html b/M/4.0/игра.html new file mode 100644 index 0000000..a84f860 --- /dev/null +++ b/M/4.0/игра.html @@ -0,0 +1,38 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/M/4.0/игра/050.Заголовок.js b/M/4.0/игра/050.Заголовок.js new file mode 100644 index 0000000..2e47500 --- /dev/null +++ b/M/4.0/игра/050.Заголовок.js @@ -0,0 +1,10 @@ +function Заголовок() +{ + this.обработатьКлюч = function(ключ, путь, значение) + { + if (ключ == "заголовок") + { + document.title = значение; + } + } +} diff --git a/M/4.0/игра/070.Виды.js b/M/4.0/игра/070.Виды.js new file mode 100644 index 0000000..c74121e --- /dev/null +++ b/M/4.0/игра/070.Виды.js @@ -0,0 +1,28 @@ +function Виды(события) +{ + this.создать = function() + { + this.задано = {}; + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] != "виды") + { + return; + } + + let имя = путь[1]; + let свойство = путь.slice(2).join("."); + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + + события.уведомить(`виды/${имя}`); + }; + + // Конструктор. + this.создать(); +}; diff --git a/M/4.0/игра/100.Изображения.js b/M/4.0/игра/100.Изображения.js new file mode 100644 index 0000000..be615c6 --- /dev/null +++ b/M/4.0/игра/100.Изображения.js @@ -0,0 +1,146 @@ +function Изображения(события, виды, корень) +{ + this.создать = function() + { + this.умолчание = { + пр: [0, 0, 100, 100], + угол: 0, + }; + this.задано = {}; + this.элементы = {}; + события.подписать(this); + }; + + this.создатьИлиПолучитьЭлемент = function(имя) + { + var эл = this.элементы[имя]; + if (эл) + { + return эл; + } + + var ум = this.умолчание; + эл = document.createElement("div"); + эл.id = `изображения-${имя}`; + эл.style.position = "absolute"; + эл.style.display = "block"; + // Свойства по умолчанию. + this.обновитьПозициюРазмерЭлемента(имя, эл); + эл.style.transform = `rotate(${ум.угол}rad)`; + this.элементы[имя] = эл; + корень.appendChild(эл); + return эл; + }; + + this.обновитьВид = function(имя, вид) + { + var эл = this.создатьИлиПолучитьЭлемент(имя); + let за = виды.задано[вид]; + for (let параметр in за) + { + эл.style.setProperty(параметр, за[параметр]); + } + this.обновитьУгол(имя); + }; + + this.обновитьПозициюРазмерЭлемента = function(имя, эл) + { + let пр = this.пр(имя); + эл.style.left = `${пр[0]}px`; + эл.style.top = `${пр[1]}px`; + эл.style.width = `${пр[2]}px`; + эл.style.height = `${пр[3]}px`; + }; + + this.обновитьУгол = function(имя) + { + var за = this.задано[имя]; + var ум = this.умолчание; + var эл = this.элементы[имя]; + + var угол = за.угол ? за.угол : ум.угол; + var transform = `rotate(${угол}deg) `; + + let вид = за["вид"]; + if (вид) + { + let виза = виды.задано[вид]; + if (виза && виза["transform"]) + { + transform += виза["transform"]; + } + } + + эл.style.transform = transform; + }; + + this.обновитьЭлемент = function(имя, свойство, значение) + { + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + var за = this.задано[имя]; + var эл = this.создатьИлиПолучитьЭлемент(имя); + + if (свойство.startsWith("пр")) + { + this.обновитьПозициюРазмерЭлемента(имя, эл); + } + else if ( + (свойство == "угол") || + (свойство == "вид") + ) { + this.обновитьВид(имя, за["вид"]); + } + }; + + this.обновитьЭлементыВида = function(вид) + { + for (let имя in this.задано) + { + let заданныйВид = this.задано[имя]["вид"]; + if (заданныйВид && заданныйВид == вид) + { + this.обновитьВид(имя, вид); + } + } + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] == "изображения") + { + var имя = путь[1]; + var свойство = путь.slice(2).join("."); + this.обновитьЭлемент(имя, свойство, значение); + } + }; + + this.обработатьСобытие = function(событие) + { + let префикс = "виды/"; + if (событие.startsWith(префикс)) + { + let вид = событие.substring(префикс.length); + this.обновитьЭлементыВида(вид); + } + }; + + this.пр = function(имя) + { + let за = this.задано[имя]; + let пр = this.умолчание.пр; + return [ + за["пр.0"] ? за["пр.0"] : пр[0], + за["пр.1"] ? за["пр.1"] : пр[1], + за["пр.2"] ? за["пр.2"] : пр[2], + за["пр.3"] ? за["пр.3"] : пр[3], + ]; + }; + + + // Конструктор. + this.создать(); +} diff --git a/M/4.0/игра/120.Физика.js b/M/4.0/игра/120.Физика.js new file mode 100644 index 0000000..d75fc12 --- /dev/null +++ b/M/4.0/игра/120.Физика.js @@ -0,0 +1,28 @@ +function Физика(события) +{ + this.создать = function() + { + this.задано = {}; + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] != "физика") + { + return; + } + + let имя = путь[1]; + let свойство = путь.slice(2).join("."); + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + + события.уведомить(`физика/${имя}`); + }; + + // Конструктор. + this.создать(); +}; diff --git a/M/4.0/игра/140.Тела.js b/M/4.0/игра/140.Тела.js new file mode 100644 index 0000000..2e9a330 --- /dev/null +++ b/M/4.0/игра/140.Тела.js @@ -0,0 +1,149 @@ +function Тела(события, физика, физмир) +{ + this.создать = function() + { + this.умолчание = { + пр: [0, 0, 40, 20], + части: [], + часть: false, + }; + + this.задано = {}; + this.тела = {}; + this.имена = {}; + события.подписать(this); + }; + + this.именаЧастей = function(за) + { + var имена = []; + for (var ключ in за) + { + if (ключ.startsWith("части")) + { + имена.push(за[ключ]); + } + } + return имена; + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] != "тела") + { + return; + } + + var имя = путь[1]; + var свойство = путь.slice(2).join("."); + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + + this.пересоздатьТело(имя); + }; + + this.обработатьСобытие = function(событие) + { + let префикс = "физика/"; + if (событие.startsWith(префикс)) + { + let физ = событие.substring(префикс.length); + this.пересоздатьТелаФизики(физ); + } + }; + + this.пересоздатьТелаФизики = function(физ) + { + for (let имя in this.задано) + { + let заданнаяФизика = this.задано[имя]["физика"]; + if (заданнаяФизика && заданнаяФизика == физ) + { + this.пересоздатьТело(имя); + } + } + }; + + this.пересоздатьТело = function(имя) + { + // Удаляем старое тело. + if (имя in this.тела) + { + var тело = this.тела[имя]; + delete this.имена[тело.id]; + // Всегда удаляем из мира: и составные, и несоставные тела. + Matter.Composite.remove(физмир, тело); + } + + var за = this.задано[имя]; + var ум = this.умолчание; + let пр = this.пр(имя); + // Переводим x,y из левого верхнего угла в центр. + пр[0] = пр[0] + пр[2] / 2.0; + пр[1] = пр[1] + пр[3] / 2.0; + // Параметры тела. + var параметры = {}; + if (за.физика) + { + let заф = физика.задано[за.физика]; + for (let параметр in заф) + { + мир.задатьПолныйКлюч(параметры, параметр, заф[параметр]); + } + } + + var тело = null; + // Создаём новое составное тело. + if (за["части.0"]) + { + параметры["parts"] = this.телаЧастей(this.именаЧастей(за)); + тело = Matter.Body.create(параметры); + } + // Создаём новое несоставное тело. + // Вполне может быть частью другого составного тела. + else + { + тело = Matter.Bodies.rectangle(пр[0], пр[1], пр[2], пр[3], параметры); + } + this.тела[имя] = тело; + this.имена[тело.id] = имя; + + // Добавляем тело в физический мир, если оно не является частью другого составного тела. + var часть = за.часть ? за.часть : ум.часть; + if (!часть) + { + Matter.Composite.add(физмир, тело); + } + }; + + this.пр = function(имя) + { + let за = this.задано[имя]; + let пр = this.умолчание.пр; + return [ + за["пр.0"] ? за["пр.0"] : пр[0], + за["пр.1"] ? за["пр.1"] : пр[1], + за["пр.2"] ? за["пр.2"] : пр[2], + за["пр.3"] ? за["пр.3"] : пр[3], + ]; + }; + + this.телаЧастей = function(имена) + { + var тела = []; + for (var н in имена) + { + var имя = имена[н]; + var тело = this.тела[имя]; + тела.push(тело); + } + return тела; + }; + + // Конструктор. + this.создать(); +} + diff --git a/M/4.0/игра/160.Слежение.js b/M/4.0/игра/160.Слежение.js new file mode 100644 index 0000000..0e7a15c --- /dev/null +++ b/M/4.0/игра/160.Слежение.js @@ -0,0 +1,105 @@ +function Слежение(состояние, изображения, тела) +{ + this.создать = function() + { + this.умолчание = { + смещение: [0, 0], + скорость: 1, + предел: 0, + }; + this.задано = {}; + }; + + this.обновить = function() + { + for (var имя in this.задано) + { + this.расположитьИзображение(имя); + } + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] != "слежение") + { + return; + } + + var имя = путь[1]; + var свойство = путь.slice(2).join("."); + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + }; + + this.расположитьИзображение = function(имя) + { + let за = this.задано[имя]; + let тело = тела.тела[за.тело]; + let элемент = изображения.элементы[за.изображение]; + if (!тело || !элемент) + { + return; + } + + let ум = this.умолчание; + + // Параметры. + var скорость = за.скорость ? за.скорость : ум.скорость; + var смещениеX = за["смещение.0"] ? за["смещение.0"] : ум.смещение[0]; + var смещениеY = за["смещение.1"] ? за["смещение.1"] : ум.смещение[1]; + var предел = за.предел ? за.предел : ум.предел; + + // Текущая позиция. + var x0 = 0; + if (элемент.dataset.слежениеX) + { + x0 = элемент.dataset.слежениеX; + } + var y0 = 0; + if (элемент.dataset.слежениеY) + { + y0 = элемент.dataset.слежениеY; + } + + // Целевая позиция. + var x1 = тело.position.x + смещениеX; + var y1 = тело.position.y + смещениеY; + // Radians -> Degrees. + var угол = тело.angle * 180 / Math.PI; + + // Устанавливаемая плавно позиция. + var x = this.lerp(x0, x1, скорость, предел); + var y = this.lerp(y0, y1, скорость, предел); + + элемент.dataset.слежениеX = x; + элемент.dataset.слежениеY = y; + + var описание = { + пр: [x, y], + угол: угол, + }; + состояние.разобрать({ + изображения: { + [за.изображение]: описание, + }, + }); + }; + + this.lerp = function(v0, v1, t, предел) { + // Убираем мельтешение в случае наличия предела. + if (предел) + { + var delta = Math.abs(v0 - v1); + if (delta < предел) { + return v0; + } + } + return v0 * (1 - t) + v1 * t; + }; + + // Конструктор. + this.создать(); +}; diff --git a/M/4.0/игра/180.Объекты.js b/M/4.0/игра/180.Объекты.js new file mode 100644 index 0000000..88e7677 --- /dev/null +++ b/M/4.0/игра/180.Объекты.js @@ -0,0 +1,109 @@ +function Объекты(состояние) +{ + this.создать = function() + { + this.умолчание = { + пр: [0, 0, 40, 20], + }; + this.задано = {}; + }; + + this.обновитьИзображение = function(имя, пр, вид) + { + состояние.разобрать({ + изображения: { + [имя]: { + пр: пр, + вид: вид, + }, + }, + }); + }; + + this.обновитьПозициюРазмер = function(имя, пр) + { + состояние.разобрать({ + тела: { + [имя]: { + пр: пр, + }, + }, + }); + }; + + this.обновитьСлежение = function(имя, пр) + { + состояние.разобрать({ + слежение: { + [имя]: { + изображение: имя, + тело: имя, + смещение: [-пр[2] / 2, -пр[3] / 2], + }, + }, + }); + }; + + this.обновитьФизику = function(имя, значение) + { + состояние.разобрать({ + тела: { + [имя]: { + физика: значение, + }, + }, + }); + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + if (путь[0] != "объекты") + { + return; + } + + let имя = путь[1]; + let свойство = путь.slice(2).join("."); + if (!this.задано[имя]) + { + this.задано[имя] = {}; + } + this.задано[имя][свойство] = значение; + + let производноеИмя = `объекты-${имя}`; + + if (свойство.startsWith("пр.")) + { + let пр = this.пр(имя); + this.обновитьПозициюРазмер(производноеИмя, пр); + this.обновитьСлежение(производноеИмя, пр); + let вид = this.задано[имя]["вид"]; + this.обновитьИзображение(производноеИмя, пр, вид); + } + else if (свойство == "физика") + { + this.обновитьФизику(производноеИмя, значение); + } + else if (свойство == "вид") + { + let пр = this.пр(имя); + let вид = this.задано[имя]["вид"]; + this.обновитьИзображение(производноеИмя, пр, вид); + } + }; + + this.пр = function(имя) + { + let за = this.задано[имя]; + let пр = this.умолчание.пр; + return [ + за["пр.0"] ? за["пр.0"] : пр[0], + за["пр.1"] ? за["пр.1"] : пр[1], + за["пр.2"] ? за["пр.2"] : пр[2], + за["пр.3"] ? за["пр.3"] : пр[3], + ]; + }; + + // Конструктор. + this.создать(); +}; diff --git a/M/4.0/игра/700.Игра.js b/M/4.0/игра/700.Игра.js new file mode 100644 index 0000000..5cfdeac --- /dev/null +++ b/M/4.0/игра/700.Игра.js @@ -0,0 +1,76 @@ +function Игра() +{ + this.создать = function() + { + мир.физдвижок = Matter.Engine.create({ + enableSleeping: true, + gravity: { + y: 2, + }, + }); + var корень = document.getElementById("корень"); + мир.события = new События(); + мир.состояние = new Состояние(); + мир.состояние.обработчик = (к, п, з) => { this.обработатьКлюч(к, п, з) }; + мир.виды = new Виды(мир.события); + мир.изображения = new Изображения(мир.события, мир.виды, корень), + мир.физика = new Физика(мир.события); + мир.тела = new Тела(мир.события, мир.физика, мир.физдвижок.world); + мир.слежение = new Слежение(мир.состояние, мир.изображения, мир.тела); + мир.объекты = new Объекты(мир.состояние); + this.ключники = [ + new Заголовок(), + мир.виды, + мир.изображения, + мир.физика, + мир.тела, + мир.слежение, + мир.объекты, + ]; + + var z64 = мир.параметрыЗапуска()["z64"]; + this.исполнитьКод(z64); + this.отслеживатьОбновленияКода(); + this.обновить(); + }; + + this.исполнитьКод = function(z64) + { + if (z64) + { + var код = мир.изZ64(z64); + eval(код); + } + }; + + this.обновить = function() + { + Matter.Engine.update(мир.физдвижок); + мир.слежение.обновить(); + + var тут = this; + requestAnimationFrame(function() { + тут.обновить(); + }); + }; + + this.обработатьКлюч = function(ключ, путь, значение) + { + for (var номер in this.ключники) + { + var ключник = this.ключники[номер]; + ключник.обработатьКлюч(ключ, путь, значение); + } + }; + + this.отслеживатьОбновленияКода = function() + { + var тут = this; + window.addEventListener("message", function(событие) { + тут.исполнитьКод(событие.data); + }); + }; + + // Конструктор. + this.создать(); +} diff --git a/M/4.0/игра/matter-js b/M/4.0/игра/matter-js new file mode 120000 index 0000000..3a19a2e --- /dev/null +++ b/M/4.0/игра/matter-js @@ -0,0 +1 @@ +../../стороннее/matter-js \ No newline at end of file diff --git a/M/4.0/общее/100.События.js b/M/4.0/общее/100.События.js new file mode 100644 index 0000000..19f8ecf --- /dev/null +++ b/M/4.0/общее/100.События.js @@ -0,0 +1,31 @@ +function События() +{ + this.создать = function() + { + this.обработчики = []; + }; + + this.подписать = function(обработчик) + { + this.обработчики.push(обработчик); + }; + + this.отписать = function(обработчик) { + var номер = this.обработчики.indexOf(обработчик); + if (номер != -1) + { + this.обработчики.splice(номер, 1); + } + }; + + this.уведомить = function(событие) { + for (var номер in this.обработчики) + { + var обработчик = this.обработчики[номер]; + обработчик.обработатьСобытие(событие); + } + }; + + // Конструктор. + this.создать(); +} diff --git a/M/4.0/общее/150.Состояние.js b/M/4.0/общее/150.Состояние.js new file mode 100644 index 0000000..5004890 --- /dev/null +++ b/M/4.0/общее/150.Состояние.js @@ -0,0 +1,61 @@ +function Состояние() +{ + this.создать = function() + { + this.обработчик = null; + this.значения = {}; + }; + + this.выпрямить = function(obj) + { + // https://stackoverflow.com/a/42121920 + var newObj = {}; + for (var key in obj) + { + if (typeof obj[key] === 'object' && obj[key] !== null) + { + var temp = this.выпрямить(obj[key]) + for (var key2 in temp) + { + newObj[key + "." + key2] = temp[key2]; + } + } + else + { + newObj[key] = obj[key]; + } + } + return newObj; + }; + + this.лишьНовыеЗначения = function(значения) { + var новые = {}; + for (var ключ in значения) + { + var было = this.значения[ключ]; + var стало = значения[ключ]; + if (!(было != null && было == стало)) + { + новые[ключ] = стало; + this.значения[ключ] = стало; + } + } + return новые; + }; + + this.разобрать = function(словарь) { + var значения = this.лишьНовыеЗначения(this.выпрямить(словарь)); + for (var ключ in значения) + { + var путь = ключ.split("."); + var значение = значения[ключ]; + if (this.обработчик) + { + this.обработчик(ключ, путь, значение); + } + } + }; + + // Конструктор. + this.создать(); +} diff --git a/M/4.0/общее/200.функции.js b/M/4.0/общее/200.функции.js new file mode 100644 index 0000000..cca058c --- /dev/null +++ b/M/4.0/общее/200.функции.js @@ -0,0 +1,91 @@ +var мир = {}; + +мир.uuid = function() +{ + // https://stackoverflow.com/a/2117523 + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( + /[xy]/g, + function(c) + { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + } + ); +}; + +мир.вZ64 = function(строка) +{ + var байты = new TextEncoder("utf-8").encode(строка); + var архив = pako.deflate(байты, { to: 'string' }); + return base64js.fromByteArray(архив); +}; + +мир.изZ64 = function(строка) +{ + var архив = base64js.toByteArray(строка); + var байты = pako.inflate(архив); + return new TextDecoder("utf-8").decode(байты); +}; + +мир.задатьПолныйКлюч = function(словарь, полныйКлюч, значение) { + var путь = полныйКлюч.split("."); + var пройти = путь.length - 1; + var вложенность = словарь; + for (var номер = 0; номер < пройти; ++номер) + { + var ключ = путь[номер]; + if (!(ключ in вложенность)) + { + вложенность[ключ] = {}; + вложенность = вложенность[ключ]; + } + } + // Значение в конце вложенности. + var ключ = путь[пройти]; + вложенность[ключ] = значение; +}; + +мир.назначитьКнопкамСобытия = function(события, список) +{ + for (var номер in список) + { + const пара = список[номер]; + var кнопка = document.getElementById(пара[0]); + кнопка.addEventListener("click", function(_) { + события.уведомить(пара[1]); + }); + } +}; + +мир.параметрыЗапуска = function() +{ + var параметры = {}; + var запрос = window.location.search.substring(1); + var аргументы = запрос.split("&"); + for (var номер in аргументы) + { + var арг = аргументы[номер]; + var позицияЗнака = арг.indexOf("="); + // Лишь ключ. + if (позицияЗнака == -1) + { + var ключ = decodeURIComponent(арг); + параметры[ключ] = null; + } + // Ключ со значением. + else + { + var сыройКлюч = арг.slice(0, позицияЗнака); + var сыроеЗначение = арг.slice(позицияЗнака + 1); + var ключ = decodeURIComponent(сыройКлюч); + var значение = decodeURIComponent(сыроеЗначение); + параметры[ключ] = значение; + } + } + return параметры; +}; + +мир.разобрать = function(словарь) +{ + мир.состояние.разобрать(словарь); +}; diff --git a/M/4.0/общее/base64-js b/M/4.0/общее/base64-js new file mode 120000 index 0000000..a3367c1 --- /dev/null +++ b/M/4.0/общее/base64-js @@ -0,0 +1 @@ +../../стороннее/base64-js \ No newline at end of file diff --git a/M/4.0/общее/pako b/M/4.0/общее/pako new file mode 120000 index 0000000..504d162 --- /dev/null +++ b/M/4.0/общее/pako @@ -0,0 +1 @@ +../../стороннее/pako \ No newline at end of file diff --git a/M/4.0/редактор.html b/M/4.0/редактор.html new file mode 100644 index 0000000..4959542 --- /dev/null +++ b/M/4.0/редактор.html @@ -0,0 +1,110 @@ + + + + +4.0 | +??? | +
3.5 | +объекты | +
3.4 | +Документация | +
3.3 | +тела, слежение | +
3.2 | +мир.параметрыЗапуска, мир.разобрать, заголовок, изображения, состояние, физика | +
3.1 | +Кнопки перезапуска, копирования ссылки, запуска в отдельной вкладке | +
3.0 | +Проверка введённого кода на отсутствие синтаксических ошибок | +
Тело представляет из себя сущность Matter.js с полной поддержкой свойств, которые можно указывать телам в Matter.js.
Пример № 1. Отображение статичной платформы и падающего на неё самовара.
- +Пример № 2. Составное тело с сенсором и статичная платформа.
- +ВНИМАНИЕ: на текущий момент слежение некорректно отрабатывает для составных объектов, +т.к. сенсор должен находиться строго под основанием самовара.
+Изображение представляет из себя отдельный <div>
, который можно исследовать в отладке браузера.
Пример № 1. Отображение статичного изображения под углом.
- +Пример № 2. Отображение статичной платформы и падающего на неё самовара.
- +Ниже представлены страницы с описанием каждого отдельного поддерживаемого ключа и примерами их использования:
diff --git a/M/doc/ru/keys.md b/M/doc/ru/keys.md index a91f1d2..dccc68c 100644 --- a/M/doc/ru/keys.md +++ b/M/doc/ru/keys.md @@ -7,14 +7,18 @@ Lang: ru Ниже представлены страницы с описанием каждого отдельного поддерживаемого ключа и примерами их использования: +1. [виды][styles] 1. [заголовок][title] 1. [изображения][images] 1. [объекты][objects] 1. [слежение][tracking] 1. [тела][bodies] +1. [физика][physics] [bodies]: bodies.html [images]: images.html [objects]: objects.html +[physics]: physics.html +[styles]: styles.html [title]: title.html [tracking]: tracking.html diff --git a/M/doc/ru/objects.html b/M/doc/ru/objects.html index bc79ebb..5985462 100644 --- a/M/doc/ru/objects.html +++ b/M/doc/ru/objects.html @@ -78,12 +78,12 @@ }Добавление одного или нескольких объектов, которые представляют собой комбинацию изображения, тела и их синхронизацию через слежение.
Пример № 1. Отображение двух падающих на платформу пауков.
- +Задание одного или нескольких настроек физики Matter.js, которые будут применяться для конкретного тела или объекта.
+Пример № 1. Маски столкновений.
+ +Задание одного или нескольких стилей CSS, которые будут применяться для конкретного изображения или объекта.
+Пример № 1. Задание стилей для изображения и объекта.
+ +Синхронизация изображения с телом. Исполняется каждый кадр.
+ВНИМАНИЕ: на текущий момент некорректно работает с составными телами: не учитывается вращение частей.
Пример № 1. Мгновенное следование изображения за телом.
- +Пример № 2. Замедленное следование изображения за телом со смещением и пределом для ограничения мельтешения.
- +