refact round

This commit is contained in:
2026-05-15 21:45:18 +02:00
parent 5b0a989712
commit 737f16f38b
18 changed files with 168 additions and 232 deletions

View File

@@ -1,5 +1,20 @@
import Phaser from "phaser"; import Phaser from "phaser";
type PhysicsBodyHolder =
| Phaser.Types.Physics.Arcade.GameObjectWithBody
| Phaser.Physics.Arcade.Body
| Phaser.Physics.Arcade.StaticBody
| Phaser.Tilemaps.Tile;
function getBody(target: PhysicsBodyHolder): Phaser.Physics.Arcade.Body | Phaser.Physics.Arcade.StaticBody {
if (target instanceof Phaser.Physics.Arcade.Body || target instanceof Phaser.Physics.Arcade.StaticBody) {
return target;
}
return (target as Phaser.Types.Physics.Arcade.GameObjectWithBody).body as
| Phaser.Physics.Arcade.Body
| Phaser.Physics.Arcade.StaticBody;
}
export class Platform extends Phaser.GameObjects.TileSprite { export class Platform extends Phaser.GameObjects.TileSprite {
static readonly TEXTURE_KEY = "platform"; static readonly TEXTURE_KEY = "platform";
@@ -12,15 +27,12 @@ export class Platform extends Phaser.GameObjects.TileSprite {
} }
// Phaser collider processCallback: only collide when the mover is descending onto the top. // Phaser collider processCallback: only collide when the mover is descending onto the top.
static canLand( static canLand: Phaser.Types.Physics.Arcade.ArcadePhysicsCallback = (mover, platform) => {
mover: Phaser.Types.Physics.Arcade.GameObjectWithBody, const moverBody = getBody(mover) as Phaser.Physics.Arcade.Body;
platform: Phaser.Types.Physics.Arcade.GameObjectWithBody, const platBody = getBody(platform) as Phaser.Physics.Arcade.StaticBody;
): boolean {
const moverBody = mover.body as Phaser.Physics.Arcade.Body;
const platBody = platform.body as Phaser.Physics.Arcade.StaticBody;
return ( return (
moverBody.velocity.y >= 0 && moverBody.velocity.y >= 0 &&
moverBody.bottom - moverBody.deltaY() <= platBody.top moverBody.bottom - moverBody.deltaY() <= platBody.top
); );
} };
} }

View File

@@ -0,0 +1,11 @@
import Phaser from "phaser";
export abstract class ObstacleSpikeBase extends Phaser.GameObjects.Image {
declare body: Phaser.Physics.Arcade.StaticBody;
constructor(scene: Phaser.Scene, x: number, y: number, textureKey: string) {
super(scene, x, y, textureKey);
scene.add.existing(this);
scene.physics.add.existing(this, true);
}
}

View File

@@ -1,15 +1,12 @@
import Phaser from "phaser"; import Phaser from "phaser";
import { ObstacleSpikeBase } from "./ObstacleSpikeBase";
export class ObstacleSpikeNormal extends Phaser.GameObjects.Image { export class ObstacleSpikeNormal extends ObstacleSpikeBase {
static readonly TEXTURE_KEY = "spike-normal"; static readonly TEXTURE_KEY = "spike-normal";
static readonly WIDTH = 40; static readonly WIDTH = 40;
static readonly HEIGHT = 20; static readonly HEIGHT = 20;
declare body: Phaser.Physics.Arcade.StaticBody;
constructor(scene: Phaser.Scene, x: number, y: number) { constructor(scene: Phaser.Scene, x: number, y: number) {
super(scene, x, y, ObstacleSpikeNormal.TEXTURE_KEY); super(scene, x, y, ObstacleSpikeNormal.TEXTURE_KEY);
scene.add.existing(this);
scene.physics.add.existing(this, true);
} }
} }

View File

