Mobile: bigger HUD text, wider canvas, on-screen D-pad for Maze/Snake
Games were unreadably small on phones (fixed-px HUD text scaled down by the Phaser FIT canvas) and Maze/Snake were unplayable on touch (keyboard-only input). Bumps HUD font sizes ~1.4x across all 4 scenes, tightens play-session's mobile padding so the canvas fills more of the screen, and adds a tappable D-pad wired through a new registry "touchDirection" event that feeds the same direction-buffering logic the keyboard already uses.
This commit is contained in:
1 parent
a61ef772db
commit
13bea64bb6
7 files changed
+104
-40
No files matched your search
@@ -1,29 +1,37 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef } from "react";
|
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
||||||
import type Phaser from "phaser";
|
import type Phaser from "phaser";
|
||||||
import type { TemplateType, GameDefinition, GameProgress, GameResult } from "@/lib/games/types";
|
import type { TemplateType, GameDefinition, GameProgress, GameResult } from "@/lib/games/types";
|
||||||
import type { ClickerAccountBonuses } from "@/lib/games/clicker";
|
import type { ClickerAccountBonuses } from "@/lib/games/clicker";
|
||||||
|
|
||||||
export function GameCanvas({
|
export type TouchDirection = "up" | "down" | "left" | "right";
|
||||||
templateType,
|
|
||||||
definition,
|
export type GameCanvasHandle = {
|
||||||
initialState,
|
sendDirection: (dir: TouchDirection) => void;
|
||||||
accountBonuses,
|
};
|
||||||
onFinish,
|
|
||||||
onProgress,
|
export const GameCanvas = forwardRef<
|
||||||
}: {
|
GameCanvasHandle,
|
||||||
|
{
|
||||||
templateType: TemplateType;
|
templateType: TemplateType;
|
||||||
definition: GameDefinition;
|
definition: GameDefinition;
|
||||||
initialState?: GameProgress;
|
initialState?: GameProgress;
|
||||||
accountBonuses?: ClickerAccountBonuses;
|
accountBonuses?: ClickerAccountBonuses;
|
||||||
onFinish?: (result: GameResult) => void;
|
onFinish?: (result: GameResult) => void;
|
||||||
onProgress?: (state: GameProgress) => void;
|
onProgress?: (state: GameProgress) => void;
|
||||||
}) {
|
}
|
||||||
|
>(function GameCanvas({ templateType, definition, initialState, accountBonuses, onFinish, onProgress }, ref) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const gameRef = useRef<Phaser.Game | null>(null);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
sendDirection: (dir) => {
|
||||||
|
gameRef.current?.registry.events.emit("touchDirection", dir);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let game: Phaser.Game | null = null;
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -35,7 +43,7 @@ export function GameCanvas({
|
|||||||
|
|
||||||
const SceneClass = sceneClassFor(templateType);
|
const SceneClass = sceneClassFor(templateType);
|
||||||
|
|
||||||
game = new PhaserLib.Game({
|
const game = new PhaserLib.Game({
|
||||||
type: PhaserLib.AUTO,
|
type: PhaserLib.AUTO,
|
||||||
parent: containerRef.current,
|
parent: containerRef.current,
|
||||||
backgroundColor: "#0a0b14",
|
backgroundColor: "#0a0b14",
|
||||||
@@ -47,6 +55,7 @@ export function GameCanvas({
|
|||||||
},
|
},
|
||||||
scene: [SceneClass],
|
scene: [SceneClass],
|
||||||
});
|
});
|
||||||
|
gameRef.current = game;
|
||||||
|
|
||||||
game.registry.set("definition", definition);
|
game.registry.set("definition", definition);
|
||||||
game.registry.set("initialState", initialState);
|
game.registry.set("initialState", initialState);
|
||||||
@@ -57,7 +66,8 @@ export function GameCanvas({
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
game?.destroy(true);
|
gameRef.current?.destroy(true);
|
||||||
|
gameRef.current = null;
|
||||||
};
|
};
|
||||||
// Intentionally only re-creating the game when the template changes —
|
// Intentionally only re-creating the game when the template changes —
|
||||||
// callers that need a fresh definition/result loaded should force a
|
// callers that need a fresh definition/result loaded should force a
|
||||||
@@ -66,4 +76,4 @@ export function GameCanvas({
|
|||||||
}, [templateType]);
|
}, [templateType]);
|
||||||
|
|
||||||
return <div ref={containerRef} className="aspect-[8/5] w-full overflow-hidden rounded-lg bg-black" />;
|
return <div ref={containerRef} className="aspect-[8/5] w-full overflow-hidden rounded-lg bg-black" />;
|
||||||
}
|
});
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
import { useEffect, useRef, useState, useCallback } from "react";
|
import { useEffect, useRef, useState, useCallback } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { RotateCcw, Trophy, XCircle, Save, Clock, Gem } from "lucide-react";
|
import { RotateCcw, Trophy, XCircle, Save, Clock, Gem } from "lucide-react";
|
||||||
import { GameCanvas } from "./game-canvas";
|
import { GameCanvas, type GameCanvasHandle } from "./game-canvas";
|
||||||
|
import { TouchDpad } from "./touch-dpad";
|
||||||
import { MANUAL_SAVE_COST } from "@/lib/wallet/economy";
|
import { MANUAL_SAVE_COST } from "@/lib/wallet/economy";
|
||||||
import type { TemplateType, GameDefinition, GameProgress, GameResult } from "@/lib/games/types";
|
import type { TemplateType, GameDefinition, GameProgress, GameResult } from "@/lib/games/types";
|
||||||
import type { ClickerAccountBonuses } from "@/lib/games/clicker";
|
import type { ClickerAccountBonuses } from "@/lib/games/clicker";
|
||||||
@@ -37,6 +38,7 @@ export function PlaySession({
|
|||||||
const [saveError, setSaveError] = useState<string | null>(null);
|
const [saveError, setSaveError] = useState<string | null>(null);
|
||||||
|
|
||||||
const latestStateRef = useRef<GameProgress | null>(initialState ?? null);
|
const latestStateRef = useRef<GameProgress | null>(initialState ?? null);
|
||||||
|
const gameCanvasRef = useRef<GameCanvasHandle>(null);
|
||||||
|
|
||||||
const handleProgress = useCallback((state: GameProgress) => {
|
const handleProgress = useCallback((state: GameProgress) => {
|
||||||
latestStateRef.current = state;
|
latestStateRef.current = state;
|
||||||
@@ -98,9 +100,10 @@ export function PlaySession({
|
|||||||
}, [result, gameId, templateType, canSave]);
|
}, [result, gameId, templateType, canSave]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-4xl flex-1 px-4 py-6 sm:px-6">
|
<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">
|
||||||
<GameCanvas
|
<GameCanvas
|
||||||
|
ref={gameCanvasRef}
|
||||||
key={attempt}
|
key={attempt}
|
||||||
templateType={templateType}
|
templateType={templateType}
|
||||||
definition={definition}
|
definition={definition}
|
||||||
@@ -146,6 +149,10 @@ export function PlaySession({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{(templateType === "maze" || templateType === "snake") && (
|
||||||
|
<TouchDpad onDirection={(dir) => gameCanvasRef.current?.sendDirection(dir)} />
|
||||||
|
)}
|
||||||
|
|
||||||
{canSave && (
|
{canSave && (
|
||||||
<div className="mt-3 flex flex-wrap items-center justify-between gap-3 text-sm">
|
<div className="mt-3 flex flex-wrap items-center justify-between gap-3 text-sm">
|
||||||
<div className="flex items-center gap-1.5 text-text-muted">
|
<div className="flex items-center gap-1.5 text-text-muted">
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp } from "lucide-react";
|
||||||
|
import type { TouchDirection } from "./game-canvas";
|
||||||
|
|
||||||
|
const BUTTON_CLASS =
|
||||||
|
"flex h-14 w-14 touch-manipulation items-center justify-center rounded-lg border border-border bg-surface text-text active:bg-surface-hover";
|
||||||
|
|
||||||
|
export function TouchDpad({ onDirection }: { onDirection: (dir: TouchDirection) => void }) {
|
||||||
|
const press = (dir: TouchDirection) => (e: React.PointerEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onDirection(dir);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-3 grid w-fit grid-cols-3 grid-rows-3 gap-1.5 select-none">
|
||||||
|
<div />
|
||||||
|
<button type="button" aria-label="Вверх" onPointerDown={press("up")} className={`${BUTTON_CLASS} col-start-2`}>
|
||||||
|
<ArrowUp size={22} />
|
||||||
|
</button>
|
||||||
|
<div />
|
||||||
|
|
||||||
|
<button type="button" aria-label="Влево" onPointerDown={press("left")} className={BUTTON_CLASS}>
|
||||||
|
<ArrowLeft size={22} />
|
||||||
|
</button>
|
||||||
|
<div />
|
||||||
|
<button type="button" aria-label="Вправо" onPointerDown={press("right")} className={BUTTON_CLASS}>
|
||||||
|
<ArrowRight size={22} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div />
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Вниз"
|
||||||
|
onPointerDown={press("down")}
|
||||||
|
className={`${BUTTON_CLASS} col-start-2`}
|
||||||
|
>
|
||||||
|
<ArrowDown size={22} />
|
||||||
|
</button>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -82,12 +82,12 @@ export class ClickerScene extends Phaser.Scene {
|
|||||||
|
|
||||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||||
|
|
||||||
this.levelText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "15px", color: "#a3a8c6" });
|
this.levelText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#a3a8c6" });
|
||||||
this.goldText = this.add
|
this.goldText = this.add
|
||||||
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "16px", color: "#fbbf24", fontStyle: "bold" })
|
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "22px", color: "#fbbf24", fontStyle: "bold" })
|
||||||
.setOrigin(1, 0);
|
.setOrigin(1, 0);
|
||||||
this.dpsText = this.add
|
this.dpsText = this.add
|
||||||
.text(940, 38, "", { fontFamily: "sans-serif", fontSize: "13px", color: "#a3a8c6" })
|
.text(940, 38, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#a3a8c6" })
|
||||||
.setOrigin(1, 0);
|
.setOrigin(1, 0);
|
||||||
|
|
||||||
this.flashCircle = this.add.circle(MONSTER_X, MONSTER_Y, 95, COLORS.flash, 0).setDepth(1);
|
this.flashCircle = this.add.circle(MONSTER_X, MONSTER_Y, 95, COLORS.flash, 0).setDepth(1);
|
||||||
@@ -100,13 +100,13 @@ export class ClickerScene extends Phaser.Scene {
|
|||||||
this.monsterEmojiText.on("pointerdown", (pointer: Phaser.Input.Pointer) => this.handleClick(pointer));
|
this.monsterEmojiText.on("pointerdown", (pointer: Phaser.Input.Pointer) => this.handleClick(pointer));
|
||||||
|
|
||||||
this.monsterNameText = this.add
|
this.monsterNameText = this.add
|
||||||
.text(MONSTER_X, 228, "", { fontFamily: "sans-serif", fontSize: "13px", color: "#818cf8" })
|
.text(MONSTER_X, 228, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#818cf8" })
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
|
|
||||||
this.hpBarBg = this.add.rectangle(MONSTER_X, HP_BAR_Y, HP_BAR_WIDTH, 18, COLORS.hpBarBg);
|
this.hpBarBg = this.add.rectangle(MONSTER_X, HP_BAR_Y, HP_BAR_WIDTH, 18, COLORS.hpBarBg);
|
||||||
this.hpBarFill = this.add.rectangle(MONSTER_X - HP_BAR_WIDTH / 2, HP_BAR_Y, HP_BAR_WIDTH, 18, COLORS.hpHigh).setOrigin(0, 0.5);
|
this.hpBarFill = this.add.rectangle(MONSTER_X - HP_BAR_WIDTH / 2, HP_BAR_Y, HP_BAR_WIDTH, 18, COLORS.hpHigh).setOrigin(0, 0.5);
|
||||||
this.hpValueText = this.add
|
this.hpValueText = this.add
|
||||||
.text(MONSTER_X, HP_BAR_Y, "", { fontFamily: "sans-serif", fontSize: "12px", color: "#eef0fb" })
|
.text(MONSTER_X, HP_BAR_Y, "", { fontFamily: "sans-serif", fontSize: "17px", color: "#eef0fb" })
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
|
|
||||||
this.bossBarBg = this.add.rectangle(MONSTER_X, 283, HP_BAR_WIDTH, 8, COLORS.bossTimerBg).setVisible(false);
|
this.bossBarBg = this.add.rectangle(MONSTER_X, 283, HP_BAR_WIDTH, 8, COLORS.bossTimerBg).setVisible(false);
|
||||||
@@ -117,11 +117,11 @@ export class ClickerScene extends Phaser.Scene {
|
|||||||
|
|
||||||
this.definition.heroes.forEach((_, index) => {
|
this.definition.heroes.forEach((_, index) => {
|
||||||
const y = HEROES_START_Y + index * HERO_ROW_GAP;
|
const y = HEROES_START_Y + index * HERO_ROW_GAP;
|
||||||
const bg = this.add.rectangle(480, y, 780, 24, COLORS.heroRow).setStrokeStyle(1, 0x4f46e5).setInteractive({
|
const bg = this.add.rectangle(480, y, 780, 26, COLORS.heroRow).setStrokeStyle(1, 0x4f46e5).setInteractive({
|
||||||
useHandCursor: true,
|
useHandCursor: true,
|
||||||
});
|
});
|
||||||
const label = this.add
|
const label = this.add
|
||||||
.text(480, y, "", { fontFamily: "sans-serif", fontSize: "12px", color: "#eef0fb" })
|
.text(480, y, "", { fontFamily: "sans-serif", fontSize: "17px", color: "#eef0fb" })
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
bg.on("pointerdown", () => this.buyHero(index));
|
bg.on("pointerdown", () => this.buyHero(index));
|
||||||
this.heroRows.push({ bg, label });
|
this.heroRows.push({ bg, label });
|
||||||
@@ -244,7 +244,7 @@ export class ClickerScene extends Phaser.Scene {
|
|||||||
const dmgText = this.add
|
const dmgText = this.add
|
||||||
.text(x, y - 40, `-${Math.round(amount)}`, {
|
.text(x, y - 40, `-${Math.round(amount)}`, {
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: "18px",
|
fontSize: "24px",
|
||||||
color: "#f87171",
|
color: "#f87171",
|
||||||
fontStyle: "bold",
|
fontStyle: "bold",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -165,10 +165,10 @@ export class MazeScene extends Phaser.Scene {
|
|||||||
this.player = this.add.circle(playerPx.x, playerPx.y, PLAYER_RADIUS, COLORS.player).setDepth(3);
|
this.player = this.add.circle(playerPx.x, playerPx.y, PLAYER_RADIUS, COLORS.player).setDepth(3);
|
||||||
this.tweens.add({ targets: this.player, scale: 0.82, duration: 140, yoyo: true, repeat: -1 });
|
this.tweens.add({ targets: this.player, scale: 0.82, duration: 140, yoyo: true, repeat: -1 });
|
||||||
|
|
||||||
this.livesText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "15px", color: "#eef0fb" });
|
this.livesText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#eef0fb" });
|
||||||
this.scoreText = this.add.text(20, 38, "", { fontFamily: "sans-serif", fontSize: "13px", color: "#a3a8c6" });
|
this.scoreText = this.add.text(20, 38, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#a3a8c6" });
|
||||||
this.dotsText = this.add
|
this.dotsText = this.add
|
||||||
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "15px", color: "#eef0fb" })
|
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#eef0fb" })
|
||||||
.setOrigin(1, 0);
|
.setOrigin(1, 0);
|
||||||
|
|
||||||
this.frightenBarBg = this.add.rectangle(480, 95, 500, 8, 0x292d4a).setVisible(false);
|
this.frightenBarBg = this.add.rectangle(480, 95, 500, 8, 0x292d4a).setVisible(false);
|
||||||
@@ -180,7 +180,7 @@ export class MazeScene extends Phaser.Scene {
|
|||||||
if (this.definition.timeLimitSec > 0) {
|
if (this.definition.timeLimitSec > 0) {
|
||||||
this.remainingMs = initialState?.remainingMs ?? this.definition.timeLimitSec * 1000;
|
this.remainingMs = initialState?.remainingMs ?? this.definition.timeLimitSec * 1000;
|
||||||
this.timerText = this.add
|
this.timerText = this.add
|
||||||
.text(480, 15, "", { fontFamily: "sans-serif", fontSize: "13px", color: "#a3a8c6" })
|
.text(480, 15, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#a3a8c6" })
|
||||||
.setOrigin(0.5, 0);
|
.setOrigin(0.5, 0);
|
||||||
this.time.addEvent({
|
this.time.addEvent({
|
||||||
delay: 100,
|
delay: 100,
|
||||||
@@ -201,6 +201,9 @@ export class MazeScene extends Phaser.Scene {
|
|||||||
this.input.keyboard!.on("keydown-RIGHT", () => (this.desiredDir = DIRS.right));
|
this.input.keyboard!.on("keydown-RIGHT", () => (this.desiredDir = DIRS.right));
|
||||||
this.input.keyboard!.on("keydown-UP", () => (this.desiredDir = DIRS.up));
|
this.input.keyboard!.on("keydown-UP", () => (this.desiredDir = DIRS.up));
|
||||||
this.input.keyboard!.on("keydown-DOWN", () => (this.desiredDir = DIRS.down));
|
this.input.keyboard!.on("keydown-DOWN", () => (this.desiredDir = DIRS.down));
|
||||||
|
this.registry.events.on("touchDirection", (dir: "up" | "down" | "left" | "right") => {
|
||||||
|
this.desiredDir = DIRS[dir];
|
||||||
|
});
|
||||||
|
|
||||||
this.time.addEvent({ delay: PLAYER_STEP_MS, loop: true, callback: () => this.playerTick() });
|
this.time.addEvent({ delay: PLAYER_STEP_MS, loop: true, callback: () => this.playerTick() });
|
||||||
this.time.addEvent({ delay: GHOST_STEP_MS, loop: true, callback: () => this.ghostTick() });
|
this.time.addEvent({ delay: GHOST_STEP_MS, loop: true, callback: () => this.ghostTick() });
|
||||||
|
|||||||
@@ -86,17 +86,17 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
|
|
||||||
this.cameras.main.setBackgroundColor(COLORS.bg);
|
this.cameras.main.setBackgroundColor(COLORS.bg);
|
||||||
|
|
||||||
this.levelText = this.add.text(30, 18, "", { fontFamily: "sans-serif", fontSize: "16px", color: "#a3a8c6" });
|
this.levelText = this.add.text(30, 18, "", { fontFamily: "sans-serif", fontSize: "22px", color: "#a3a8c6" });
|
||||||
this.prizeText = this.add
|
this.prizeText = this.add
|
||||||
.text(930, 18, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#eef0fb", fontStyle: "bold" })
|
.text(930, 18, "", { fontFamily: "sans-serif", fontSize: "24px", color: "#eef0fb", fontStyle: "bold" })
|
||||||
.setOrigin(1, 0);
|
.setOrigin(1, 0);
|
||||||
this.categoryText = this.add
|
this.categoryText = this.add
|
||||||
.text(480, 18, "", { fontFamily: "sans-serif", fontSize: "13px", color: "#818cf8" })
|
.text(480, 18, "", { fontFamily: "sans-serif", fontSize: "18px", color: "#818cf8" })
|
||||||
.setOrigin(0.5, 0);
|
.setOrigin(0.5, 0);
|
||||||
this.questionText = this.add
|
this.questionText = this.add
|
||||||
.text(480, 55, "", {
|
.text(480, 55, "", {
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: "21px",
|
fontSize: "28px",
|
||||||
color: "#eef0fb",
|
color: "#eef0fb",
|
||||||
align: "center",
|
align: "center",
|
||||||
wordWrap: { width: 840 },
|
wordWrap: { width: 840 },
|
||||||
@@ -108,7 +108,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
.setStrokeStyle(1, 0x4f46e5)
|
.setStrokeStyle(1, 0x4f46e5)
|
||||||
.setInteractive({ useHandCursor: true });
|
.setInteractive({ useHandCursor: true });
|
||||||
this.walkAwayLabel = this.add
|
this.walkAwayLabel = this.add
|
||||||
.text(880, 60, "Забрать", { fontFamily: "sans-serif", fontSize: "13px", color: "#eef0fb" })
|
.text(880, 60, "Забрать", { fontFamily: "sans-serif", fontSize: "18px", color: "#eef0fb" })
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
this.walkAwayButton.on("pointerdown", () => this.walkAway());
|
this.walkAwayButton.on("pointerdown", () => this.walkAway());
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
.rectangle(x, 425, 130, 36, COLORS.lifeline)
|
.rectangle(x, 425, 130, 36, COLORS.lifeline)
|
||||||
.setStrokeStyle(1, 0x4f46e5)
|
.setStrokeStyle(1, 0x4f46e5)
|
||||||
.setInteractive({ useHandCursor: true });
|
.setInteractive({ useHandCursor: true });
|
||||||
this.add.text(x, 425, label, { fontFamily: "sans-serif", fontSize: "14px", color: "#eef0fb" }).setOrigin(0.5);
|
this.add.text(x, 425, label, { fontFamily: "sans-serif", fontSize: "19px", color: "#eef0fb" }).setOrigin(0.5);
|
||||||
bg.on("pointerdown", () => this.useLifeline(kind));
|
bg.on("pointerdown", () => this.useLifeline(kind));
|
||||||
this.lifelineButtons.set(kind, bg);
|
this.lifelineButtons.set(kind, bg);
|
||||||
});
|
});
|
||||||
@@ -183,7 +183,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
const label = this.add
|
const label = this.add
|
||||||
.text(140, y, hidden ? "" : `${OPTION_LETTERS[i]}: ${option}`, {
|
.text(140, y, hidden ? "" : `${OPTION_LETTERS[i]}: ${option}`, {
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: "16px",
|
fontSize: "22px",
|
||||||
color: "#eef0fb",
|
color: "#eef0fb",
|
||||||
})
|
})
|
||||||
.setOrigin(0, 0.5);
|
.setOrigin(0, 0.5);
|
||||||
@@ -286,7 +286,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
const bg = this.add.rectangle(480, 505, 780, 70, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
const bg = this.add.rectangle(480, 505, 780, 70, COLORS.overlayBg).setStrokeStyle(1, 0x292d4a);
|
||||||
this.overlayObjects.push(bg);
|
this.overlayObjects.push(bg);
|
||||||
const title = this.add
|
const title = this.add
|
||||||
.text(480, 478, "Помощь зала", { fontFamily: "sans-serif", fontSize: "12px", color: "#a3a8c6" })
|
.text(480, 478, "Помощь зала", { fontFamily: "sans-serif", fontSize: "17px", color: "#a3a8c6" })
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
this.overlayObjects.push(title);
|
this.overlayObjects.push(title);
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
const label = this.add
|
const label = this.add
|
||||||
.text(x, 495, `${OPTION_LETTERS[optIndex]}: ${Math.round(pct * 100)}%`, {
|
.text(x, 495, `${OPTION_LETTERS[optIndex]}: ${Math.round(pct * 100)}%`, {
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: "13px",
|
fontSize: "18px",
|
||||||
color: "#eef0fb",
|
color: "#eef0fb",
|
||||||
})
|
})
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
@@ -317,7 +317,7 @@ export class QuizScene extends Phaser.Scene {
|
|||||||
const text = this.add
|
const text = this.add
|
||||||
.text(480, 500, `Друг на телефоне: «Я почти уверен, это ${OPTION_LETTERS[suggestedIndex]}»`, {
|
.text(480, 500, `Друг на телефоне: «Я почти уверен, это ${OPTION_LETTERS[suggestedIndex]}»`, {
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: "14px",
|
fontSize: "19px",
|
||||||
color: "#eef0fb",
|
color: "#eef0fb",
|
||||||
align: "center",
|
align: "center",
|
||||||
wordWrap: { width: 720 },
|
wordWrap: { width: 720 },
|
||||||
|
|||||||
@@ -95,15 +95,16 @@ export class SnakeScene extends Phaser.Scene {
|
|||||||
this.foodShape = this.add.circle(0, 0, this.cellSize * 0.4, COLORS.food);
|
this.foodShape = this.add.circle(0, 0, this.cellSize * 0.4, COLORS.food);
|
||||||
this.updateFoodPosition();
|
this.updateFoodPosition();
|
||||||
|
|
||||||
this.scoreText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "15px", color: "#eef0fb" });
|
this.scoreText = this.add.text(20, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#eef0fb" });
|
||||||
this.lengthText = this.add
|
this.lengthText = this.add
|
||||||
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "15px", color: "#eef0fb" })
|
.text(940, 15, "", { fontFamily: "sans-serif", fontSize: "20px", color: "#eef0fb" })
|
||||||
.setOrigin(1, 0);
|
.setOrigin(1, 0);
|
||||||
|
|
||||||
this.input.keyboard!.on("keydown-LEFT", () => this.setDesiredDirection("left"));
|
this.input.keyboard!.on("keydown-LEFT", () => this.setDesiredDirection("left"));
|
||||||
this.input.keyboard!.on("keydown-RIGHT", () => this.setDesiredDirection("right"));
|
this.input.keyboard!.on("keydown-RIGHT", () => this.setDesiredDirection("right"));
|
||||||
this.input.keyboard!.on("keydown-UP", () => this.setDesiredDirection("up"));
|
this.input.keyboard!.on("keydown-UP", () => this.setDesiredDirection("up"));
|
||||||
this.input.keyboard!.on("keydown-DOWN", () => this.setDesiredDirection("down"));
|
this.input.keyboard!.on("keydown-DOWN", () => this.setDesiredDirection("down"));
|
||||||
|
this.registry.events.on("touchDirection", (dir: Direction) => this.setDesiredDirection(dir));
|
||||||
|
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
this.reportProgress();
|
this.reportProgress();
|
||||||
|
|||||||
Reference in new issue
Block a user