Я уже писал про завершение создания нами (Студия 42) браузерной казуальной игры про доблестную выхухоль Плюха. С процессом было связано много интересных особенностей, изысканий, решений о которых и постараюсь рассказать.
Изначально планировалось, что одной из мини-игр будет простой кликер. Но подумалось, что механика с сортировкой будет намного занятнее. Сделал прототип с обычным перетаскиванием – стало понятно, что эту механику можно дополнить двумерной физикой. Гравитацию сделать можно и без движка, а вот реализацию столкновений хотелось чуть более сложную. Хотелось, чтобы решение было сразу легко масштабируемым. К тому же, по бюджету это не слишком затратно.
Для рендера использовал старого знакомого – движок отрисовки Pixi.js. И когда-то давно уже успешно прикручивал к Pixi.js порт физического движка Box2d, но работа по разным причинам оказалась не востребованной. Проверил состояние этого движка в разных реализациях, посмотрел API и решил поискать альтернативу. Остановился на Matter.js.
Интеграция, как и с Box2d много времени не заняла. В репозитории можно посмотреть пример реализации механики в подробностях. Основной принцип – связь тела физического движка и отображаемого объекта.
Класс на Coffeescript для объекта PIXI.Graphics:
class BoxBody
@anchor = {
x: 0
y: 0
}
constructor: (x, y, width, height, color, isStatic=true, options=null) ->
@display = new PIXI.Graphics()
@display.x = x - BoxBody.anchor.x
@display.y = y - BoxBody.anchor.y
@width = width
@height = height
@color = color
@display.rect -width / 2, -height / 2, width, height
@display.fill color
@display.eventMode = 'static'
@display.cursor = 'pointer'
@options = {...(options or {}), ...{
isStatic
}}
@body = Matter.Bodies.rectangle x + width / 2, y + height / 2, width, height, @options
move: ->
{ x, y } = @body.position
@display.x = x
@display.y = y
@display.rotation = @body.angle
Класс на Coffeescript для объекта PIXI.Sprite:
class SpriteBody
constructor: (x, y, width, height, texture, isStatic=true, options=null) ->
@display = PIXI.Sprite.from texture
@display.anchor.set .5
@display.x = x
@display.y = y
@display.width = width
@display.height = height
@display.eventMode = 'static'
@display.cursor = 'pointer'
@options = {...(options or {}), ...{
isStatic
}}
@body = Matter.Bodies.rectangle x + width / 2, y + height / 2, width, height, @options
move: ->
{ x, y } = @body.position
@display.x = x
@display.y = y
@display.rotation = @body.angle
В цикле отрисовки Pixi.js обновляем состояние движка и положение отображаемого объекта.
tick: (time) ->
@actors.forEach (a) ->
a.move()
if @engine
Matter.Engine.update @engine, time.deltaTime * (1000 / 60)
Всё просто! Но интересно 🙂
Интерактивный пример можно потрогать здесь.
Отправить комментарий