@@ -1,23 +1,20 @@
import Phaser from "phaser"; import Phaser from "phaser";
import { ObstacleSpikeBase } from "./ObstacleSpikeBase";
export class ObstacleSpikeTricky extends Phaser.GameObjects.Image { export class ObstacleSpikeTricky extends ObstacleSpikeBase {
static readonly TEXTURE_KEY = "spike-tricky"; static readonly TEXTURE_KEY = "spike-tricky";
static readonly WIDTH = 40; static readonly WIDTH = 40;
static readonly HEIGHT = 20; static readonly HEIGHT = 20;
static readonly TRIGGER_DISTANCE = 55; static readonly TRIGGER_DISTANCE = 55;
static readonly DISPLACEMENT = 100; static readonly DISPLACEMENT = 100;
declare body: Phaser.Physics.Arcade.StaticBody;
private moved = false; private moved = false;
constructor(scene: Phaser.Scene, x: number, y: number) { constructor(scene: Phaser.Scene, x: number, y: number) {
super(scene, x, y, ObstacleSpikeTricky.TEXTURE_KEY); super(scene, x, y, ObstacleSpikeTricky.TEXTURE_KEY);
scene.add.existing(this);
scene.physics.add.existing(this, true);
} }
react(playerX: number): void { react(playerX: number, _playerY: number): void {
if (this.moved) return; if (this.moved) return;
const dx = this.x - playerX; const dx = this.x - playerX;
if (Math.abs(dx) < ObstacleSpikeTricky.TRIGGER_DISTANCE) { if (Math.abs(dx) < ObstacleSpikeTricky.TRIGGER_DISTANCE) {

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level01 = defineLevel("Spike Hop", [ export const level01 = defineLevel("Spike Hop", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E........^........P", ".E........^........P",
"####################", "####################",
"####################", "####################",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level02 = defineLevel("Trap Bridge", [ export const level02 = defineLevel("Trap Bridge", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E.................P", ".E.................P",
"#######~~~##########", "#######~~~##########",
"#######~~~##########", "#######~~~##########",

View File

@@ -1,13 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level03 = defineLevel("Trickster Stairs", [ export const level03 = defineLevel("Trickster Stairs", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E..................", ".E..................",
"#####...............", "#####...............",
"....#####...........", "....#####...........",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level04 = defineLevel("Spike Field", [ export const level04 = defineLevel("Spike Field", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E....^...^...^....P", ".E....^...^...^....P",
"####################", "####################",
"####################", "####################",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level05 = defineLevel("Pit Crossing", [ export const level05 = defineLevel("Pit Crossing", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E.................P", ".E.................P",
"####...######...####", "####...######...####",
"####^^^######^^^####", "####^^^######^^^####",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level06 = defineLevel("Trickster", [ export const level06 = defineLevel("Trickster", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E..........T......P", ".E..........T......P",
"####################", "####################",
"####################", "####################",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level07 = defineLevel("Bridge Hopping", [ export const level07 = defineLevel("Bridge Hopping", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E.................P", ".E.................P",
"####...#####...#####", "####...#####...#####",
"####...#####...#####", "####...#####...#####",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level08 = defineLevel("Mixed Hazards", [ export const level08 = defineLevel("Mixed Hazards", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E..^......T....^..P", ".E..^......T....^..P",
"####################", "####################",
"####################", "####################",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level09 = defineLevel("Vanishing Bridges", [ export const level09 = defineLevel("Vanishing Bridges", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E.................P", ".E.................P",
"####~~~####~~~######", "####~~~####~~~######",
"####~~~####~~~######", "####~~~####~~~######",

View File

@@ -1,18 +1,6 @@
import { defineLevel } from "../lib/levelTypes"; import { defineLevel } from "../lib/levelTypes";
export const level10 = defineLevel("Final Gauntlet", [ export const level10 = defineLevel("Final Gauntlet", [
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
"....................",
".E......T..........P", ".E......T..........P",
"####...####~~~######", "####...####~~~######",
"####^^^####...######", "####^^^####...######",

View File

@@ -18,18 +18,29 @@ export interface LoadedLevel {
trickySpikes: ObstacleSpikeTricky[]; trickySpikes: ObstacleSpikeTricky[];
} }
interface Cell { const cellCenterX = (col: number): number => col * TILE_SIZE + TILE_SIZE / 2;
row: number; const cellBottomY = (row: number, entityHeight: number): number =>
col: number; (row + 1) * TILE_SIZE - entityHeight / 2;
}
export class LevelLoader { export class LevelLoader {
constructor(private readonly scene: Phaser.Scene) {} constructor(private readonly scene: Phaser.Scene) {}
load(matrix: LevelMatrix): LoadedLevel { load(matrix: LevelMatrix): LoadedLevel {
return { return {
player: this.buildPlayer(matrix), player: this.buildSingleton(
exit: this.buildExit(matrix), matrix,
TileType.Player,
Player.SIZE,
(x, y) => new Player(this.scene, x, y),
"Player",
),
exit: this.buildSingleton(
matrix,
TileType.Exit,
Exit.HEIGHT,
(x, y) => new Exit(this.scene, x, y),
"Exit",
),
platforms: this.buildHorizontalRuns( platforms: this.buildHorizontalRuns(
matrix, matrix,
TileType.Platform, TileType.Platform,
@@ -40,16 +51,18 @@ export class LevelLoader {
TileType.DisappearingPlatform, TileType.DisappearingPlatform,
(x, y, w, h) => new ObstaclePlatformDisappearing(this.scene, x, y, w, h), (x, y, w, h) => new ObstaclePlatformDisappearing(this.scene, x, y, w, h),
), ),
spikes: this.buildSingleCells(matrix, TileType.Spike, (col, row) => { spikes: this.buildSingleCells(
const x = col * TILE_SIZE + TILE_SIZE / 2; matrix,
const y = (row + 1) * TILE_SIZE - ObstacleSpikeNormal.HEIGHT / 2; TileType.Spike,
return new ObstacleSpikeNormal(this.scene, x, y); ObstacleSpikeNormal.HEIGHT,
}), (x, y) => new ObstacleSpikeNormal(this.scene, x, y),
trickySpikes: this.buildSingleCells(matrix, TileType.TrickySpike, (col, row) => { ),
const x = col * TILE_SIZE + TILE_SIZE / 2; trickySpikes: this.buildSingleCells(
const y = (row + 1) * TILE_SIZE - ObstacleSpikeTricky.HEIGHT / 2; matrix,
return new ObstacleSpikeTricky(this.scene, x, y); TileType.TrickySpike,
}), ObstacleSpikeTricky.HEIGHT,
(x, y) => new ObstacleSpikeTricky(this.scene, x, y),
),
}; };
} }
@@ -81,39 +94,34 @@ export class LevelLoader {
private buildSingleCells<T>( private buildSingleCells<T>(
matrix: LevelMatrix, matrix: LevelMatrix,
tileType: TileType, tileType: TileType,
factory: (col: number, row: number) => T, entityHeight: number,
factory: (x: number, y: number) => T,
): T[] { ): T[] {
const result: T[] = []; const result: T[] = [];
for (let row = 0; row < matrix.length; row++) { for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) { for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col] === tileType) result.push(factory(col, row)); if (matrix[row][col] === tileType) {
result.push(factory(cellCenterX(col), cellBottomY(row, entityHeight)));
}
} }
} }
return result; return result;
} }
private buildPlayer(matrix: LevelMatrix): Player { private buildSingleton<T>(
const cell = this.findTile(matrix, TileType.Player); matrix: LevelMatrix,
if (!cell) throw new Error("Level matrix has no Player tile"); tileType: TileType,
const x = cell.col * TILE_SIZE + TILE_SIZE / 2; entityHeight: number,
const y = (cell.row + 1) * TILE_SIZE - Player.SIZE / 2; factory: (x: number, y: number) => T,
return new Player(this.scene, x, y); label: string,
} ): T {
private buildExit(matrix: LevelMatrix): Exit {
const cell = this.findTile(matrix, TileType.Exit);
if (!cell) throw new Error("Level matrix has no Exit tile");
const x = cell.col * TILE_SIZE + TILE_SIZE / 2;
const y = (cell.row + 1) * TILE_SIZE - Exit.HEIGHT / 2;
return new Exit(this.scene, x, y);
}
private findTile(matrix: LevelMatrix, tile: TileType): Cell | null {
for (let row = 0; row < matrix.length; row++) { for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) { for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col] === tile) return { row, col }; if (matrix[row][col] === tileType) {
return factory(cellCenterX(col), cellBottomY(row, entityHeight));
} }
} }
return null; }
throw new Error(`Level matrix has no ${label} tile`);
} }
} }

View File

@@ -29,6 +29,8 @@ const CHAR_TO_TILE: Record<string, TileType> = {
"T": TileType.TrickySpike, "T": TileType.TrickySpike,
}; };
const EMPTY_ROW = ".".repeat(LEVEL_COLS);
function parseLevel(rows: string[]): LevelMatrix { function parseLevel(rows: string[]): LevelMatrix {
return rows.map((row, rowIdx) => return rows.map((row, rowIdx) =>
[...row].map((c, colIdx) => { [...row].map((c, colIdx) => {
@@ -42,5 +44,12 @@ function parseLevel(rows: string[]): LevelMatrix {
} }
export function defineLevel(name: string, rows: string[]): LevelDef { export function defineLevel(name: string, rows: string[]): LevelDef {
return { name, matrix: parseLevel(rows) }; if (rows.length > LEVEL_ROWS) {
throw new Error(
`Level "${name}" has ${rows.length} rows, max is ${LEVEL_ROWS}`,
);
}
const padCount = LEVEL_ROWS - rows.length;
const padded = padCount > 0 ? [...Array(padCount).fill(EMPTY_ROW), ...rows] : rows;
return { name, matrix: parseLevel(padded) };
} }

View File

@@ -7,26 +7,69 @@ import {
ObstacleSpikeTricky, ObstacleSpikeTricky,
} from "../entities/obstacles"; } from "../entities/obstacles";
interface SpriteAsset {
key: string;
path: string;
width: number;
height: number;
}
const SPRITE_ASSETS: SpriteAsset[] = [
{ key: Player.TEXTURE_KEY, path: "/sprites/player.svg", width: Player.SIZE, height: Player.SIZE },
{ key: Exit.TEXTURE_KEY, path: "/sprites/exit.svg", width: Exit.WIDTH, height: Exit.HEIGHT },
{ key: Platform.TEXTURE_KEY, path: "/sprites/platform.svg", width: 40, height: 40 },
{
key: ObstacleSpikeNormal.TEXTURE_KEY,
path: "/sprites/spike-normal.svg",
width: ObstacleSpikeNormal.WIDTH,
height: ObstacleSpikeNormal.HEIGHT,
},
{
key: ObstacleSpikeTricky.TEXTURE_KEY,
path: "/sprites/spike-tricky.svg",
width: ObstacleSpikeTricky.WIDTH,
height: ObstacleSpikeTricky.HEIGHT,
},
];
const TITLE_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
fontFamily: "Arial Black, Arial",
fontSize: "78px",
color: "#ffd700",
fontStyle: "bold",
stroke: "#7a5500",
strokeThickness: 6,
};
const SUBTITLE_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
fontFamily: "Arial",
fontSize: "18px",
color: "#aaaaaa",
fontStyle: "italic",
};
const PROMPT_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
fontFamily: "Arial",
fontSize: "26px",
color: "#ffffff",
fontStyle: "bold",
};
const HINT_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
fontFamily: "Arial",
fontSize: "14px",
color: "#888888",
};
export class BootScene extends Phaser.Scene { export class BootScene extends Phaser.Scene {
constructor() { constructor() {
super({ key: "BootScene" }); super({ key: "BootScene" });
} }
preload(): void { preload(): void {
this.load.svg(Player.TEXTURE_KEY, "/sprites/player.svg", { width: 32, height: 32 }); for (const asset of SPRITE_ASSETS) {
this.load.svg(Exit.TEXTURE_KEY, "/sprites/exit.svg", { this.load.svg(asset.key, asset.path, { width: asset.width, height: asset.height });
width: Exit.WIDTH, }
height: Exit.HEIGHT,
});
this.load.svg(Platform.TEXTURE_KEY, "/sprites/platform.svg", { width: 40, height: 40 });
this.load.svg(ObstacleSpikeNormal.TEXTURE_KEY, "/sprites/spike-normal.svg", {
width: ObstacleSpikeNormal.WIDTH,
height: ObstacleSpikeNormal.HEIGHT,
});
this.load.svg(ObstacleSpikeTricky.TEXTURE_KEY, "/sprites/spike-tricky.svg", {
width: ObstacleSpikeTricky.WIDTH,
height: ObstacleSpikeTricky.HEIGHT,
});
} }
create(): void { create(): void {
@@ -38,48 +81,16 @@ export class BootScene extends Phaser.Scene {
this.add.tileSprite(cx, h - 20, w, 40, Platform.TEXTURE_KEY); this.add.tileSprite(cx, h - 20, w, 40, Platform.TEXTURE_KEY);
this.add this.add.text(cx, 130, "TRICKSTER", TITLE_STYLE).setOrigin(0.5);
.text(cx, 130, "TRICKSTER", { this.add.text(cx, 200, "TILES", TITLE_STYLE).setOrigin(0.5);
fontFamily: "Arial Black, Arial", this.add.text(cx, 270, "a pixel-art platformer", SUBTITLE_STYLE).setOrigin(0.5);
fontSize: "78px",
color: "#ffd700",
fontStyle: "bold",
stroke: "#7a5500",
strokeThickness: 6,
})
.setOrigin(0.5);
this.add
.text(cx, 200, "TILES", {
fontFamily: "Arial Black, Arial",
fontSize: "78px",
color: "#ffd700",
fontStyle: "bold",
stroke: "#7a5500",
strokeThickness: 6,
})
.setOrigin(0.5);
this.add
.text(cx, 270, "a pixel-art platformer", {
fontFamily: "Arial",
fontSize: "18px",
color: "#aaaaaa",
fontStyle: "italic",
})
.setOrigin(0.5);
this.add.image(cx - 80, 360, Player.TEXTURE_KEY); this.add.image(cx - 80, 360, Player.TEXTURE_KEY);
this.add.image(cx, 374, ObstacleSpikeNormal.TEXTURE_KEY); this.add.image(cx, 374, ObstacleSpikeNormal.TEXTURE_KEY);
this.add.image(cx + 80, 374, ObstacleSpikeTricky.TEXTURE_KEY); this.add.image(cx + 80, 374, ObstacleSpikeTricky.TEXTURE_KEY);
const startText = this.add const startText = this.add
.text(cx, 450, "PRESS SPACE TO START", { .text(cx, 450, "PRESS SPACE TO START", PROMPT_STYLE)
fontFamily: "Arial",
fontSize: "26px",
color: "#ffffff",
fontStyle: "bold",
})
.setOrigin(0.5); .setOrigin(0.5);
this.tweens.add({ this.tweens.add({
@@ -91,11 +102,7 @@ export class BootScene extends Phaser.Scene {
}); });
this.add this.add
.text(cx, 510, "← → / A D to move SPACE / ↑ / W to jump", { .text(cx, 510, "← → / A D to move SPACE / ↑ / W to jump", HINT_STYLE)
fontFamily: "Arial",
fontSize: "14px",
color: "#888888",
})
.setOrigin(0.5); .setOrigin(0.5);
const start = () => this.scene.start("GameScene"); const start = () => this.scene.start("GameScene");

View File

@@ -14,9 +14,14 @@ interface SceneData {
levelIndex?: number; levelIndex?: number;
} }
interface Reactive {
react(playerX: number, playerY: number): void;
}
export class GameScene extends Phaser.Scene { export class GameScene extends Phaser.Scene {
private static readonly TRANSITION_DELAY_MS = 1200; private static readonly TRANSITION_DELAY_MS = 1200;
private static readonly FALL_LIMIT_PADDING = 80; private static readonly FALL_LIMIT_PADDING = 80;
private static readonly WORLD_BOUNDS_BOTTOM_PADDING = 200;
private levelIndex = 0; private levelIndex = 0;
private player!: Player; private player!: Player;
@@ -25,6 +30,7 @@ export class GameScene extends Phaser.Scene {
private disappearing: ObstaclePlatformDisappearing[] = []; private disappearing: ObstaclePlatformDisappearing[] = [];
private spikes: ObstacleSpikeNormal[] = []; private spikes: ObstacleSpikeNormal[] = [];
private trickySpikes: ObstacleSpikeTricky[] = []; private trickySpikes: ObstacleSpikeTricky[] = [];
private reactives: Reactive[] = [];
private levelCompleted = false; private levelCompleted = false;
private dying = false; private dying = false;
private hudText!: Phaser.GameObjects.Text; private hudText!: Phaser.GameObjects.Text;
@@ -42,10 +48,16 @@ export class GameScene extends Phaser.Scene {
this.disappearing = []; this.disappearing = [];
this.spikes = []; this.spikes = [];
this.trickySpikes = []; this.trickySpikes = [];
this.reactives = [];
} }
create(): void { create(): void {
this.physics.world.setBounds(0, 0, this.scale.width, this.scale.height + 200); this.physics.world.setBounds(
0,
0,
this.scale.width,
this.scale.height + GameScene.WORLD_BOUNDS_BOTTOM_PADDING,
);
const def = LEVELS[this.levelIndex]; const def = LEVELS[this.levelIndex];
const loader = new LevelLoader(this); const loader = new LevelLoader(this);
@@ -56,6 +68,7 @@ export class GameScene extends Phaser.Scene {
this.disappearing = loaded.disappearing; this.disappearing = loaded.disappearing;
this.spikes = loaded.spikes; this.spikes = loaded.spikes;
this.trickySpikes = loaded.trickySpikes; this.trickySpikes = loaded.trickySpikes;
this.reactives = [...loaded.disappearing, ...loaded.trickySpikes];
this.physics.add.collider(this.player, this.platforms, undefined, Platform.canLand); this.physics.add.collider(this.player, this.platforms, undefined, Platform.canLand);
this.physics.add.collider(this.player, this.disappearing, undefined, Platform.canLand); this.physics.add.collider(this.player, this.disappearing, undefined, Platform.canLand);
@@ -85,11 +98,8 @@ export class GameScene extends Phaser.Scene {
if (this.levelCompleted || this.dying) return; if (this.levelCompleted || this.dying) return;
this.player.update(); this.player.update();
for (const platform of this.disappearing) { for (const entity of this.reactives) {
platform.react(this.player.x, this.player.y); entity.react(this.player.x, this.player.y);
}
for (const spike of this.trickySpikes) {
spike.react(this.player.x);
} }
if (this.player.y > this.scale.height + GameScene.FALL_LIMIT_PADDING) { if (this.player.y > this.scale.height + GameScene.FALL_LIMIT_PADDING) {