Taller canvas + real background design for all 4 game templates
Phone screenshots showed the canvas was short and squat (960x600, 8:5) leaving most of the screen blank, with Clicker's hero list and Quiz's answer options too cramped to tap comfortably. Also the dark-mode canvas background was the same near-black as the page, so games had no visible frame and read as flat/undesigned. Bumps canvas to 960x720 (4:3) and uses the extra room to enlarge hero rows, quiz options/lifelines, and maze/snake grid cells. Adds a themed gradient frame around the canvas in play-session.tsx and replaces each scene's flat background fill with a subtle top-to-bottom gradient.
This commit is contained in:
1 parent
13bea64bb6
commit
65044fa828
6 files changed
+42
-26
No files matched your search
@@ -51,7 +51,7 @@ export const GameCanvas = forwardRef<
|
||||
mode: PhaserLib.Scale.FIT,
|
||||
autoCenter: PhaserLib.Scale.CENTER_BOTH,
|
||||
width: 960,
|
||||
height: 600,
|
||||
height: 720,
|
||||
},
|
||||
scene: [SceneClass],
|
||||
});
|
||||
@@ -75,5 +75,5 @@ export const GameCanvas = forwardRef<
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [templateType]);
|
||||
|
||||
return <div ref={containerRef} className="aspect-[8/5] w-full overflow-hidden rounded-lg bg-black" />;
|
||||
return <div ref={containerRef} className="aspect-[4/3] w-full overflow-hidden rounded-lg bg-black" />;
|
||||
});
|
||||
@@ -101,7 +101,7 @@ export function PlaySession({
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-4xl flex-1 px-1 py-4 sm:px-4 sm:py-6">
|
||||
<div className="relative">
|
||||
<div className="relative rounded-xl border border-border bg-gradient-to-b from-accent-soft/40 to-surface p-2 shadow-lg sm:p-3">
|
||||
<GameCanvas
|
||||
ref={gameCanvasRef}
|
||||
key={attempt}
|
||||
|
||||
@@ -30,7 +30,7 @@ const MONSTER_Y = 155;
|
||||
const HP_BAR_Y = 258;
|
||||
const HP_BAR_WIDTH = 500;
|
||||
const HEROES_START_Y = 308;
|
||||
const HERO_ROW_GAP = 28;
|
||||
const HERO_ROW_GAP = 38;
|
||||
|
||||
export class ClickerScene extends Phaser.Scene {
|
||||
private definition!: ClickerDefinition;
|
||||
@@ -80,7 +80,11 @@ export class ClickerScene extends Phaser.Scene {
|
||||
this.heroLevels = this.definition.heroes.map((_, i) => initialState?.heroLevels[i] ?? 0);
|
||||
this.finished = false;
|
||||
|
||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||
this.add
|
||||
.graphics()
|
||||
.fillGradientStyle(0x23264a, 0x23264a, COLORS.bg, COLORS.bg, 1)
|
||||
.fillRect(0, 0, 960, 720)
|
||||
.setDepth(-10);
|
||||
|
||||
this.levelText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#a3a8c6" });
|
||||
this.goldText = this.add
|
||||
@@ -117,11 +121,11 @@ export class ClickerScene extends Phaser.Scene {
|
||||
|
||||
this.definition.heroes.forEach((_, index) => {
|
||||
const y = HEROES_START_Y + index * HERO_ROW_GAP;
|
||||
const bg = this.add.rectangle(480, y, 780, 26, COLORS.heroRow).setStrokeStyle(1, 0x4f46e5).setInteractive({
|
||||
const bg = this.add.rectangle(480, y, 780, 34, COLORS.heroRow).setStrokeStyle(1, 0x4f46e5).setInteractive({
|
||||
useHandCursor: true,
|
||||
});
|
||||
const label = this.add
|
||||
.text(480, y, "", { fontFamily: "sans-serif", fontSize: "17px", color: "#eef0fb" })
|
||||
.text(480, y, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#eef0fb" })
|
||||
.setOrigin(0.5);
|
||||
bg.on("pointerdown", () => this.buyHero(index));
|
||||
this.heroRows.push({ bg, label });
|
||||
|
||||
@@ -102,7 +102,11 @@ export class MazeScene extends Phaser.Scene {
|
||||
this.finished = false;
|
||||
this.desiredDir = null;
|
||||
this.currentDir = null;
|
||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||
this.add
|
||||
.graphics()
|
||||
.fillGradientStyle(0x14162a, 0x14162a, COLORS.bg, COLORS.bg, 1)
|
||||
.fillRect(0, 0, 960, 720)
|
||||
.setDepth(-10);
|
||||
|
||||
const initialState = this.registry.get("initialState") as MazeProgress | undefined;
|
||||
this.collectedKeys = new Set(initialState?.collectedKeys ?? []);
|
||||
@@ -112,7 +116,7 @@ export class MazeScene extends Phaser.Scene {
|
||||
this.grid = this.definition.grid;
|
||||
this.rows = this.grid.length;
|
||||
this.cols = this.grid[0].length;
|
||||
this.cellSize = Math.max(10, Math.min(34, Math.floor(900 / this.cols), Math.floor(420 / this.rows)));
|
||||
this.cellSize = Math.max(10, Math.min(40, Math.floor(900 / this.cols), Math.floor(550 / this.rows)));
|
||||
this.offsetX = 480 - (this.cols * this.cellSize) / 2;
|
||||
this.offsetY = 130;
|
||||
|
||||
|
||||
@@ -84,7 +84,11 @@ export class QuizScene extends Phaser.Scene {
|
||||
this.usedQuestionKeys = new Set();
|
||||
this.finished = false;
|
||||
|
||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||
this.add
|
||||
.graphics()
|
||||
.fillGradientStyle(0x23264a, 0x23264a, COLORS.bg, COLORS.bg, 1)
|
||||
.fillRect(0, 0, 960, 720)
|
||||
.setDepth(-10);
|
||||
|
||||
this.levelText = this.add.text(30, 18, "", { fontFamily: "sans-serif", fontSize: "22px", color: "#a3a8c6" });
|
||||
this.prizeText = this.add
|
||||
@@ -113,16 +117,16 @@ export class QuizScene extends Phaser.Scene {
|
||||
this.walkAwayButton.on("pointerdown", () => this.walkAway());
|
||||
|
||||
const lifelineDefs: { kind: LifelineKind; x: number; label: string }[] = [
|
||||
{ kind: "fiftyFifty", x: 330, label: "50:50" },
|
||||
{ kind: "fiftyFifty", x: 300, label: "50:50" },
|
||||
{ kind: "audience", x: 480, label: "Зал" },
|
||||
{ kind: "phone", x: 630, label: "Звонок" },
|
||||
{ kind: "phone", x: 660, label: "Звонок" },
|
||||
];
|
||||
lifelineDefs.forEach(({ kind, x, label }) => {
|
||||
const bg = this.add
|
||||
.rectangle(x, 425, 130, 36, COLORS.lifeline)
|
||||
.rectangle(x, 520, 150, 46, COLORS.lifeline)
|
||||
.setStrokeStyle(1, 0x4f46e5)
|
||||
.setInteractive({ useHandCursor: true });
|
||||
this.add.text(x, 425, label, { fontFamily: "sans-serif", fontSize: "19px", color: "#eef0fb" }).setOrigin(0.5);
|
||||
this.add.text(x, 520, label, { fontFamily: "sans-serif", fontSize: "21px", color: "#eef0fb" }).setOrigin(0.5);
|
||||
bg.on("pointerdown", () => this.useLifeline(kind));
|
||||
this.lifelineButtons.set(kind, bg);
|
||||
});
|
||||
@@ -170,20 +174,20 @@ export class QuizScene extends Phaser.Scene {
|
||||
|
||||
private renderOptions() {
|
||||
this.clearOptions();
|
||||
const startY = 175;
|
||||
const gap = 58;
|
||||
const startY = 200;
|
||||
const gap = 76;
|
||||
|
||||
this.shuffledOptions.forEach((option, i) => {
|
||||
const y = startY + i * gap;
|
||||
const hidden = this.hiddenIndices.has(i);
|
||||
const bg = this.add.rectangle(480, y, 780, 48, hidden ? COLORS.optionHidden : COLORS.option).setStrokeStyle(
|
||||
const bg = this.add.rectangle(480, y, 780, 64, hidden ? COLORS.optionHidden : COLORS.option).setStrokeStyle(
|
||||
1,
|
||||
hidden ? 0x292d4a : 0x4f46e5,
|
||||
);
|
||||
const label = this.add
|
||||
.text(140, y, hidden ? "" : `${OPTION_LETTERS[i]}: ${option}`, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: "22px",
|
||||
fontSize: "24px",
|
||||
color: "#eef0fb",
|
||||
})
|
||||
.setOrigin(0, 0.5);
|
||||
@@ -283,10 +287,10 @@ export class QuizScene extends Phaser.Scene {
|
||||
|
||||
private showAudienceOverlay(shares: Map<number, number>) {
|
||||
this.clearOverlay();
|
||||
const bg = this.add.rectangle(480, 505, 780, 70, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
||||
const bg = this.add.rectangle(480, 615, 780, 90, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
||||
this.overlayObjects.push(bg);
|
||||
const title = this.add
|
||||
.text(480, 478, "Помощь зала", { fontFamily: "sans-serif", fontSize: "17px", color: "#a3a8c6" })
|
||||
.text(480, 585, "Помощь зала", { fontFamily: "sans-serif", fontSize: "17px", color: "#a3a8c6" })
|
||||
.setOrigin(0.5);
|
||||
this.overlayObjects.push(title);
|
||||
|
||||
@@ -296,7 +300,7 @@ export class QuizScene extends Phaser.Scene {
|
||||
entries.forEach(([optIndex, pct], i) => {
|
||||
const x = 480 - barAreaWidth / 2 + i * (barAreaWidth / entries.length) + barWidth / 2 + 8;
|
||||
const label = this.add
|
||||
.text(x, 495, `${OPTION_LETTERS[optIndex]}: ${Math.round(pct * 100)}%`, {
|
||||
.text(x, 605, `${OPTION_LETTERS[optIndex]}: ${Math.round(pct * 100)}%`, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: "18px",
|
||||
color: "#eef0fb",
|
||||
@@ -304,7 +308,7 @@ export class QuizScene extends Phaser.Scene {
|
||||
.setOrigin(0.5);
|
||||
this.overlayObjects.push(label);
|
||||
const bar = this.add
|
||||
.rectangle(x, 522, Math.max(6, barWidth * pct), 10, 0x818cf8)
|
||||
.rectangle(x, 635, Math.max(6, barWidth * pct), 10, 0x818cf8)
|
||||
.setOrigin(0.5);
|
||||
this.overlayObjects.push(bar);
|
||||
});
|
||||
@@ -312,10 +316,10 @@ export class QuizScene extends Phaser.Scene {
|
||||
|
||||
private showPhoneOverlay(suggestedIndex: number) {
|
||||
this.clearOverlay();
|
||||
const bg = this.add.rectangle(480, 500, 780, 60, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
||||
const bg = this.add.rectangle(480, 615, 780, 70, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
||||
this.overlayObjects.push(bg);
|
||||
const text = this.add
|
||||
.text(480, 500, `Друг на телефоне: «Я почти уверен, это ${OPTION_LETTERS[suggestedIndex]}»`, {
|
||||
.text(480, 615, `Друг на телефоне: «Я почти уверен, это ${OPTION_LETTERS[suggestedIndex]}»`, {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: "19px",
|
||||
color: "#eef0fb",
|
||||
|
||||
@@ -54,11 +54,15 @@ export class SnakeScene extends Phaser.Scene {
|
||||
this.onProgress = this.registry.get("onProgress");
|
||||
this.finished = false;
|
||||
|
||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||
this.add
|
||||
.graphics()
|
||||
.fillGradientStyle(0x14162a, 0x14162a, COLORS.bg, COLORS.bg, 1)
|
||||
.fillRect(0, 0, 960, 720)
|
||||
.setDepth(-10);
|
||||
|
||||
this.width = this.definition.width;
|
||||
this.height = this.definition.height;
|
||||
this.cellSize = Math.max(8, Math.min(30, Math.floor(920 / this.width), Math.floor(460 / this.height)));
|
||||
this.cellSize = Math.max(8, Math.min(36, Math.floor(920 / this.width), Math.floor(580 / this.height)));
|
||||
this.offsetX = 480 - (this.width * this.cellSize) / 2;
|
||||
this.offsetY = 110;
|
||||
|
||||
|
||||
Reference in new issue
Block a user