Пробуем физику в Phaser

В этой статье мы познакомимся с физическими движками доступными в Phaser-е по умолчанию. Это Arcade, P2JS и Ninja.

Так же в Phaser-е доступен и Box2d, но он доступен только как платное дополнение.

Arcade

Физика Arcade весьма элементарна, в ней возможны только простейшие геометрические фигуры: прямоугольник и окружность. При этом тела не могу вращаться. Поэтому эта физика подходит только для каких-нибудь элементарных физических игр. Достаточно посмотреть пример на оф. сайте.

Ninja

Физика Ninja, была создана во Flash компанией Metanet Software и портирована на js Ричардом (создателем Фейзера).

Как говорит сам Ричи (написано в документации), «библиотека работает хорошо, но она нуждается в серьёзной доработке и оптимизации». Таким образом эту физику не используют, т.к., можно сказать, она технически устарела. Да и скудное кол-во примеров на сайте тоже об этом говорит.

P2JS

А вот физика P2 — то что надо. Можно создавать сложные объекты, настраивать и вращать их и т.д. как в полноценном физическом движке.

Для начала сделаем простейший пример использование этой физики — создание и удаление геометрических примитивов.

Для всех своих проектов я буду брать свой шаблон для HTML5 проекта на Phaser+TypeScript который описан в этой статье. Создаём новый проект на TS, подключаем фейзер или просто берём мой шаблон.

И делам создание объектов по тапу на пустом месте и уничтожение объекта если тапнули на сам объект:

Можно открыть чистую страницу примера для мобильных устройств: страница примера.

Полный код примера вы найдёте на гитхабе.

Основной код находится в классе состояния Game:

module P2JSExample.Client {

	export class Game extends Phaser.State {

		tfFPS: Phaser.Text;

		create() {
			// for fps displaing
			this.game.time.advancedTiming = true;
			// physics init
			this.physics.startSystem(Phaser.Physics.P2JS);
			// setting gravity
			this.game.physics.p2.gravity.y = 300;
			// adding event listener for mousedown/touch event
			this.game.input.onDown.add(this.onDown, this);

			this.tfFPS = new Phaser.Text(this.game, 5, 5, 'FPS: ', { fill: '#EEEEEE', align: 'left' });
			this.add.existing(this.tfFPS);

			var info = this.add.text(Config.GW - 5, 5, 'Phaser P2 physics test\nclick on the screen and objects', { fill: '#EEEEEE', align: 'right' });
			info.anchor.set(1, 0);

			this.addRandomObject(new Phaser.Point(this.world.centerX, this.world.centerY));
		}

		onDown(pointer: Phaser.Pointer) {
			// checking for bodies under the mouse
			var bodyClicked = this.game.physics.p2.hitTest(pointer.position);
			if (bodyClicked.length == 0) {
				this.addRandomObject(pointer.position);
			}
			else {
				try {
					// destruction of physics body and its graphic asset
					for (var i = 0; i < bodyClicked.length; i++) {
						var spr: Phaser.Sprite = bodyClicked[i]['parent']['sprite'] as Phaser.Sprite;
						if (spr != null) spr.kill();
					}
				}
				catch (e) {
					LogMng.log(e, LogMng.ERROR);
				}
			}

		}

		// creation of physics body and its graphic asset
		addRandomObject(aPos: Phaser.Point) {
			// select random texture
			var isCerc: boolean = MyMath.randomIntInRange(1, 10) <= 5;
			var key = isCerc ? Const.cercObjs[MyMath.randomIntInRange(0, Const.cercObjs.length - 1)] :
				Const.rectObjs[MyMath.randomIntInRange(0, Const.rectObjs.length - 1)];

			var newObj = this.add.sprite(aPos.x, aPos.y, key);

			// enable physics to graphic
			this.game.physics.p2.enable(newObj);

			// make circle
			if (isCerc)
				newObj.body.setCircle(35);
		}

		update() {

		}

		render() {
			// update FPS
			this.tfFPS.text = 'FPS: ' + (String(this.game.time.fps) || '--');
    }

	}

}

Из интересных моментов стоит обратить как надо отображать FPS counter в Phaser-е, для начала надо поставить свойство game.time.advancedTiming в true а затем отображать переменную this.game.time.fps в процедуре render(), т.к. в отличии от update() она вызывается через фиксированные промежутки времени.

Использование Physics Editor для P2

Physics Editor — это очень простая и удобная программа разработанная командой CodeAndWeb (создатели TexturePacker) для создания физики для 2D объектов.

Программа не бесплатная, но стоит не дорого и она того стоит.

Существует готовый экспорт данных для Phaser-а и для многих других движков и фреймворков. Вот официальная документация для Phaser-а: ссылка.

Принцип использования такой — загружаешь текстуры, которые будут использоваться в игре в программу и прям по ним создаёшь физический объект. Далее экспорт и использование в программе.

Вот как загружаются данные:

preload() {
	// phys
	this.load.physics('physData', './assets/phys/objects.json');
}

А вот как применяются на объект:

constructor(game: Phaser.Game, x: number, y: number, id: number) {
	super(game, x, y, 'game', ConstObjs.ObjsData[id].texture);

	this.game.physics.p2.enable(this, false);
	this.body.clearShapes();
	this.body.loadPolygon('physData', ConstObjs.ObjsData[id].texture);
	this.body.fixedRotation = true;
	this.body.kinematic = true;
}

Легко, просто и удобно. Я приобрёл редактор как раз перед проектом, в котором надо было делать физику не стандартной формы, теперь я не знаю лучшей альтернативы и доволен как слон)

В следующих статьях сделаем какую-нибудь простую игру с физикой)

В комментариях можете писать какую бы вам хотелось.