phaser-jsx
Version:
Use JSX in Phaser.
376 lines • 16.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.reconcileTree = reconcileTree;
const phaser_1 = __importDefault(require("phaser"));
const components_1 = require("../components");
const GameObjects = __importStar(require("../components/GameObjects"));
const constants_1 = require("../constants");
const element_1 = require("../element");
const props_1 = require("./props");
const ref_1 = require("./ref");
/**
* Reconciles a new JSX element tree against the existing game object tree.
*
* @param element - The new JSX element to reconcile.
* @param oldNode - The existing game object node (or null if none).
* @param scene - The Phaser scene.
* @param parent - Optional parent container/layer.
* @returns The new game object node tree.
*/
function reconcileTree(element, oldNode, scene, parent) {
var _a, _b;
if (element == null) {
return destroyIfOld(oldNode);
}
if (Array.isArray(element)) {
return reconcileArray(element, (_a = oldNode === null || oldNode === void 0 ? void 0 : oldNode.children) !== null && _a !== void 0 ? _a : null, scene, parent);
}
if (element.type === components_1.Fragment) {
const children = element.props.children;
return reconcileArray(children ? toArray(children) : [], (_b = oldNode === null || oldNode === void 0 ? void 0 : oldNode.children) !== null && _b !== void 0 ? _b : null, scene, parent);
}
if (!(0, element_1.isValidElement)(element)) {
return destroyIfOld(oldNode);
}
// function component
if (typeof element.type === 'function' && !isGameObject(element.type)) {
const Component = element.type;
return reconcileTree(Component(element.props), oldNode, scene, parent);
}
return reconcileGameObject(element, oldNode, scene, parent);
}
function destroyIfOld(oldNode) {
if (oldNode) {
destroyNode(oldNode);
}
return null;
}
function reconcileArray(elements, oldChildren, scene, parent) {
var _a, _b;
const node = {
gameObject: null,
props: {},
children: [],
};
const oldLength = (_a = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren.length) !== null && _a !== void 0 ? _a : 0;
for (let i = 0; i < elements.length; i++) {
const oldChild = (_b = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren[i]) !== null && _b !== void 0 ? _b : null;
const newChild = reconcileTree(elements[i], oldChild, scene, parent);
node.children.push(newChild);
if (oldChild && !newChild) {
destroyNode(oldChild);
}
}
// Destroy any extra old children beyond new length
for (let i = elements.length; i < oldLength; i++) {
const oldChild = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren[i];
if (oldChild) {
destroyNode(oldChild);
}
}
return node;
}
function reconcileGameObject(element, oldNode, scene, parent) {
var _a, _b, _c;
const elementProps = element.props;
const { children, ref } = elementProps, props = __rest(elementProps, ["children", "ref"]);
let gameObject;
if (oldNode) {
// Reuse existing game object - just patch changed props
gameObject = oldNode.gameObject;
// v8 ignore next
if (gameObject) {
patchProps(gameObject, oldNode.props, props, scene);
(0, ref_1.attachRef)(gameObject, ref);
}
}
else {
// Create new game object
const newGameObject = createGameObject(element, scene);
// Add to scene
if (typeof (parent === null || parent === void 0 ? void 0 : parent.add) === 'function') {
parent.add(newGameObject);
}
else {
scene.add.existing(newGameObject);
}
(0, props_1.setProps)(newGameObject, props, scene);
(0, ref_1.attachRef)(newGameObject, ref);
gameObject = newGameObject;
}
// Reconcile children for Container/Layer
const node = {
gameObject,
props,
children: [],
};
if (element.type === phaser_1.default.GameObjects.Container ||
element.type === phaser_1.default.GameObjects.Layer) {
const childArray = children ? toArray(children) : [];
const oldChildren = (_a = oldNode === null || oldNode === void 0 ? void 0 : oldNode.children) !== null && _a !== void 0 ? _a : null;
const oldLength = (_b = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren.length) !== null && _b !== void 0 ? _b : 0;
for (let i = 0; i < childArray.length; i++) {
const oldChild = (_c = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren[i]) !== null && _c !== void 0 ? _c : null;
const newChild = reconcileTree(childArray[i], oldChild, scene, gameObject);
node.children.push(newChild);
if (oldChild && !newChild) {
destroyNode(oldChild);
}
}
// Destroy extra old children beyond new length
for (let i = childArray.length; i < oldLength; i++) {
const oldChild = oldChildren === null || oldChildren === void 0 ? void 0 : oldChildren[i];
if (oldChild) {
destroyNode(oldChild);
}
}
}
return node;
}
function createGameObject(element, scene) {
const { props, color, frame, points, shader, style, texture } = element.props;
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
switch (true) {
case element.type === phaser_1.default.GameObjects.BitmapText:
case element.type === phaser_1.default.GameObjects.DynamicBitmapText: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.font,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Bob: {
const blitter = new phaser_1.default.GameObjects.Blitter(scene);
scene.add.existing(blitter);
const args = [
blitter,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
frame,
props === null || props === void 0 ? void 0 : props.visible,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Container:
case element.type === phaser_1.default.GameObjects.Layer: {
const args = [scene];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.GameObject: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.type,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Image:
case element.type === phaser_1.default.GameObjects.Sprite:
case element.type === phaser_1.default.GameObjects.NineSlice: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
texture,
frame,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Light: {
const args = [
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.radius,
color === null || color === void 0 ? void 0 : color.r,
color === null || color === void 0 ? void 0 : color.g,
color === null || color === void 0 ? void 0 : color.b,
props === null || props === void 0 ? void 0 : props.intensity,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.PathFollower: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.path,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
texture,
frame,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Mesh2D: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
texture,
props === null || props === void 0 ? void 0 : props.vertices,
props === null || props === void 0 ? void 0 : props.indices,
props === null || props === void 0 ? void 0 : props.flipV,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.PointLight: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
// v8 ignore start
color
? phaser_1.default.Display.Color.GetColor(color.r, color.g, color.b)
: // v8 ignore end
undefined,
props === null || props === void 0 ? void 0 : props.radius,
props === null || props === void 0 ? void 0 : props.intensity,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Rectangle: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.width,
props === null || props === void 0 ? void 0 : props.height,
props === null || props === void 0 ? void 0 : props.fillColor,
props === null || props === void 0 ? void 0 : props.fillAlpha,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Zone: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Rope: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
texture,
frame,
points,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Shader: {
const args = [scene, shader];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Text: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.text,
style,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.TileSprite: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.width,
props === null || props === void 0 ? void 0 : props.height,
texture,
frame,
];
return new element.type(...args);
}
case element.type === phaser_1.default.GameObjects.Video: {
const args = [
scene,
props === null || props === void 0 ? void 0 : props.x,
props === null || props === void 0 ? void 0 : props.y,
props === null || props === void 0 ? void 0 : props.cacheKey,
];
return new element.type(...args);
}
default:
return new element.type(scene);
}
/* eslint-enable @typescript-eslint/non-nullable-type-assertion-style, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
}
function patchProps(gameObject, oldProps, newProps, scene) {
// Remove old event listeners
for (const key in oldProps) {
if ((0, constants_1.isEventKey)(key) && typeof oldProps[key] === 'function') {
const eventName = key.slice(2).toLowerCase();
gameObject.off(eventName);
}
}
(0, props_1.setProps)(gameObject, newProps, scene);
}
function destroyNode(node) {
var _a;
if ((_a = node.gameObject) === null || _a === void 0 ? void 0 : _a.active) {
node.gameObject.destroy();
}
for (const child of node.children) {
if (child) {
destroyNode(child);
}
}
}
const gameObjects = Object.keys(GameObjects).map((key) => GameObjects[key]);
function isGameObject(type) {
return gameObjects.some((gameObject) => gameObject === type);
}
function toArray(item) {
return Array.isArray(item) ? item : [item];
}
//# sourceMappingURL=reconcile.js.map