Extract pill UI helper and replace text backgrounds with rounded pills
This change introduces a new `src/util/pill.js` module that provides reusable helpers for creating "pill"-style UI labels: a semi-transparent white rounded rectangle backing (with black stroke) sized to the text, plus optional interactivity. It replaces the previous pattern of using Phaser's plain rectangular `backgroundColor` on Text objects, which couldn't produce rounded corners or consistent padding/stroke styling. Key changes: - Add `createPill(scene, x, y, text, style, originX, originY)` returning a Container with graphics backing + text, supporting corner origins and automatic re-fitting when text updates. - Add `pillInteractive(container, config)` to make pills clickable with a properly sized hit area (Containers lack texture frames by default). - Update UI scenes (`MainMenuScene`, `PlayScene`, `LevelSelectScene`, `LevelScoreScene`) to use `createPill` for HUD elements, labels, score/time displays, and menu/back buttons. - Remove per-call `backgroundColor` usage in favor of the shared pill styling constants in `pill.js`. This centralizes pill styling and behavior, improves visual consistency (rounded corners, padding, stroke), and simplifies interaction setup across scenes.
This commit is contained in:
parent
b81ffac547
commit
ba3385ee19
|
|
@ -3,6 +3,7 @@ import { GAME_WIDTH, GAME_HEIGHT, WORLD_SCALE, SCORE } from '../config.js';
|
||||||
import { markLevelComplete } from '../util/progress.js';
|
import { markLevelComplete } from '../util/progress.js';
|
||||||
import { createButton } from '../util/ui.js';
|
import { createButton } from '../util/ui.js';
|
||||||
import { formatTime } from '../util/formatTime.js';
|
import { formatTime } from '../util/formatTime.js';
|
||||||
|
import { createPill } from '../util/pill.js';
|
||||||
|
|
||||||
const KID_ROW_Y = GAME_HEIGHT * 0.62;
|
const KID_ROW_Y = GAME_HEIGHT * 0.62;
|
||||||
const KID_SPACING = 92 * WORLD_SCALE;
|
const KID_SPACING = 92 * WORLD_SCALE;
|
||||||
|
|
@ -43,21 +44,19 @@ export default class LevelScoreScene extends Phaser.Scene {
|
||||||
// so this reads as that same clock continuing, not a new element.
|
// so this reads as that same clock continuing, not a new element.
|
||||||
const startX = 24 * WORLD_SCALE;
|
const startX = 24 * WORLD_SCALE;
|
||||||
const hudY = 24 * WORLD_SCALE;
|
const hudY = 24 * WORLD_SCALE;
|
||||||
this.timeText = this.add.text(GAME_WIDTH - startX, hudY, formatTime(this.timeRemainingSeconds), {
|
this.timeText = createPill(this, GAME_WIDTH - startX, hudY, formatTime(this.timeRemainingSeconds), {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${32 * WORLD_SCALE}px`,
|
fontSize: `${32 * WORLD_SCALE}px`,
|
||||||
fontStyle: 'bold',
|
fontStyle: 'bold',
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
}, 1, 0).setDepth(10);
|
||||||
}).setOrigin(1, 0).setDepth(10);
|
|
||||||
|
|
||||||
this.scoreLabel = this.add.text(GAME_WIDTH / 2, GAME_HEIGHT * 0.2, 'Score:', {
|
this.scoreLabel = createPill(this, GAME_WIDTH / 2, GAME_HEIGHT * 0.2, 'Score:', {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${32 * WORLD_SCALE}px`,
|
fontSize: `${32 * WORLD_SCALE}px`,
|
||||||
fontStyle: 'bold',
|
fontStyle: 'bold',
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
}).setScale(0).setDepth(10);
|
||||||
}).setOrigin(0.5).setScale(0).setDepth(10);
|
|
||||||
|
|
||||||
// Both start alpha 0 - they sit at Phaser's default (0,0) position until
|
// Both start alpha 0 - they sit at Phaser's default (0,0) position until
|
||||||
// _flyInScore places them off-screen and tweens them in, and origin
|
// _flyInScore places them off-screen and tweens them in, and origin
|
||||||
|
|
@ -72,13 +71,12 @@ export default class LevelScoreScene extends Phaser.Scene {
|
||||||
strokeThickness: 6 * WORLD_SCALE,
|
strokeThickness: 6 * WORLD_SCALE,
|
||||||
}).setOrigin(0.5, 0.5).setAlpha(0).setDepth(10);
|
}).setOrigin(0.5, 0.5).setAlpha(0).setDepth(10);
|
||||||
|
|
||||||
this.solidFinishText = this.add.text(0, 0, 'Solid Finish', {
|
this.solidFinishText = createPill(this, 0, 0, 'Solid Finish', {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${20 * WORLD_SCALE}px`,
|
fontSize: `${20 * WORLD_SCALE}px`,
|
||||||
fontStyle: 'bold',
|
fontStyle: 'bold',
|
||||||
color: '#2c8f3c',
|
color: '#2c8f3c',
|
||||||
backgroundColor: '#ffffffaa',
|
}, 0, 0.5).setAlpha(0).setDepth(10);
|
||||||
}).setOrigin(0, 0.5).setAlpha(0).setDepth(10);
|
|
||||||
|
|
||||||
this.kidSprites = [];
|
this.kidSprites = [];
|
||||||
this.kidLabels = [];
|
this.kidLabels = [];
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { autoLayoutPoints, sampleSpline } from '../data/levels/positioning.js';
|
||||||
import { isLevelComplete, getBestScore } from '../util/progress.js';
|
import { isLevelComplete, getBestScore } from '../util/progress.js';
|
||||||
import { playMenuMusic } from '../util/music.js';
|
import { playMenuMusic } from '../util/music.js';
|
||||||
import { nodeDisplaySize, scalePos, BADGE_HIT_FRAC, BADGE_HIT_RADIUS_MULT } from '../util/mapArt.js';
|
import { nodeDisplaySize, scalePos, BADGE_HIT_FRAC, BADGE_HIT_RADIUS_MULT } from '../util/mapArt.js';
|
||||||
|
import { createPill, pillInteractive } from '../util/pill.js';
|
||||||
|
|
||||||
const NODE_HOVER = 1.12;
|
const NODE_HOVER = 1.12;
|
||||||
const NODE_IDLE_PULSE = 1.05;
|
const NODE_IDLE_PULSE = 1.05;
|
||||||
|
|
@ -29,10 +30,12 @@ const PILL_STYLE = {
|
||||||
// SCORE_PILL_STYLE below.
|
// SCORE_PILL_STYLE below.
|
||||||
fontSize: `${13 * WORLD_SCALE}px`,
|
fontSize: `${13 * WORLD_SCALE}px`,
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
|
||||||
padding: { x: 9 * WORLD_SCALE, y: 5 * WORLD_SCALE },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Labels that share PILL_STYLE are pills (see util/pill.js) - createPill
|
||||||
|
// supplies the rounded white backing + black stroke and the guaranteed
|
||||||
|
// text/edge padding; only the font side lives here.
|
||||||
|
|
||||||
// The "best score" pill that rolls up under cleared nodes - gold, to match
|
// The "best score" pill that rolls up under cleared nodes - gold, to match
|
||||||
// the gold score numerals in the score tally scene.
|
// the gold score numerals in the score tally scene.
|
||||||
const SCORE_PILL_STYLE = {
|
const SCORE_PILL_STYLE = {
|
||||||
|
|
@ -73,18 +76,15 @@ export default class LevelSelectScene extends Phaser.Scene {
|
||||||
.setDepth(DEPTH.chrome);
|
.setDepth(DEPTH.chrome);
|
||||||
this._pager = this.add.graphics().setDepth(DEPTH.chrome);
|
this._pager = this.add.graphics().setDepth(DEPTH.chrome);
|
||||||
|
|
||||||
const back = this.add
|
const back = createPill(this, 44 * WORLD_SCALE, GAME_HEIGHT - 44 * WORLD_SCALE, '< Menu', { ...PILL_STYLE, fontSize: `${16 * WORLD_SCALE}px` }, 0, 0);
|
||||||
.text(44 * WORLD_SCALE, GAME_HEIGHT - 44 * WORLD_SCALE, '< Menu', { ...PILL_STYLE, fontSize: `${16 * WORLD_SCALE}px` })
|
pillInteractive(back, { useHandCursor: true });
|
||||||
.setInteractive({ useHandCursor: true })
|
back.setDepth(DEPTH.chrome);
|
||||||
.setDepth(DEPTH.chrome);
|
|
||||||
back.on('pointerdown', () => {
|
back.on('pointerdown', () => {
|
||||||
this.scene.stop('LevelSelect');
|
this.scene.stop('LevelSelect');
|
||||||
this.scene.start('MainMenu');
|
this.scene.start('MainMenu');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.add
|
createPill(this, GAME_WIDTH / 2, GAME_HEIGHT - 36 * WORLD_SCALE, '← → switch campaign · click a node to drive', PILL_STYLE)
|
||||||
.text(GAME_WIDTH / 2, GAME_HEIGHT - 36 * WORLD_SCALE, '← → switch campaign · click a node to drive', PILL_STYLE)
|
|
||||||
.setOrigin(0.5)
|
|
||||||
.setDepth(DEPTH.chrome);
|
.setDepth(DEPTH.chrome);
|
||||||
|
|
||||||
this._buildCampaign(true);
|
this._buildCampaign(true);
|
||||||
|
|
@ -217,7 +217,7 @@ export default class LevelSelectScene extends Phaser.Scene {
|
||||||
const best = getBestScore(level.id);
|
const best = getBestScore(level.id);
|
||||||
if (best != null) this._scoreRollup(p, nh, best, 80 + i * 70);
|
if (best != null) this._scoreRollup(p, nh, best, 80 + i * 70);
|
||||||
} else if (state === 'current') {
|
} else if (state === 'current') {
|
||||||
this._groups.tags.push(this.add.text(p.x, p.y + nh * 0.68, level.name, PILL_STYLE).setOrigin(0.5).setDepth(DEPTH.tag));
|
this._groups.tags.push(createPill(this, p.x, p.y + nh * 0.68, level.name, PILL_STYLE).setDepth(DEPTH.tag));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -353,6 +353,8 @@ export default class LevelSelectScene extends Phaser.Scene {
|
||||||
|
|
||||||
_tooltip(x, y, msg) {
|
_tooltip(x, y, msg) {
|
||||||
this._hideTooltip();
|
this._hideTooltip();
|
||||||
|
// Tooltip is dark, not one of the white pills (util/pill.js is
|
||||||
|
// white-fill-only), so it keeps its own plain backgroundColor.
|
||||||
this._tip = this.add
|
this._tip = this.add
|
||||||
.text(x, y, msg, {
|
.text(x, y, msg, {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Phaser from 'phaser';
|
import Phaser from 'phaser';
|
||||||
import { GAME_WIDTH, GAME_HEIGHT, WORLD_SCALE } from '../config.js';
|
import { GAME_WIDTH, GAME_HEIGHT, WORLD_SCALE } from '../config.js';
|
||||||
import { createButton } from '../util/ui.js';
|
import { createButton } from '../util/ui.js';
|
||||||
|
import { createPill } from '../util/pill.js';
|
||||||
import { playMenuMusic } from '../util/music.js';
|
import { playMenuMusic } from '../util/music.js';
|
||||||
|
|
||||||
export default class MainMenuScene extends Phaser.Scene {
|
export default class MainMenuScene extends Phaser.Scene {
|
||||||
|
|
@ -26,15 +27,14 @@ export default class MainMenuScene extends Phaser.Scene {
|
||||||
this.scene.start('LevelSelect');
|
this.scene.start('LevelSelect');
|
||||||
});
|
});
|
||||||
|
|
||||||
// backgroundColor pill (same convention as PlayScene's HUD text) - the
|
// Pill (see util/pill.js) - the treeline in bg_menu.png sits right
|
||||||
// treeline in bg_menu.png sits right behind this text and would
|
// behind this text and would otherwise swallow the dark-on-dark-green
|
||||||
// otherwise swallow the dark-on-dark-green portion of it.
|
// portion of it.
|
||||||
this.add.text(GAME_WIDTH / 2, GAME_HEIGHT / 2 + 60 * WORLD_SCALE, 'Arrows/WASD to drive and lean.\nDon\'t let the g-force throw the kids out!', {
|
createPill(this, GAME_WIDTH / 2, GAME_HEIGHT / 2 + 60 * WORLD_SCALE, 'Arrows/WASD to drive and lean.\nDon\'t let the g-force throw the kids out!', {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${14 * WORLD_SCALE}px`,
|
fontSize: `${14 * WORLD_SCALE}px`,
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
backgroundColor: '#ffffffaa',
|
});
|
||||||
}).setOrigin(0.5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import EngineSound from '../systems/EngineSound.js';
|
||||||
import { stopMenuMusic } from '../util/music.js';
|
import { stopMenuMusic } from '../util/music.js';
|
||||||
import { playLevelVoiceLine } from '../util/voiceLine.js';
|
import { playLevelVoiceLine } from '../util/voiceLine.js';
|
||||||
import { formatTime } from '../util/formatTime.js';
|
import { formatTime } from '../util/formatTime.js';
|
||||||
|
import { createPill } from '../util/pill.js';
|
||||||
|
|
||||||
export default class PlayScene extends Phaser.Scene {
|
export default class PlayScene extends Phaser.Scene {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -214,28 +215,25 @@ export default class PlayScene extends Phaser.Scene {
|
||||||
this.hudIcons.push(icon);
|
this.hudIcons.push(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hudText = this.add.text(startX, y + 24 * WORLD_SCALE, `Kids aboard: ${this.level.kidsAboard}/${this.level.kidsAboard}`, {
|
this.hudText = createPill(this, startX, y + 24 * WORLD_SCALE, `Kids aboard: ${this.level.kidsAboard}/${this.level.kidsAboard}`, {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${14 * WORLD_SCALE}px`,
|
fontSize: `${14 * WORLD_SCALE}px`,
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
}, 0, 0).setScrollFactor(0).setDepth(10);
|
||||||
}).setScrollFactor(0).setDepth(10);
|
|
||||||
|
|
||||||
this.timerText = this.add.text(GAME_WIDTH - startX, y, formatTime(this._timeRemaining), {
|
this.timerText = createPill(this, GAME_WIDTH - startX, y, formatTime(this._timeRemaining), {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${32 * WORLD_SCALE}px`,
|
fontSize: `${32 * WORLD_SCALE}px`,
|
||||||
fontStyle: 'bold',
|
fontStyle: 'bold',
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
}, 1, 0).setScrollFactor(0).setDepth(10);
|
||||||
}).setOrigin(1, 0).setScrollFactor(0).setDepth(10);
|
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
this.debugText = this.add.text(startX, y + 52 * WORLD_SCALE, 'g-force: 0.00', {
|
this.debugText = createPill(this, startX, y + 52 * WORLD_SCALE, 'g-force: 0.00', {
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: `${14 * WORLD_SCALE}px`,
|
fontSize: `${14 * WORLD_SCALE}px`,
|
||||||
color: '#1a1f29',
|
color: '#1a1f29',
|
||||||
backgroundColor: '#ffffffaa',
|
}, 0, 0).setScrollFactor(0).setDepth(10);
|
||||||
}).setScrollFactor(0).setDepth(10);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
import Phaser from 'phaser';
|
||||||
|
import { WORLD_SCALE } from '../config.js';
|
||||||
|
|
||||||
|
// Rounded "pill" backing for the dark-on-white text labels used across the
|
||||||
|
// UI. Phaser's Text backgroundColor is always a plain rectangle, so this
|
||||||
|
// helper replaces it: the text keeps its own style (font, size, color) but
|
||||||
|
// draws with NO background, and a graphics pill - semi-transparent white,
|
||||||
|
// rounded corners, black stroke - is sized to the text and sits just behind
|
||||||
|
// it in a Container. The container is one object with one depth/alpha/tween
|
||||||
|
// identity, so it can replace a bare Text in place; the text's padding
|
||||||
|
// (floored at PILL_PADDING) keeps breathing room between glyphs and the
|
||||||
|
// pill edges.
|
||||||
|
//
|
||||||
|
// Usage: const pill = createPill(scene, x, y, 'Label', { fontSize: ... })
|
||||||
|
// The container is origin-0.5 by default, so existing .setOrigin(0.5) call
|
||||||
|
// sites keep working. For labels that used a corner origin (the HUD timer
|
||||||
|
// at (1, 0), "Solid Finish" at (0, 0.5)), pass originX/originY - the
|
||||||
|
// backing then aligns so that corner of the pill sits on the container
|
||||||
|
// position, and the container's transform/positioning semantics are
|
||||||
|
// unchanged.
|
||||||
|
|
||||||
|
export const PILL_FILL = 0xffffff;
|
||||||
|
export const PILL_FILL_ALPHA = 0.667; // same '#ffffffaa' the text backgrounds used
|
||||||
|
export const PILL_STROKE = 0x000000;
|
||||||
|
export const PILL_STROKE_WIDTH = 2 * WORLD_SCALE;
|
||||||
|
export const PILL_RADIUS = 8 * WORLD_SCALE;
|
||||||
|
export const PILL_PADDING = 6 * WORLD_SCALE;
|
||||||
|
|
||||||
|
// Sizes the backing pill to the text and positions both so the pill's
|
||||||
|
// origin corner (0/0.5/1 on each axis) lands on the container position -
|
||||||
|
// mirroring what setOrigin(ox, oy) on a bare Text would do. The text and
|
||||||
|
// pill share one bounding box, so the corner aligns for both.
|
||||||
|
function fitPill(c) {
|
||||||
|
const back = c.list[0];
|
||||||
|
const text = c.list[1];
|
||||||
|
const w = Math.max(text.width, 1);
|
||||||
|
const h = Math.max(text.height, 1);
|
||||||
|
const cx = (0.5 - c.pillOriginX) * w;
|
||||||
|
const cy = (0.5 - c.pillOriginY) * h;
|
||||||
|
// Track the pill box as the container's own size - displayOriginX/Y
|
||||||
|
// (used by the input system to normalize hit-test points) are derived
|
||||||
|
// from width/2, so without this an enabled hit area would be off by
|
||||||
|
// half its width/height.
|
||||||
|
c.setSize(w, h);
|
||||||
|
text.x = cx;
|
||||||
|
text.y = cy;
|
||||||
|
back.clear();
|
||||||
|
back.fillStyle(PILL_FILL, PILL_FILL_ALPHA);
|
||||||
|
back.fillRoundedRect(cx - w / 2, cy - h / 2, w, h, PILL_RADIUS);
|
||||||
|
back.lineStyle(PILL_STROKE_WIDTH, PILL_STROKE, 1);
|
||||||
|
back.strokeRoundedRect(cx - w / 2, cy - h / 2, w, h, PILL_RADIUS);
|
||||||
|
// Keep an input hit area (if enabled via pillInteractive) matched to the
|
||||||
|
// pill box. Container hit-test points are normalized by adding
|
||||||
|
// displayOrigin (always width/2, height/2 for a Container), so the rect
|
||||||
|
// lives in that normalized space - (cx, cy) here rather than the raw
|
||||||
|
// local corner.
|
||||||
|
if (c.input && c.input.hitArea) {
|
||||||
|
syncHitArea(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every Text re-render path (setText, setStyle, setPadding, ...) funnels
|
||||||
|
// through updateText, but this Phaser build emits no event for it - so
|
||||||
|
// wrap it and re-fit the backing after each pass.
|
||||||
|
function observeText(c, text) {
|
||||||
|
const originalUpdateText = text.updateText.bind(text);
|
||||||
|
text.updateText = function () {
|
||||||
|
const r = originalUpdateText();
|
||||||
|
fitPill(c);
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createPill(scene, x, y, textContent, style, originX = 0.5, originY = 0.5) {
|
||||||
|
// The text's own background is what we're replacing - drop it here (and
|
||||||
|
// keep it off any later setStyle too), else both would draw.
|
||||||
|
delete style.backgroundColor;
|
||||||
|
const textStyle = { ...style };
|
||||||
|
const padding = textStyle.padding ? { ...textStyle.padding } : {};
|
||||||
|
padding.left = Math.max(padding.left || 0, PILL_PADDING);
|
||||||
|
padding.right = Math.max(padding.right || 0, PILL_PADDING);
|
||||||
|
padding.top = Math.max(padding.top || 0, PILL_PADDING);
|
||||||
|
padding.bottom = Math.max(padding.bottom || 0, PILL_PADDING);
|
||||||
|
textStyle.padding = padding;
|
||||||
|
|
||||||
|
const textObj = scene.add.text(0, 0, textContent, textStyle).setOrigin(0.5);
|
||||||
|
const back = scene.add.graphics();
|
||||||
|
const c = scene.add.container(x, y, [back, textObj]);
|
||||||
|
c.pillOriginX = originX;
|
||||||
|
c.pillOriginY = originY;
|
||||||
|
observeText(c, textObj);
|
||||||
|
fitPill(c);
|
||||||
|
|
||||||
|
// Scene code treats the pill like the Text it replaces - delegate the
|
||||||
|
// Text methods it calls. setText goes through the observed updateText,
|
||||||
|
// so the backing re-fits automatically.
|
||||||
|
c.text = textObj;
|
||||||
|
c.setText = (value) => { textObj.setText(value); return c; };
|
||||||
|
c.setColor = (color) => { textObj.setColor(color); return c; };
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes a pill clickable. A bare setInteractive() on a Container derives its
|
||||||
|
// hit area from a texture frame it doesn't have (a 0x0 rectangle -
|
||||||
|
// effectively unclickable), so this supplies an explicit rectangle that
|
||||||
|
// fitPill keeps sized to the pill box on every text update. Extra config
|
||||||
|
// (useHandCursor, draggable, ...) is forwarded as-is.
|
||||||
|
export function pillInteractive(c, config = {}) {
|
||||||
|
// Explicit rect + Rectangle.Contains - same semantics as the default
|
||||||
|
// texture-frame hit area, but sized to the pill box (a Container has no
|
||||||
|
// texture frame of its own, so the default would be 0x0 / unclickable).
|
||||||
|
const hitArea = new Phaser.Geom.Rectangle(0, 0, 1, 1);
|
||||||
|
c.setInteractive({ hitArea, hitAreaCallback: Phaser.Geom.Rectangle.Contains, ...config });
|
||||||
|
syncHitArea(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncHitArea(c) {
|
||||||
|
if (!c.input || !c.input.hitArea) return;
|
||||||
|
const text = c.list[1];
|
||||||
|
const w = Math.max(text.width, 1);
|
||||||
|
const h = Math.max(text.height, 1);
|
||||||
|
const cx = (0.5 - c.pillOriginX) * w;
|
||||||
|
const cy = (0.5 - c.pillOriginY) * h;
|
||||||
|
Object.assign(c.input.hitArea, { x: cx, y: cy, width: w, height: h });
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue