Разработка на коленке

"тут должна быть красивая цитата о программировании"

Гонки на phaser3 + matterjs

2018-08-22 22:50
phaser3-racing-car-preview

Чем мне нравится разработка игр в качестве хобби, так это возможностью менять геймплей по ходу разработки, не опасаясь, что это кому-нибудь сломает бизнес-модель.

Сперва я думал сделать так, чтобы машинка собирала разбросанные шины в центре поля, а людей и конусы сбивать было нельзя. Но потом оказалось, что гораздо веселее как раз таки сбивать конусы, а о людях вообще не заботиться. Потом сделал так, чтобы люди были кем-то вроде дорожных работников, которые поднимают сваленные конусы. Что самое интересное, обычного рандомного движения для людей оказалось достаточно, а писать ИИ не понадобилось, и без него играть порой сложно.

В итоге получилась игра, в которой нужно кататься машинкой по полю, сбивать конусы, а заодно отпихивать ремонтников подальше от конусов, потому что эти вредные рабочие совсем не боятся столкновений.

Matter

Аркадный физический движок мне не подошёл, потому что его модель работы AABB создавала проблемы даже в шутере, так как вращается там только картинка, а не тело целиком.

Код

В плане кода в этот раз вместо наследования для объектов стал использовать агрегирование, в связке с phaser это оказалось удобнее, чем расширение классов:

class Cone {
    constructor(scene, x, y) {
        this.UP = 'cone1';
        this.DOWN = 'cone2';

        this.isUp = true;

        this.scene = scene;

        this.body = this.scene.matter.add.image(x, y, this.UP);

        this.body.body.label = 'cone';

        this.body.body.cone = this;

        this.body.setScale(0.5);
    }

    up () {
        this.isUp = true;
        this.body.setTexture('cone1');
    }

    down () {
        this.isUp = false;
        this.body.setTexture('cone2');
    }
};

Агрегация даёт возможность строить свою иерархию, а объекты движка использовать для рисования и физики. Впрочем, здесь наверняка сказывается моё плохое знание третьей версии фазера, которая отличается от второй, плюс новая физика.

Ну и ещё пришлось разбираться, как работает детект столкновений, если их несколько. Для нормальной обработки нужно перебрать все пары столкнувшихся тел:

createCollisions() {
    this.matter.world.on('collisionstart', (event) => {
        event.pairs.forEach(pair => {
            const { bodyA, bodyB  } = pair;

            if (bodyA.label === 'car' && bodyB.label === 'cone') {
                bodyB.cone.down();
            }
            else if (bodyA.label === 'cone' && bodyB.label === 'car') {
                bodyA.cone.down();
            }
            else if (bodyA.label === 'man' && bodyB.label === 'cone') {
                bodyB.cone.up();
            }
            else if (bodyA.label === 'cone' && bodyB.label === 'man') {
                bodyA.cone.up();
            }
        });

        if (this.cones.filter(cone => cone.isUp).length === 0) {
            this.scene.start('GameOver');
        }
    });
}

Ссылка на игру

deathworld game

Ресурсы

В этот раз решил не рисовать графику, а взять на http://opengameart.org/

Исходники

Исходный код там - Исходники