8 октября 2025 г.

Интеграции Pixi.js и Matter.js

Я уже писал про завершение создания нами (Студия 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)

Всё просто! Но интересно 🙂

Интерактивный пример можно потрогать здесь.

Комментариев нет...

Отправить комментарий