From accd693b4a9287f17b4ef1125a3b3cfe297bf595 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Thu, 8 Feb 2024 16:06:19 +0100 Subject: [PATCH 01/13] refactor(linter): resolve conflicting rules --- .eslintrc.cjs | 90 +++++++++++++++++---------------------------------- tsconfig.json | 1 - 2 files changed, 29 insertions(+), 62 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e46baaed..8f09bb5a 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,63 +1,31 @@ module.exports = { - 'env': { - 'browser': true, - 'es2021': true - }, - 'extends': [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier' - ], - 'overrides': [ - { - 'env': { - 'node': true - }, - 'files': [ - '.eslintrc.{js,cjs}' - ], - 'parserOptions': { - 'sourceType': 'script' - } - } - ], - 'parser': '@typescript-eslint/parser', - 'parserOptions': { - 'ecmaVersion': 'latest', - 'sourceType': 'module' - }, - 'plugins': [ - '@typescript-eslint', - 'prettier' - ], - 'ignorePatterns': [ - '/node_modules/', - '**/*.d.ts' - ], - 'rules': { - 'indent': [ - 'error', - 2 - ], - 'linebreak-style': [ - 'error', - 'unix' - ], - 'quotes': [ - 'error', - 'single' - ], - 'semi': [ - 'error', - 'always' - ], - 'object-curly-spacing': [ - 'error', - 'always' - ], - 'prettier/prettier': 'error', - 'prefer-const': [ - 'error' - ] - } + env: { + browser: true, + es2021: true, + }, + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], + overrides: [ + { + env: { + node: true, + }, + files: ['.eslintrc.{js,cjs}'], + parserOptions: { + sourceType: 'script', + }, + }, + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['@typescript-eslint', 'prettier'], + ignorePatterns: ['/node_modules/', '**/*.d.ts'], + rules: { + 'prettier/prettier': 'error', + 'prefer-const': ['error'], + 'linebreak-style': ['error', 'unix'], + 'object-curly-spacing': ['error', 'always'], + }, }; diff --git a/tsconfig.json b/tsconfig.json index 8921d538..d50a3737 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ /* Bundler mode */ "types": ["./src/types/Globals.d.ts"], "moduleResolution": "bundler", - "allowImportingTsExtensions": true, "isolatedModules": true, "noEmit": true, From 88a4b87675c49b38d6ed2c2f970650a261a7bb9d Mon Sep 17 00:00:00 2001 From: Walidoux Date: Fri, 9 Feb 2024 12:48:46 +0100 Subject: [PATCH 02/13] perf(rooms/heightmap): precompute stairs + clean up types & method usage memory --- src/objects/rooms/RoomHeightmap.ts | 139 ++++++++++++++++------------- 1 file changed, 76 insertions(+), 63 deletions(-) diff --git a/src/objects/rooms/RoomHeightmap.ts b/src/objects/rooms/RoomHeightmap.ts index 5b008d2a..8b99fb26 100644 --- a/src/objects/rooms/RoomHeightmap.ts +++ b/src/objects/rooms/RoomHeightmap.ts @@ -9,41 +9,55 @@ export class RoomHeightmap { public heightMap: HeightMap; public door: Vector2D | undefined; + private stairMap: Map> = new Map(); + constructor(heightMap: string) { this.heightMap = RoomHeightmap.parse(heightMap); - this.door = this.calculateDoor(); + + for (let y: number = 0; y < this.heightMap.length; y++) { + for (let x: number = 0; x < this.heightMap[y].length; x++) { + // Pre-compute stairs for later use + this.stairMap.set(`${x}-${y}`, this.getStair({ x, y })); + + if (this.door === undefined && this.isEntrance({ x, y })) { + this.door = { x, y }; + } + } + } } public static parse(heightMap: string): HeightMap { return heightMap .trim() .split(/\r?\n/) - .map((line: string) => { - return line.split(''); - }); + .map((line: string): string[] => line.split('')); } - public calculateDoor(): Vector2D | undefined { + public isEntrance({ x, y }: Vector2D): typeof this.door { + const topLeftTile: Vector2D = { x: x - 1, y: y - 1 }; + const topTile: Vector2D = { x, y: y - 1 }; + + const midLeftTile: Vector2D = { x: x - 1, y }; + const midTile: Vector2D = { x: x, y: y }; + + const botLeftTile: Vector2D = { x: x - 1, y: y + 1 }; + const botTile: Vector2D = { x, y: y + 1 }; + + if ( + !this.isTile(topTile) && + !this.isTile(topLeftTile) && + !this.isTile(midLeftTile) && + !this.isTile(botLeftTile) && + !this.isTile(botTile) && + this.isTile(midTile) + ) + return { x, y }; + } + + public calculateDoor(): typeof this.door { for (let y: number = 0; y < this.heightMap.length; y++) { for (let x: number = 0; x < this.heightMap[y].length; x++) { - const topLeftTile: Vector2D = { x: x - 1, y: y - 1 }; - const topTile: Vector2D = { x, y: y - 1 }; - - const midLeftTile: Vector2D = { x: x - 1, y }; - const midTile: Vector2D = { x: x, y: y }; - - const botLeftTile: Vector2D = { x: x - 1, y: y + 1 }; - const botTile: Vector2D = { x, y: y + 1 }; - - if ( - !this.isTile(topTile) && - !this.isTile(topLeftTile) && - !this.isTile(midLeftTile) && - !this.isTile(botLeftTile) && - !this.isTile(botTile) && - this.isTile(midTile) - ) - return { x, y }; + return this.isEntrance({ x, y }); } } } @@ -62,16 +76,19 @@ export class RoomHeightmap { return tile === 'x' ? 0 : isNaN(Number(tile)) ? tile.charCodeAt(0) - 96 + 9 : Number(tile); } - public getTileDifference(position1: Vector2D, position2: Vector2D): number { - return Number(this.getTileHeight(position1)) - Number(this.getTileHeight(position2)); + public getTileHeightDiff(position1: Vector2D, position2: Vector2D): number { + return this.getTileHeight(position1) - this.getTileHeight(position2); } public getStair({ x, y }: Vector2D): Stair | undefined { + if (!this.isTile({ x, y })) return undefined; + const topLeftTile: Vector2D = { x: x - 1, y: y - 1 }; const topTile: Vector2D = { x: x, y: y - 1 }; const topRightTile: Vector2D = { x: x + 1, y: y - 1 }; const midLeftTile: Vector2D = { x: x - 1, y: y }; + const midTile: Vector2D = { x: x, y: y }; const midRightTile: Vector2D = { x: x + 1, y: y }; const botLeftTile: Vector2D = { x: x - 1, y: y + 1 }; @@ -79,11 +96,10 @@ export class RoomHeightmap { const botRightTile: Vector2D = { x: x + 1, y: y + 1 }; if ( - this.isTile({ x, y }) && this.isTile(topRightTile) && - this.getTileDifference(topRightTile, { x, y }) === 1 && - this.getTileDifference(midRightTile, { x, y }) === 1 && - this.getTileDifference(topTile, { x, y }) === 1 + this.getTileHeightDiff(topRightTile, midTile) === 1 && + this.getTileHeightDiff(midRightTile, midTile) === 1 && + this.getTileHeightDiff(topTile, midTile) === 1 ) return { type: StairType.INNER_CORNER_STAIR, @@ -91,11 +107,10 @@ export class RoomHeightmap { }; if ( - this.isTile({ x, y }) && this.isTile(botRightTile) && - this.getTileDifference(botRightTile, { x, y }) === 1 && - this.getTileDifference(midRightTile, { x, y }) === 1 && - this.getTileDifference(botTile, { x, y }) === 1 + this.getTileHeightDiff(botRightTile, midTile) === 1 && + this.getTileHeightDiff(midRightTile, midTile) === 1 && + this.getTileHeightDiff(botTile, midTile) === 1 ) return { type: StairType.INNER_CORNER_STAIR, @@ -103,11 +118,10 @@ export class RoomHeightmap { }; if ( - this.isTile({ x, y }) && this.isTile(botLeftTile) && - this.getTileDifference(botLeftTile, { x, y }) === 1 && - this.getTileDifference(midLeftTile, { x, y }) === 1 && - this.getTileDifference(botTile, { x, y }) === 1 + this.getTileHeightDiff(botLeftTile, midTile) === 1 && + this.getTileHeightDiff(midLeftTile, midTile) === 1 && + this.getTileHeightDiff(botTile, midTile) === 1 ) return { type: StairType.INNER_CORNER_STAIR, @@ -115,28 +129,26 @@ export class RoomHeightmap { }; if ( - this.isTile({ x, y }) && this.isTile(topLeftTile) && - this.getTileDifference(topLeftTile, { x, y }) === 1 && - this.getTileDifference(midLeftTile, { x, y }) === 1 && - this.getTileDifference(topTile, { x, y }) === 1 + this.getTileHeightDiff(topLeftTile, { x, y }) === 1 && + this.getTileHeightDiff(midLeftTile, { x, y }) === 1 && + this.getTileHeightDiff(topTile, { x, y }) === 1 ) return { type: StairType.INNER_CORNER_STAIR, direction: Direction.NORTH_WEST, }; - if (this.isTile({ x, y }) && this.isTile(topTile) && this.getTileDifference(topTile, { x, y }) === 1) + if (this.isTile(topTile) && this.getTileHeightDiff(topTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.NORTH }; if ( - this.isTile({ x, y }) && this.isTile(topRightTile) && - this.getTileDifference(topRightTile, { x, y }) === 1 && - this.getTileDifference(midRightTile, { x, y }) !== 1 && - this.getTileDifference(topTile, { x, y }) !== 1 + this.getTileHeightDiff(topRightTile, midTile) === 1 && + this.getTileHeightDiff(midRightTile, midTile) !== 1 && + this.getTileHeightDiff(topTile, midTile) !== 1 ) { - if (this.getTileDifference(midLeftTile, { x, y }) === 1) + if (this.getTileHeightDiff(midLeftTile, midTile) === 1) return { type: StairType.INNER_CORNER_STAIR, direction: Direction.NORTH_EAST, @@ -148,52 +160,53 @@ export class RoomHeightmap { }; } - if (this.isTile({ x, y }) && this.isTile(midRightTile) && this.getTileDifference(midRightTile, { x, y }) === 1) + if (this.isTile(midRightTile) && this.getTileHeightDiff(midRightTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.EAST }; if ( - this.isTile({ x, y }) && this.isTile(botRightTile) && - this.getTileDifference(botRightTile, { x, y }) === 1 && - this.getTileDifference(midRightTile, { x, y }) !== 1 && - this.getTileDifference(botTile, { x, y }) !== 1 + this.getTileHeightDiff(botRightTile, midTile) === 1 && + this.getTileHeightDiff(midRightTile, midTile) !== 1 && + this.getTileHeightDiff(botTile, midTile) !== 1 ) return { type: StairType.OUTER_CORNER_STAIR, direction: Direction.SOUTH_EAST, }; - if (this.isTile({ x, y }) && this.isTile(botTile) && this.getTileDifference(botTile, { x, y }) === 1) + if (this.isTile(botTile) && this.getTileHeightDiff(botTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.SOUTH }; if ( - this.isTile({ x, y }) && this.isTile(botLeftTile) && - this.getTileDifference(botLeftTile, { x, y }) === 1 && - this.getTileDifference(midLeftTile, { x, y }) !== 1 && - this.getTileDifference(botTile, { x, y }) !== 1 + this.getTileHeightDiff(botLeftTile, midTile) === 1 && + this.getTileHeightDiff(midLeftTile, midTile) !== 1 && + this.getTileHeightDiff(botTile, midTile) !== 1 ) return { type: StairType.OUTER_CORNER_STAIR, direction: Direction.SOUTH_WEST, }; - if (this.isTile({ x, y }) && this.isTile(midLeftTile) && this.getTileDifference(midLeftTile, { x, y }) === 1) + if (this.isTile(midLeftTile) && this.getTileHeightDiff(midLeftTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.WEST }; if ( - this.isTile({ x, y }) && this.isTile(topLeftTile) && - this.getTileDifference(topLeftTile, { x, y }) === 1 && - this.getTileDifference(midLeftTile, { x, y }) !== 1 && - this.getTileDifference(topTile, { x, y }) !== 1 + this.getTileHeightDiff(topLeftTile, midTile) === 1 && + this.getTileHeightDiff(midLeftTile, midTile) !== 1 && + this.getTileHeightDiff(topTile, midTile) !== 1 ) return { type: StairType.OUTER_CORNER_STAIR, direction: Direction.NORTH_WEST, }; - return; + return undefined; + } + + public getComputedStair({ x, y }: Parameters[number]): ReturnType { + return this.stairMap.get(`${x}-${y}`) ?? this.getStair({ x, y }); } public getWall({ x, y }: Vector2D): WallType | undefined { From ad6af9f3dc52395ea3326f196bc4421308fe5b80 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Fri, 23 Feb 2024 21:24:25 +0100 Subject: [PATCH 03/13] test(objects/rooms/mesher): work in progress --- src/objects/rooms/geometry/GreedyMesher.ts | 385 ++++++++++----------- 1 file changed, 178 insertions(+), 207 deletions(-) diff --git a/src/objects/rooms/geometry/GreedyMesher.ts b/src/objects/rooms/geometry/GreedyMesher.ts index 9d7f1705..892fad0c 100644 --- a/src/objects/rooms/geometry/GreedyMesher.ts +++ b/src/objects/rooms/geometry/GreedyMesher.ts @@ -10,21 +10,16 @@ export class GreedyMesher { constructor(public heightMap: RoomHeightmap) {} public get tiles(): Array { - const sizes: Record> = {}; - let tiles: Array = []; + let sizes: Record> = {}; + const tiles: Array = []; - for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { - sizes[y] = {}; - for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { - if (!this.heightMap.isTile({ x, y }) || this.heightMap.getStair({ x, y })) sizes[y][x] = undefined; - else - sizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } - } + sizes = this.heightMap.heightMap.map( + (row, y): Array => + row.map((_, x): Vector3D | undefined => { + if (!this.heightMap.isTile({ x, y }) || this.heightMap.getStair({ x, y })) return undefined; + else return { x: 1, y: 1, z: this.heightMap.getTileHeight({ x, y }) }; + }), + ); for (let y: number = 1; y < this.heightMap.heightMap.length; y++) { for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { @@ -47,35 +42,33 @@ export class GreedyMesher { (this.heightMap.door?.x === x - 1 && this.heightMap.door?.y === y) ) continue; - if (sizes[y][x] && sizes[y][x - 1] && sizes[y][x]!.y === sizes[y][x - 1]!.y) { - sizes[y][x]!.x += sizes[y][x - 1]!.x; - sizes[y][x - 1] = undefined; + if (sizes[y][x] && sizes[y][x - 1]) { + if (sizes[y][x]!.y === sizes[y][x - 1]!.y) { + sizes[y][x]!.x += sizes[y][x - 1]!.x; + sizes[y][x - 1] = undefined; + } } } } - for (const y in sizes) { - for (const x in sizes[y]) { - if (sizes[y][x]) { + for (const [y, row] of Object.entries(sizes)) { + for (const [x, size] of Object.entries(row)) { + if (size) { const door: boolean = this.heightMap.door?.x === Number(x) && this.heightMap.door?.y === Number(y); tiles.push({ position: { - x: Number(x) - sizes[y][x]!.x + 1, - y: Number(y) - sizes[y][x]!.y + 1, - z: sizes[y][x]!.z, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + z: size.z, }, - size: sizes[y][x] as Vector2D, + size: size as Vector2D, door: door, }); } } } - tiles = tiles.sort((a, b) => { - if (a.position.x + a.size.x <= b.position.x || a.position.y + a.size.y <= b.position.y || a.position.z <= b.position.z) return 1; - return -1; - }); return tiles; } @@ -90,169 +83,163 @@ export class GreedyMesher { columnStairSizes[y] = {}; for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { const stair: Stair | undefined = this.heightMap.getStair({ x, y }); - if (stair) { - if (stair.direction === Direction.NORTH || stair.direction === Direction.SOUTH) { - rowStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else if (stair.direction === Direction.WEST || stair.direction === Direction.EAST) { - columnStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else if (stair.type !== StairType.STAIR) { - rowStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - columnStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } + + if (!stair) continue; + if (stair.directions.includes(Direction.NORTH) || stair.directions.includes(Direction.SOUTH)) { + rowStairSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; + } else if (stair.directions.includes(Direction.WEST) || stair.directions.includes(Direction.EAST)) { + columnStairSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; + } else { + const z = this.heightMap.getTileHeight({ x, y }); + + rowStairSizes[y][x] = { x: 1, y: 1, z: z }; + columnStairSizes[y][x] = { x: 1, y: 1, z: z }; } } } - for (let y: number = 1; y < this.heightMap.heightMap.length; y++) { - for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { - const stair: Stair | undefined = this.heightMap.getStair({ - x: x - 1, - y, - }); - if (stair && this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x: x - 1, y: y })) { - if (stair.direction === Direction.NORTH || stair.direction === Direction.SOUTH || stair.type !== StairType.STAIR) { - if (rowStairSizes[y][x] && rowStairSizes[y][x - 1] && rowStairSizes[y][x]!.y === rowStairSizes[y][x - 1]!.y) { - rowStairSizes[y][x]!.x += rowStairSizes[y][x - 1]!.x; - rowStairSizes[y][x - 1] = undefined; - } else if (!rowStairSizes[y][x - 1]) { - rowStairSizes[y][x]!.x += rowStairSizes[y][x]!.x; + for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { + for (let x: number = 1; x <= this.heightMap.heightMap[y].length; x++) { + const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }); + const stair: Stair | undefined = this.heightMap.getStair({ x: x - 1, y }); + + if (!stair || !currentStair) continue; + if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x: x - 1, y: y })) { + if (stair.directions.includes(Direction.NORTH) || stair.directions.includes(Direction.SOUTH) || stair.type !== StairType.STAIR) { + if (!(stair.type === currentStair.type && !currentStair.directions.includes(stair.directions[0]))) { + if (rowStairSizes[y][x] && rowStairSizes[y][x - 1]) { + if (rowStairSizes[y][x]?.y === rowStairSizes[y][x - 1]?.y) { + rowStairSizes[y][x]!.x += rowStairSizes[y][x - 1]!.x; + rowStairSizes[y][x - 1] = undefined; + } + } } } } } } - for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { - for (let x: number = 1; x < this.heightMap.heightMap[y].length; x++) { - const stair: Stair | undefined = this.heightMap.getStair({ - x, - y: y - 1, - }); - if (stair && this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x: x, y: y - 1 })) { - if (stair.direction === Direction.WEST || stair.direction === Direction.EAST || stair.type !== StairType.STAIR) { - if (columnStairSizes[y][x] && columnStairSizes[y - 1][x] && columnStairSizes[y][x]!.x === columnStairSizes[y - 1][x]!.x) { - columnStairSizes[y][x]!.y += columnStairSizes[y - 1][x]!.y; - columnStairSizes[y - 1][x] = undefined; - } else if (!columnStairSizes[y - 1][x]) { - columnStairSizes[y][x]!.y += columnStairSizes[y][x]!.y; + for (let y: number = 1; y < this.heightMap.heightMap.length; y++) { + for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { + const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }); + const stair: Stair | undefined = this.heightMap.getStair({ x, y: y - 1 }); + + if (!stair || !currentStair) continue; + if (!(currentStair.directions.length >= 2)) { + if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x, y: y - 1 })) { + if (!(stair.type === currentStair.type && !currentStair.directions.includes(stair.directions[0]))) { + if (columnStairSizes[y][x] && columnStairSizes[y - 1][x]) { + if (columnStairSizes[y][x]?.x === columnStairSizes[y - 1][x]?.x) { + columnStairSizes[y][x]!.y += columnStairSizes[y - 1][x]!.y; + columnStairSizes[y - 1][x] = undefined; + } + } } } } } } - for (const y in rowStairSizes) { - for (const x in rowStairSizes[y]) { - const stair: Stair | undefined = this.heightMap.getStair({ + for (const [y, row] of Object.entries(rowStairSizes)) { + for (const [x, size] of Object.entries(row)) { + const stair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y), - }); - if (rowStairSizes[y][x] && stair) { - const length: number = Number(rowStairSizes[y][x]!.x); - let direction: Direction = stair.direction; + })!; - if (direction === Direction.NORTH_WEST || direction === Direction.NORTH_EAST) direction = Direction.NORTH; - if (direction === Direction.SOUTH_WEST || direction === Direction.SOUTH_EAST) direction = Direction.SOUTH; + if (size) { + let directions: Direction[] = stair.directions; - const leftStair: Stair | undefined = this.heightMap.getStair({ - x: Number(x) - rowStairSizes[y][x]!.x + 1, - y: Number(y) - rowStairSizes[y][x]!.y + 1, - }); + if (directions.includes(Direction.NORTH_WEST) || directions.includes(Direction.NORTH_EAST)) directions = [Direction.NORTH]; + if (directions.includes(Direction.SOUTH_WEST) || directions.includes(Direction.SOUTH_EAST)) directions = [Direction.SOUTH]; - const rightStair: Stair | undefined = this.heightMap.getStair({ + const leftStair: Stair = this.heightMap.getStair({ + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + })!; + + const rightStair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y), - }); + })!; // Check if it's a tiny stair - if (rowStairSizes[y][x]!.x == 1 && rowStairSizes[y][x]!.y == 1) { - if (leftStair) { - if (leftStair.direction === Direction.NORTH_EAST) { - rightStair!.type = StairType.STAIR; - } else if (leftStair.direction === Direction.NORTH_WEST) { - leftStair!.type = StairType.STAIR; - } + if (size.x === 1 && size.y === 1) { + if (leftStair.directions.includes(Direction.NORTH_EAST)) { + rightStair.type = StairType.STAIR; + } else if (leftStair.directions.includes(Direction.NORTH_WEST)) { + leftStair.type = StairType.STAIR; } } stairs.push({ position: { - x: Number(x) - rowStairSizes[y][x]!.x + 1, - y: Number(y) - rowStairSizes[y][x]!.y + 1, - z: rowStairSizes[y][x]!.z, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + z: size.z, }, - length: length, - direction: direction, + length: size.x, + direction: directions[0], corners: { - left: leftStair ? leftStair.type : StairType.STAIR, - right: rightStair ? rightStair.type : StairType.STAIR, + left: leftStair.type, + right: rightStair.type, }, }); } } } - for (const y in columnStairSizes) { - for (const x in columnStairSizes[y]) { - const stair: Stair | undefined = this.heightMap.getStair({ + for (const [y, column] of Object.entries(columnStairSizes)) { + for (const [x, size] of Object.entries(column)) { + const stair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y), - }); - if (columnStairSizes[y][x] && stair) { - const length: number = Number(columnStairSizes[y][x]!.y); - let direction: Direction = stair.direction; + })!; - if (direction === Direction.NORTH_WEST || direction === Direction.SOUTH_WEST) direction = Direction.WEST; - if (direction === Direction.SOUTH_EAST || direction === Direction.NORTH_EAST) direction = Direction.EAST; + if (size) { + let directions: Direction[] = stair.directions; - const leftStair: Stair | undefined = this.heightMap.getStair({ + if (directions.includes(Direction.NORTH_WEST) || directions.includes(Direction.SOUTH_WEST)) directions = [Direction.WEST]; + if (directions.includes(Direction.SOUTH_EAST) || directions.includes(Direction.NORTH_EAST)) directions = [Direction.EAST]; + + const leftStair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y), - }); + })!; - const rightStair: Stair | undefined = this.heightMap.getStair({ - x: Number(x) - columnStairSizes[y][x]!.x + 1, - y: Number(y) - columnStairSizes[y][x]!.y + 1, - }); + const rightStair: Stair = this.heightMap.getStair({ + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + })!; // Check if it's a tiny stair - if (columnStairSizes[y][x]!.x == 1 && columnStairSizes[y][x]!.y == 1) { - if (leftStair) { - if (leftStair.direction === Direction.NORTH_WEST) { - rightStair!.type = StairType.STAIR; - } else if (leftStair.direction === Direction.SOUTH_WEST) { - leftStair!.type = StairType.STAIR; - } + if (size.x === 1 && size.y === 1) { + if (leftStair.directions.includes(Direction.NORTH_WEST)) { + rightStair.type = StairType.STAIR; + } else if (leftStair.directions.includes(Direction.SOUTH_WEST)) { + leftStair.type = StairType.STAIR; } } stairs.push({ position: { - x: Number(x) - columnStairSizes[y][x]!.x + 1, - y: Number(y) - columnStairSizes[y][x]!.y + 1, - z: columnStairSizes[y][x]!.z, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + z: size.z, }, - length: length, - direction: direction, + length: size.y, + direction: directions[0], corners: { - left: leftStair ? leftStair.type : StairType.STAIR, - right: rightStair ? rightStair.type : StairType.STAIR, + left: leftStair.type, + right: rightStair.type, }, }); } @@ -273,31 +260,31 @@ export class GreedyMesher { columnWallSizes[y] = {}; for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { const wall: WallType | undefined = this.heightMap.getWall({ x, y }); - if (wall !== undefined) { - if (wall === WallType.RIGHT_WALL) { - rowWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else if (wall === WallType.LEFT_WALL) { - columnWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else if (wall === WallType.CORNER_WALL) { - rowWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - columnWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } + + if (wall === undefined) continue; + if (wall === WallType.RIGHT_WALL) { + rowWallSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; + } else if (wall === WallType.LEFT_WALL) { + columnWallSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; + } else if (wall === WallType.CORNER_WALL) { + rowWallSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; + columnWallSizes[y][x] = { + x: 1, + y: 1, + z: this.heightMap.getTileHeight({ x, y }), + }; } } } @@ -308,12 +295,12 @@ export class GreedyMesher { x: x - 1, y, }); - if (wall !== undefined) { - if (wall === WallType.RIGHT_WALL || wall === WallType.CORNER_WALL) { - if (rowWallSizes[y][x] && rowWallSizes[y][x - 1] && rowWallSizes[y][x]!.y === rowWallSizes[y][x - 1]!.y) { - rowWallSizes[y][x]!.x += rowWallSizes[y][x - 1]!.x; - rowWallSizes[y][x - 1] = undefined; - } + + if (wall === undefined) continue; + if (wall === WallType.RIGHT_WALL || wall === WallType.CORNER_WALL) { + if (rowWallSizes[y][x] && rowWallSizes[y][x - 1] && rowWallSizes[y][x]!.y === rowWallSizes[y][x - 1]!.y) { + rowWallSizes[y][x]!.x += rowWallSizes[y][x - 1]!.x; + rowWallSizes[y][x - 1] = undefined; } } } @@ -321,37 +308,28 @@ export class GreedyMesher { for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { for (let x: number = 1; x < this.heightMap.heightMap[y].length; x++) { - const wall: WallType | undefined = this.heightMap.getWall({ - x, - y: y - 1, - }); - if (wall !== undefined) { - if (wall === WallType.LEFT_WALL || wall === WallType.CORNER_WALL) { - if (columnWallSizes[y][x] && columnWallSizes[y - 1][x] && columnWallSizes[y][x]!.x === columnWallSizes[y - 1][x]!.x) { - columnWallSizes[y][x]!.y += columnWallSizes[y - 1][x]!.y; - columnWallSizes[y - 1][x] = undefined; - } + const wall: WallType | undefined = this.heightMap.getWall({ x, y: y - 1 }); + + if (wall === undefined) continue; + if (wall === WallType.LEFT_WALL || wall === WallType.CORNER_WALL) { + if (columnWallSizes[y][x] && columnWallSizes[y - 1][x] && columnWallSizes[y][x]!.x === columnWallSizes[y - 1][x]!.x) { + columnWallSizes[y][x]!.y += columnWallSizes[y - 1][x]!.y; + columnWallSizes[y - 1][x] = undefined; } } } } - for (const y in rowWallSizes) { - for (const x in rowWallSizes[y]) { - const wall: WallType | undefined = this.heightMap.getWall({ - x: Number(x), - y: Number(y), - }); - if (rowWallSizes[y][x] && wall !== undefined) { - const length: number = Number(rowWallSizes[y][x]!.x); - + for (const [y, row] of Object.entries(rowWallSizes)) { + for (const [x, size] of Object.entries(row)) { + if (size) { walls.push({ position: { - x: Number(x) - rowWallSizes[y][x]!.x + 1, - y: Number(y) - rowWallSizes[y][x]!.y + 1, - z: rowWallSizes[y][x]!.z, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + z: size.z, }, - length: length, + length: size.x, direction: Direction.NORTH, corner: false, }); @@ -359,29 +337,22 @@ export class GreedyMesher { } } - for (const y in columnWallSizes) { - for (const x in columnWallSizes[y]) { - const wall: WallType | undefined = this.heightMap.getWall({ - x: Number(x), - y: Number(y), - }); - - if (columnWallSizes[y][x] && wall !== undefined) { - const length: number = Number(columnWallSizes[y][x]!.y); - + for (const [y, column] of Object.entries(columnWallSizes)) { + for (const [x, size] of Object.entries(column)) { + if (size) { const corner: boolean = this.heightMap.getWall({ - x: Number(x) - columnWallSizes[y][x]!.x + 1, - y: Number(y) - columnWallSizes[y][x]!.y + 1, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, }) === WallType.CORNER_WALL; walls.push({ position: { - x: Number(x) - columnWallSizes[y][x]!.x + 1, - y: Number(y) - columnWallSizes[y][x]!.y + 1, - z: columnWallSizes[y][x]!.z, + x: Number(x) - size.x + 1, + y: Number(y) - size.y + 1, + z: size.z, }, - length: length, + length: size.y, direction: Direction.WEST, corner: corner, }); From 1a1b5702b2b392370a8d47d64da285b2a8916f80 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Sun, 25 Feb 2024 18:35:29 +0100 Subject: [PATCH 04/13] test(objects/rooms/parts): fix stair corner issues --- src/objects/rooms/parts/floor/StairPart.ts | 302 +++++++++++++-------- 1 file changed, 186 insertions(+), 116 deletions(-) diff --git a/src/objects/rooms/parts/floor/StairPart.ts b/src/objects/rooms/parts/floor/StairPart.ts index cf72fa96..9de18c3e 100644 --- a/src/objects/rooms/parts/floor/StairPart.ts +++ b/src/objects/rooms/parts/floor/StairPart.ts @@ -1,6 +1,6 @@ import { RoomPart } from '../RoomPart'; import { Room } from '../../Room'; -import { Container, FederatedPointerEvent, Point, Polygon } from 'pixi.js'; +import { Container, FederatedPointerEvent, Graphics, Point, Polygon } from 'pixi.js'; import { FloorMaterial } from '../../materials/FloorMaterial'; import { Cube } from '../../geometry/Cube'; import { Vector2D, Vector3D } from '../../../../types/Vector'; @@ -9,37 +9,33 @@ import { EventManager } from '../../../events/EventManager'; import { StairType } from '../../../../enums/StairType'; import { Direction } from '../../../../enums/Direction'; import { floorOrder } from '../../../../utils/Sorting'; +import { StairMesh } from '../../../..'; -interface Corners { - left: StairType; - right: StairType; -} - -interface Configuration { - material?: FloorMaterial; - position: Vector3D; +interface Configuration extends StairMesh { + material: FloorMaterial; thickness: number; - length: number; - direction: Direction; - corners: Corners; } export class StairPart extends RoomPart { public room!: Room; - public container: Container = new Container(); + public container: Container | undefined = new Container(); public eventManager: EventManager = new EventManager(); - private _material: FloorMaterial; - private _position: Vector3D; - private _thickness: number; - private _length: number; - private _direction: Direction; - private _corners: Corners; + private _material: Configuration['material']; + private _position: Configuration['position']; + private _thickness: Configuration['thickness']; + private _length: Configuration['length']; + private _direction: Configuration['direction']; + private _corners: Configuration['corners']; constructor({ material, position, thickness, length, direction, corners }: Configuration) { super(); - this._material = material ?? new FloorMaterial(101); + this._material = material; + this.container!.name = `X:${position.x}, Y: ${position.y} / ${StairType[corners.left]} ${StairType[corners.right]} ${ + Direction[direction] + }`; + this._position = position; this._thickness = thickness; this._length = length; @@ -50,112 +46,135 @@ export class StairPart extends RoomPart { } private _registerEvents(): void { - this.container.onpointerdown = (event: FederatedPointerEvent) => + this.container!.onpointerdown = (event: FederatedPointerEvent): void => this.eventManager.handlePointerDown({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerup = (event: FederatedPointerEvent) => + this.container!.onpointerup = (event: FederatedPointerEvent): void => this.eventManager.handlePointerUp({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointermove = (event: FederatedPointerEvent) => + this.container!.onpointermove = (event: FederatedPointerEvent): void => this.eventManager.handlePointerMove({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerout = (event: FederatedPointerEvent) => + this.container!.onpointerout = (event: FederatedPointerEvent): void => this.eventManager.handlePointerOut({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerover = (event: FederatedPointerEvent) => + this.container!.onpointerover = (event: FederatedPointerEvent): void => this.eventManager.handlePointerOver({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); + + this.container!.eventMode = 'static'; } public render(): void { const position = this._containerPosition(); - this.container.x = position.x; - this.container.y = position.y; + this.container!.x = position.x; + this.container!.y = position.y; switch (this._direction) { case Direction.NORTH: - this._renderStair({ - x: 8, - y: -12, - }); + const graphics = new Graphics(); + + const polygonPoints = [ + new Point(0, 0), + new Point(32, -16), + new Point(32 * (this._length + 1), 16 * (this._length - 1)), + new Point(32 * this._length, 16 * this._length), + new Point(0, 0), + ]; + + this.container!.hitArea = new Polygon(polygonPoints); + + // rectangle + /* graphics + .beginFill('ffd800', 0.3) + .drawPolygon(...polygonPoints) + .endFill(); */ + + // circles + /* for (const point of polygonPoints) { + graphics.beginFill('#ffd800').drawCircle(point.x, point.y, 1).endFill(); + } */ + + this.container!.addChild(graphics); + + this._renderStair({ x: 8, y: -12 }); break; case Direction.WEST: - this.container.y -= 24; - this._renderStair({ - x: 8, - y: 12, - }); + const graphics2 = new Graphics(); + + const test = [ + new Point(0, 24), + new Point(32 * this._length, -16 * this._length + 24), + new Point(64 + 32 * (this._length - 1), -16 * (this._length - 1) + 24), + new Point(32, 40), + new Point(0, 24), + ]; + + this.container!.y -= 24; + this.container!.hitArea = new Polygon(test); + + // rectangle + /* graphics2 + .beginFill(0x00ff00, 0.3) + .drawPolygon(...test) + .endFill(); */ + + // circles + /* for (const point of test) { + graphics2.beginFill('#ffd800').drawCircle(point.x, point.y, 1).endFill(); + } */ + + this.container!.addChild(graphics2); + + this._renderStair({ x: 8, y: 12 }); break; case Direction.SOUTH: - this.container.x += 24; - this.container.y -= 12; - this._renderStair({ - x: -8, - y: -4, - }); - break; - case Direction.EAST: - this.container.x += 24; - this.container.y -= 12; - this._renderStair({ - x: -8, - y: 4, - }); - break; - } - - if (this._direction === Direction.NORTH) { - this.container.hitArea = new Polygon( - new Point(0, 0), - new Point(32, -16), - new Point(32 * (this._length + 1) + 32 * (1 - 1), -16 * (1 - 1) + 16 * (this._length - 1)), - new Point(32 * this._length, 16 * this._length), - new Point(0, 0), - ); - } else if (this._direction === Direction.WEST) { - this.container.hitArea = new Polygon( - new Point(0, 24), - new Point(32 * this._length, -16 * this._length + 24), - new Point(64 + 32 * (this._length - 1), -16 * (this._length - 1) + 24), - new Point(32, 40), - new Point(0, 24), - ); - } else if (this._direction === Direction.SOUTH) { - this.container.hitArea = new Polygon(); - /*this.container.addChild(new Graphics().beginFill(0x00FF00, 0.3).drawPolygon( + this.container!.x += 24; + this.container!.y -= 12; + this.container!.hitArea = new Polygon(); + /*this.container.addChild(new Graphics().beginFill(0x00FF00, 0.3).drawPolygon( new Point(0 - 24, 0 + 12), new Point(32 * 1 - 24, -16 * 1 + 12), new Point(32 * (this._length + 1) + 32 * (1 - 1) - 24, -16 * (1 - 1) + 16 * (this._length - 1) + 12), new Point(32 * this._length - 24, 16 * this._length + 12), new Point(0 - 24, 0 + 12) ).endFill());*/ - } else if (this._direction === Direction.EAST) { - this.container.hitArea = new Polygon(); - /*this.container.addChild(new Graphics().beginFill(0xFF0000, 0.3).drawPolygon( - new Point(0 - 24, 24 - 12), - new Point(32 * this._length - 24, -16 * this._length + 24 - 12), - new Point(64 + 32 * (this._length - 1) - 24, -16 * (this._length - 1) + 24 - 12), - new Point(32 - 24, 40 - 12), - new Point(0 - 24, 24 - 12) - ).endFill());*/ - } - this.container.eventMode = 'static'; + this._renderStair({ x: -8, y: -4 }); + break; + case Direction.EAST: + this.container!.x += 24; + this.container!.y -= 12; + this.container!.hitArea = new Polygon(); + /* this.container!.addChild( + new Graphics() + .beginFill(0xff0000, 0.3) + .drawPolygon( + new Point(0 - 24, 24 - 12), + new Point(32 * this._length - 24, -16 * this._length + 24 - 12), + new Point(64 + 32 * (this._length - 1) - 24, -16 * (this._length - 1) + 24 - 12), + new Point(32 - 24, 40 - 12), + new Point(0 - 24, 24 - 12), + ) + .endFill(), + ); */ + + this._renderStair({ x: -8, y: 4 }); + break; + } } private _renderStair(offsets: Vector2D): void { - const material: FloorMaterial = this._material ?? new FloorMaterial(101); - for (let i: number = 0; i < 4; i++) { const size: Vector3D = { x: this._direction === Direction.NORTH || this._direction === Direction.SOUTH ? this._length : 8 / 32, @@ -184,14 +203,14 @@ export class StairPart extends RoomPart { this._corners.right === StairType.OUTER_CORNER_STAIR && (this._direction === Direction.WEST || this._direction === Direction.EAST) ) { - size.y += (8 / 32) * (i - 3); + size.y -= (8 / 32) * (3 - i); } if ( this._corners.left === StairType.INNER_CORNER_STAIR && (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) ) { - size.x += (8 / 32) * (i - 4); + size.x -= (8 / 32) * (3 - i); } else if ( this._corners.left === StairType.INNER_CORNER_STAIR && (this._direction === Direction.WEST || this._direction === Direction.EAST) @@ -203,19 +222,28 @@ export class StairPart extends RoomPart { this._corners.right === StairType.INNER_CORNER_STAIR && (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) ) { - size.x += (8 / 32) * (i - 4) + 0.25; + size.x -= (8 / 32) * (4 - i) + 0.25; } else if ( this._corners.right === StairType.INNER_CORNER_STAIR && (this._direction === Direction.WEST || this._direction === Direction.EAST) ) { size.y -= (8 / 32) * i; - if (this._direction === Direction.WEST) size.y -= 0.25; } - const textureOffset: Vector2D = { - x: 0, - y: 0, - }; + // NEEDS REFACTORING + if (this._corners.right === StairType.TWIN_CORNER_STAIR && this._direction === Direction.WEST) { + /* this._position.x === 13 && this._position.y === 3 && console.log(size.y); */ + // cuurent: [0.25, 0.5, 0.75, 1] + // expected: [0.25, 0.5, 0.5, 0.25] + size.y = i === 0 || i === 3 ? 0.25 : 0.5; + /* this._position.x === 13 && this._position.y === 3 && console.log(size.y); */ + } + + if (this._corners.left === StairType.TWIN_CORNER_STAIR && this._direction === Direction.NORTH) { + size.x -= (8 / 32) * (3 - i); + } + + const textureOffset: Vector2D = { x: 0, y: 0 }; if (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) { switch (this._corners.left) { @@ -256,24 +284,22 @@ export class StairPart extends RoomPart { }; if (this._direction === Direction.WEST || this._direction === Direction.EAST) { - zOrders[CubeFace.TOP] += 3 + i; - zOrders[CubeFace.LEFT] += 3 + i; - zOrders[CubeFace.RIGHT] += 3 + i; - - if (this._direction === Direction.EAST) zOrders[CubeFace.RIGHT] -= 100; + zOrders[CubeFace.TOP] -= i - 3; + zOrders[CubeFace.LEFT] -= i - 3; + zOrders[CubeFace.RIGHT] -= i - 3; } else { - zOrders[CubeFace.TOP] -= 3 + i; - zOrders[CubeFace.LEFT] -= 3 + i; - zOrders[CubeFace.RIGHT] -= 3 + i; - - if (this._direction === Direction.SOUTH) zOrders[CubeFace.LEFT] -= 100; + zOrders[CubeFace.TOP] += i; + zOrders[CubeFace.LEFT] += i; + zOrders[CubeFace.RIGHT] += i; } + const cubes: Cube[] = []; + const cube: Cube = new Cube({ layer: this.room.renderer.layer, + texture: this._material.texture, + color: this._material.color, zOrders: zOrders, - texture: material.texture, - color: material.color, size: size, offsets: { [CubeFace.TOP]: textureOffset, @@ -282,6 +308,8 @@ export class StairPart extends RoomPart { }, }); + cube.name = `Cube -> ${i}, size: ${size.x} ${size.y} ${size.z} ${zOrders[CubeFace.RIGHT]}`; + cube.x = offsets.x * i; cube.y = offsets.y * i; @@ -313,16 +341,50 @@ export class StairPart extends RoomPart { cube.y -= 4 * i; } - if (this._direction === Direction.EAST) cube.zIndex = -i; + if (this._corners.left === StairType.TWIN_CORNER_STAIR && this._direction === Direction.NORTH) { + cube.x += 8 * (3 - i); + cube.y += 4 * (3 - i); + } + + cubes.push(cube); - this.container.addChild(cube); + // NEEDS REFACTORING + if ( + this._corners.left === StairType.TWIN_CORNER_STAIR && + (this._direction === Direction.NORTH || this._direction === Direction.WEST) + ) { + const cube: Cube = new Cube({ + layer: this.room.renderer.layer, + texture: this._material.texture, + color: this._material.color, + zOrders: zOrders, + size: size, + offsets: { + [CubeFace.TOP]: textureOffset, + [CubeFace.LEFT]: textureOffset, + [CubeFace.RIGHT]: textureOffset, + }, + }); + + // what you're doing is right + + // this._position.x === 13 && this._position.y === 3 && console.log(8 * (3 - i)); + this._position.x === 13 && this._position.y === 3 && console.log(offsets.x, offsets.y, -offsets.x + offsets.x, offsets.y * (3 - i)); + + cube.x = offsets.x + offsets.x * i; + cube.y = offsets.y * (3 - i); + + cubes.push(cube); + } + + this.container!.addChild(...cubes); } } - public destroy() { - if (this.container !== undefined) { + public destroy(): void { + if (this.container != undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } @@ -341,9 +403,10 @@ export class StairPart extends RoomPart { } public getGlobalTilePosition(point: Point): Vector3D { - const localPosition: Point = this.container.toLocal(point); + const localPosition: Point = this.container!.toLocal(point); let localX: number; let localY: number; + if (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) { localX = Math.floor(localPosition.x / 64 + localPosition.y / 32); localY = Math.floor(localPosition.y / 32 - localPosition.x / 64) + 1; @@ -351,6 +414,13 @@ export class StairPart extends RoomPart { localX = Math.floor(localPosition.x / 64 + localPosition.y / 32 + 0.3) - 1; localY = Math.floor(localPosition.y / 32 - localPosition.x / 64 + 0.24) + this._length - 1; } + + /* console.log({ + x: localX + this._position.x, + y: localY + this._position.y, + z: this._position.z, + }) */ + return { x: localX + this._position.x, y: localY + this._position.y, From 692894375aaede7fe61c90d1d24127b23b353151 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Mon, 26 Feb 2024 00:53:51 +0100 Subject: [PATCH 05/13] refactor(logger): fix truncate leading zeros at time --- src/utils/Logger.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts index c0023cb9..55d6582b 100644 --- a/src/utils/Logger.ts +++ b/src/utils/Logger.ts @@ -1,7 +1,5 @@ -import { benchmark } from './Benchmark'; - function formatDate(date: Date): string { - return String(date.getHours()) + ':' + String(date.getMinutes()) + ':' + String(date.getSeconds()); + return date.toLocaleTimeString('en-US', { hour12: false }); } function format(title: string, message: string, date: Date, backgroundColor: string, textColor: string): void { @@ -25,8 +23,8 @@ function error(title: string, message: string): void { format(title, message, new Date(), '#E86C5D', '#FFFFFF'); } -function perf(title: string, tag: string): void { - format('⏱️ BENCHMARK', `${title} initialized in ${benchmark(tag)}ms`, new Date(), '#093a52', '#FFFFFF'); +function perf(title: string, message: string): void { + format(title, message, new Date(), '#093a52', '#FFFFFF'); } export { log, warn, error, perf }; From ad06dc4dd0ae008c35cf9418602bb9fb4a639e17 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Mon, 26 Feb 2024 00:55:15 +0100 Subject: [PATCH 06/13] refactor(benchmark): separate logger logic from benchmark + clean up --- src/utils/Benchmark.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/utils/Benchmark.ts b/src/utils/Benchmark.ts index e63217f6..bdde03b9 100644 --- a/src/utils/Benchmark.ts +++ b/src/utils/Benchmark.ts @@ -1,14 +1,22 @@ +import { perf } from '.'; + const benchmarks: Record = {}; -function benchmark(tag: string): undefined | string { - if (!benchmarks[tag]) { - benchmarks[tag] = performance.now(); - } else { - const time = performance.now() - benchmarks[tag]; - delete benchmarks[tag]; +function benchmark(tag: string) { + benchmarks[tag] = performance.now(); + + return { + perf: (): void => { + const time = performance.now() - benchmarks[tag]; + const title = tag + .split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); - return time.toFixed(2); - } + delete benchmarks[tag]; + return perf('⏱️ BENCHMARK', `${title} initialized in ${time}ms`); + }, + }; } export { benchmark }; From 4763bf8e6820b639445da6315381f9d12fc75c20 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Tue, 27 Feb 2024 14:32:49 +0100 Subject: [PATCH 07/13] feat(stairs): wip --- .gitignore | 18 +- package.json | 7 +- public/assets/dev.ts | 22 ++ public/assets/main.ts | 271 +------------ public/assets/style.css | 8 + public/index.html | 10 +- vite.config.js => public/vite.config.js | 1 + src/Scuti.ts | 13 +- src/ScutiConfiguration.ts | 12 +- src/entities/index.ts | 1 + src/enums/StairType.ts | 1 + src/enums/index.ts | 4 + src/index.ts | 16 +- src/objects/events/index.ts | 1 + src/objects/filters/index.ts | 2 + src/objects/index.ts | 6 + src/objects/parsers/index.ts | 3 + src/objects/rooms/Room.ts | 45 ++- src/objects/rooms/RoomCamera.ts | 67 +++- src/objects/rooms/RoomHeightmap.ts | 55 ++- src/objects/rooms/RoomPreview.ts | 20 + src/objects/rooms/RoomVisualization.ts | 79 ++-- src/objects/rooms/geometry/Cube.ts | 1 + src/objects/rooms/geometry/GreedyMesher.ts | 145 +++---- src/objects/rooms/geometry/index.ts | 2 + src/objects/rooms/index.ts | 12 + src/objects/rooms/layers/MaskLayer.ts | 20 +- src/objects/rooms/layers/ObjectLayer.ts | 3 +- src/objects/rooms/layers/PartLayer.ts | 9 +- src/objects/rooms/layers/index.ts | 4 + src/objects/rooms/materials/index.ts | 4 + .../rooms/objects/furnitures/WallFurniture.ts | 6 +- .../placeholders/WallFurniturePlaceholder.ts | 8 +- .../FurnitureValRandomizerVisualization.ts | 1 - .../visualizations/FurnitureVisualization.ts | 14 +- src/objects/rooms/objects/index.ts | 3 + src/objects/rooms/parts/RoomPart.ts | 2 +- src/objects/rooms/parts/floor/CursorPart.ts | 27 +- src/objects/rooms/parts/floor/StairPart.ts | 364 ++++++++---------- src/objects/rooms/parts/floor/TilePart.ts | 68 ++-- src/objects/rooms/parts/index.ts | 1 + src/objects/rooms/parts/wall/DoorPart.ts | 18 +- src/objects/rooms/parts/wall/WallPart.ts | 56 ++- .../parts/wall/landscapes/LandscapePart.ts | 24 +- .../wall/landscapes/layers/LandscapeLayer.ts | 7 +- src/types/Mesh.ts | 12 +- src/types/index.ts | 5 + src/utils/Assets.ts | 3 +- src/utils/index.ts | 3 + tsconfig.json | 4 +- tsup.config.ts | 23 +- 51 files changed, 658 insertions(+), 853 deletions(-) create mode 100644 public/assets/dev.ts rename vite.config.js => public/vite.config.js (74%) create mode 100644 src/entities/index.ts create mode 100644 src/enums/index.ts create mode 100644 src/objects/events/index.ts create mode 100644 src/objects/filters/index.ts create mode 100644 src/objects/index.ts create mode 100644 src/objects/parsers/index.ts create mode 100644 src/objects/rooms/RoomPreview.ts create mode 100644 src/objects/rooms/geometry/index.ts create mode 100644 src/objects/rooms/index.ts create mode 100644 src/objects/rooms/layers/index.ts create mode 100644 src/objects/rooms/materials/index.ts create mode 100644 src/objects/rooms/objects/index.ts create mode 100644 src/objects/rooms/parts/index.ts create mode 100644 src/types/index.ts create mode 100644 src/utils/index.ts diff --git a/.gitignore b/.gitignore index 8e8231ba..1dd8bcd6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,7 @@ -node_modules/* -yarn-error.log -yarn.lock - -.idea/* - -.cache/* -dist/* -.parcel-cache/* -.proxyrc.js -git -.npmrc +node_modules +dist +.vscode +.idea .DS_Store +.npmrc + diff --git a/package.json b/package.json index f79bf331..286a5a3f 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,12 @@ "dist/*" ], "scripts": { - "dev": "vite --host", "build": "tsup", - "preview": "vite preview", + "dev": "vite serve public", + "preview": "vite preview public", + "build:production": "vite build public", "lint": "eslint --fix . --ignore-path .gitignore --ext .js,.ts src", - "format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|json)\"" + "format": "prettier --ignore-path .gitignore --write \"**/*.+(ts|html|css)\"" }, "dependencies": { "@pixi/layers": "^2.1.0", diff --git a/public/assets/dev.ts b/public/assets/dev.ts new file mode 100644 index 00000000..d2e04132 --- /dev/null +++ b/public/assets/dev.ts @@ -0,0 +1,22 @@ +// HMR +// https://stackoverflow.com/questions/71743027/how-to-use-vite-hmr-api-with-pixi-js +/* if (import.meta.hot) { + import.meta.hot.accept((): void => { + room.destroy(); + }); +} */ + +import { StatsJSAdapter, addStats } from 'pixi-stats'; +import { renderer } from './main'; +import { Ticker, UPDATE_PRIORITY } from 'pixi.js'; + +setTimeout(() => { + // Pixi stats + const stats: StatsJSAdapter = addStats(document, renderer.application); + const ticker: Ticker = Ticker.shared; + + ticker.add(stats.update, stats, UPDATE_PRIORITY.UTILITY); + + // Pixi devtools + globalThis.__PIXI_APP__ = renderer.application; +}, 1000); diff --git a/public/assets/main.ts b/public/assets/main.ts index 33e1217f..892ff2f6 100644 --- a/public/assets/main.ts +++ b/public/assets/main.ts @@ -3,108 +3,27 @@ import { Scuti } from '../../src/Scuti'; import { Room } from '../../src/objects/rooms/Room'; import { FloorMaterial } from '../../src/objects/rooms/materials/FloorMaterial'; import { WallMaterial } from '../../src/objects/rooms/materials/WallMaterial'; -import { TileEvent, WallEvent } from '../../src/entities/Events'; import { LandscapeMaterial } from '../../src'; -import { FloorFurniture } from '../../src/objects/rooms/objects/furnitures/FloorFurniture'; -import { benchmark } from '../../src/utils/Benchmark'; -import { perf } from '../../src/utils/Logger'; -import { WallFurniture } from '../../src/objects/rooms/objects/furnitures/WallFurniture'; -const renderer: Scuti = new Scuti({ - canvas: document.getElementById('app') as HTMLElement, - width: window.innerWidth, - height: window.innerHeight, +export const renderer: Scuti = new Scuti({ + canvas: document.getElementById('app')!, resources: 'http://127.0.0.1:8081', backgroundColor: 0x0c567c, - //backgroundColor: 0x000000, - zoom: { type: 'both', direction: 'cursor' }, + zoom: { direction: 'center' }, }); -// @ts-ignore await renderer.load(); const heightMap: string = ` -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -x100000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x002220000000000000004321111000000000000000000000000000000000000000000000000 -x001110000000000000000000001001000000000000000000000000000000000000000000000 -x000000000000000000000000001001000000000000000000000000000000000000000000000 -x000000000000000000000000001111000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x0xxx00x0x00xxx0xxx0x0x0xxx0xxx000000000000000000000000000000000000000000000 -x00x00x0x0x0x000x000x0x00x000x0000000000000000000000000000000000000000000000 -x00x00x000x0xxx0x000x0x00x000x0000000000000000000000000000000000000000000000 -x00x000x0x0000x0x000x0x00x000x0000000000000000000000000000000000000000000000 -x0xxx000x000xxx0xxx0xxx00x00xxx000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000xxxxxxxxxx00000000000000000000000000000000000000000 -x000000000000000000000000x00000000x00000000000000000000000000000000000000000 -x000000000000000000000000x00000000x00000000000000000000000000000000000000000 -x000000000000000000000000x00000000x00000000000000000000000000000000000000000 -x000000000000000000000000xxxxxxxxxx00000000000000000000000000000000000000000 -x000000000000000000000000000xxx000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 -x000000000000000000000000000000000000000000000000000000000000000000000000000 +x10012xxxxxxxxxx +x20000xxxxxxxxxx +000000xxx0000012 +0000000000022000 +x000000000001000 +x10003xxx0000000 +x10002xxx0000000 +x20001xxx1200000 +xxxxxxxxx0330000 `; const room: Room = new Room({ @@ -112,172 +31,12 @@ const room: Room = new Room({ dragging: true, centerCamera: true, floorMaterial: new FloorMaterial(101), - floorThickness: 16, + floorThickness: 8, + wallHidden: true, wallMaterial: new WallMaterial(108), wallThickness: 8, - wallHeight: 1, + wallHeight: -1, landscapeMaterial: new LandscapeMaterial(101), - zoom: { type: 'both' }, }); renderer.add(room); - -const wheel = new WallFurniture({ - id: 4010, - position: { - x: -1, - y: 1, - offsets: { - x: 7, - y: -25, - }, - }, - direction: 2, - state: 0, -}); -//room.add(wheel); - -const windowFurniture = new WallFurniture({ - id: 4054, - position: { - x: 1, - y: 1, - offsets: { - x: 0, - y: 0, - }, - }, - /*position: { - x: -1, - y: 1, - offsets: { - x: 7, - y: -25, - }, - },*/ - direction: 2, - state: 0, -}); - -const windowFurniture2 = new WallFurniture({ - //id: 4039, - id: 4037, - position: { - x: 0, - y: 5, - offsets: { - x: 5, - y: 43, - }, - }, - direction: 2, - state: 0, -}); - -const windowFurniture3 = new WallFurniture({ - id: 4037, - position: { - x: 4, - y: 0, - offsets: { - x: 7, - y: 57, - }, - }, - direction: 4, - state: 0, -}); - -/*setTimeout(() => { - wheel2.state = 2; -}, 1000);*/ -room.add(windowFurniture); -room.add(windowFurniture2); -room.add(windowFurniture3); - -/*room.events.tiles.onPointerMove = (event: TileEvent) => { - windowFurniture.position = { - x: event.position.x - 1, - y: event.position.y - 3, - offsets: { x: -7, y: -event.position.z * 16 }, - }; -}; - -room.events.walls.onPointerMove = (event: WallEvent) => { - //console.log(event.position); - windowFurniture.position = event.position; - //windowFurniture2.position = event.position; - - windowFurniture3.position = event.position; - - if (event.direction === 6) { - windowFurniture3.direction = 2; - } else if (event.direction === 0) { - windowFurniture3.direction = 4; - } -}; - -setTimeout(() => { - room.destroy(); -}, 10000); - -setTimeout(() => { - room.render(); - room.add(windowFurniture); - room.add(windowFurniture2); - room.add(windowFurniture3); - - setInterval(() => { - room.floorMaterial = new FloorMaterial(Math.floor(Math.random() * (111 - 101 + 1) + 101)); - room.wallMaterial = new FloorMaterial(Math.floor(Math.random() * (111 - 101 + 1) + 101)); - room.floorThickness = Math.floor(Math.random() * (32 - 8 + 1) + 8); - room.wallThickness = Math.floor(Math.random() * (32 - 8 + 1) + 8); - }, 2000); - - setTimeout(() => { - room.wallHidden = true; - }, 5000); - - setTimeout(() => { - room.wallHidden = false; - }, 7000); - - setTimeout(() => { - room.heightMap = ` -xxxxxx -x00000 -x00000 -102222 -x01111 -x00000 -x00000 -x00000 -x00000 - `; - }, 9000); - - room.events.walls.onPointerMove = (event: WallEvent) => { - console.log(event.position); - windowFurniture.position = event.position; - }; -}, 13000); -*/ -/*let size = 10; -for (let x = 0; x < size; x++) { - for (let y = 0; y < 20; y++) { - for (let z = 0; z < size; z++) { - const dragon = new FloorFurniture({ - id: 8213, - position: { - x: x, - y: y, - z: z, - }, - direction: 2, - state: 1, - }); - room.add(dragon); - } - } -} -*/ diff --git a/public/assets/style.css b/public/assets/style.css index 8a42b879..b9323b35 100644 --- a/public/assets/style.css +++ b/public/assets/style.css @@ -14,3 +14,11 @@ div#stats { opacity: 0.8; user-select: none; } + +#preview { + position: fixed; + inset: 0; + width: 600px; + height: 250px; + overflow: auto; +} diff --git a/public/index.html b/public/index.html index 8ef5e5a9..40be0fe2 100644 --- a/public/index.html +++ b/public/index.html @@ -1,13 +1,15 @@ + Vite + TS - - Vite + TS + + -
- +
+
+
diff --git a/vite.config.js b/public/vite.config.js similarity index 74% rename from vite.config.js rename to public/vite.config.js index ab6e49f7..2fdc7a24 100644 --- a/vite.config.js +++ b/public/vite.config.js @@ -2,4 +2,5 @@ import { defineConfig } from 'vite'; export default defineConfig({ root: 'public', + build: { target: 'esnext' }, }); diff --git a/src/Scuti.ts b/src/Scuti.ts index 31cde9a5..71bc58e7 100644 --- a/src/Scuti.ts +++ b/src/Scuti.ts @@ -5,7 +5,7 @@ import { Layer, Stage } from '@pixi/layers'; import { addStats, StatsJSAdapter } from 'pixi-stats'; import { Configuration, ScutiConfiguration } from './ScutiConfiguration'; import { loadBundle } from './objects/parsers/BundleParser'; -import { log, perf } from './utils/Logger'; +import { log } from './utils/Logger'; import { benchmark } from './utils/Benchmark'; import { loadData } from './objects/parsers/DataParser'; import { ScutiData } from './ScutiData'; @@ -25,7 +25,7 @@ export class Scuti { } private _initialize(): void { - benchmark('renderer'); + const { perf } = benchmark('renderer'); // Pixi settings extensions.add(loadBundle); extensions.add(loadData); @@ -46,7 +46,7 @@ export class Scuti { eventMode: 'passive', }); this.application.stage = new Stage(); - globalThis.__PIXI_APP__ = this.application; // Support for PIXI.js dev-tool. + globalThis.__PIXI_APP__ = this.application; // Pixi dev-tools this.canvas = this.configuration.canvas; this.canvas.append(this.application.view as HTMLCanvasElement); @@ -58,11 +58,12 @@ export class Scuti { this.layer.group.enableSort = true; this.application.stage.addChild(this.layer); - perf('Renderer', 'renderer'); + + perf(); } public async load(): Promise { - benchmark('resources'); + const { perf } = benchmark('resources'); await Promise.all([ register('room/materials', '/bundles/room/materials.bundle'), @@ -72,7 +73,7 @@ export class Scuti { this.data = new ScutiData(); - perf('Resources', 'resources'); + perf(); } public add(item: GameObject): void { diff --git a/src/ScutiConfiguration.ts b/src/ScutiConfiguration.ts index 0192204c..0d384602 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -4,10 +4,10 @@ import { registerPath } from './utils/Assets'; export interface Configuration { renderer: Scuti; - canvas: HTMLElement; - width: number; - height: number; resources: string; + canvas: HTMLElement; + width?: number; + height?: number; backgroundColor?: number; backgroundAlpha?: number; resizeTo?: HTMLElement | Window; @@ -39,12 +39,12 @@ export class ScutiConfiguration { this.renderer = renderer; this._canvas = canvas; - this._width = width; - this._height = height; + this._width = width ?? window.innerWidth; + this._height = height ?? window.innerHeight; this._backgroundColor = backgroundColor ?? 0x000000; this._backgroundAlpha = backgroundAlpha ?? 1; this._resizeTo = resizeTo ?? window; - this._zoom = { wheel: true, level: 1, min: 0.5, max: 3, step: 0.5, duration: 0.125, direction: 'center', ...zoom }; + this._zoom = { wheel: true, level: 2, min: 0.5, max: 8, step: 0.5, duration: 0.125, direction: 'center', ...zoom }; registerPath(resources); } diff --git a/src/entities/index.ts b/src/entities/index.ts new file mode 100644 index 00000000..e162ea91 --- /dev/null +++ b/src/entities/index.ts @@ -0,0 +1 @@ +export * from './Events'; diff --git a/src/enums/StairType.ts b/src/enums/StairType.ts index c574c16a..b5e01505 100644 --- a/src/enums/StairType.ts +++ b/src/enums/StairType.ts @@ -2,4 +2,5 @@ export enum StairType { STAIR, INNER_CORNER_STAIR, OUTER_CORNER_STAIR, + TWIN_CORNER_STAIR, } diff --git a/src/enums/index.ts b/src/enums/index.ts new file mode 100644 index 00000000..6fb26780 --- /dev/null +++ b/src/enums/index.ts @@ -0,0 +1,4 @@ +export * from './CubeFace'; +export * from './Direction'; +export * from './WallType'; +export * from './StairType'; diff --git a/src/index.ts b/src/index.ts index 72d5bd40..73b95fb0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,7 @@ export * from './Scuti'; -export * from './objects/rooms/Room'; -export * from './objects/rooms/RoomCamera'; -export * from './objects/rooms/RoomVisualization'; -export * from './objects/rooms/RoomEvents'; -export * from './objects/GameObject'; -export * from './utils/Assets'; -export * from './objects/events/EventManager'; -export * from './objects/rooms/materials/FloorMaterial'; -export * from './objects/rooms/materials/WallMaterial'; -export * from './objects/rooms/materials/RoomMaterial'; -export * from './objects/rooms/materials/LandscapeMaterial'; +export * from './objects'; +export * from './entities'; +export * from './enums'; +export * from './types'; +export * from './utils'; diff --git a/src/objects/events/index.ts b/src/objects/events/index.ts new file mode 100644 index 00000000..0f43ab15 --- /dev/null +++ b/src/objects/events/index.ts @@ -0,0 +1 @@ +export * from './EventManager'; diff --git a/src/objects/filters/index.ts b/src/objects/filters/index.ts new file mode 100644 index 00000000..481cba83 --- /dev/null +++ b/src/objects/filters/index.ts @@ -0,0 +1,2 @@ +export * from './BlackSpriteMaskFilter'; +export * from './ReverseSpriteMaskFilter'; diff --git a/src/objects/index.ts b/src/objects/index.ts new file mode 100644 index 00000000..e2c09185 --- /dev/null +++ b/src/objects/index.ts @@ -0,0 +1,6 @@ +export * from './GameObject'; + +export * from './events'; +export * from './filters'; +export * from './parsers'; +export * from './rooms'; diff --git a/src/objects/parsers/index.ts b/src/objects/parsers/index.ts new file mode 100644 index 00000000..712db6a9 --- /dev/null +++ b/src/objects/parsers/index.ts @@ -0,0 +1,3 @@ +export * from './BundleParser'; +export * from './DataParser'; +export * from './Parser'; diff --git a/src/objects/rooms/Room.ts b/src/objects/rooms/Room.ts index 42b11786..49334406 100644 --- a/src/objects/rooms/Room.ts +++ b/src/objects/rooms/Room.ts @@ -5,9 +5,10 @@ import { GameObject } from '../GameObject'; import { RoomHeightmap } from './RoomHeightmap'; import { RoomEvents } from './RoomEvents'; import { RoomObject } from './objects/RoomObject'; -import { FloorMaterial } from './materials/FloorMaterial.ts'; -import { WallMaterial } from './materials/WallMaterial.ts'; -import { LandscapeMaterial } from './materials/LandscapeMaterial.ts'; +import { FloorMaterial } from './materials/FloorMaterial'; +import { WallMaterial } from './materials/WallMaterial'; +import { LandscapeMaterial } from './materials/LandscapeMaterial'; +import { RoomPreview } from './RoomPreview'; interface Configuration { heightMap: string; @@ -21,15 +22,15 @@ interface Configuration { landscapeMaterial?: LandscapeMaterial; dragging?: boolean; centerCamera?: boolean; - zoom?: number; } export class Room extends GameObject { public renderer!: Scuti; public parsedHeightMap!: RoomHeightmap; - public visualization!: RoomVisualization; - public camera!: RoomCamera; + public visualization: RoomVisualization | undefined; + public camera: RoomCamera | undefined; public events!: RoomEvents; + public previewme!: RoomPreview; private _heightMap: string; private _floorMaterial: FloorMaterial; @@ -42,7 +43,6 @@ export class Room extends GameObject { private _landscapeMaterial: LandscapeMaterial; private _dragging: boolean; private _centerCamera: boolean; - private _zoom: number; constructor({ heightMap, @@ -56,7 +56,6 @@ export class Room extends GameObject { landscapeMaterial, dragging, centerCamera, - zoom, }: Configuration) { super(); @@ -71,7 +70,6 @@ export class Room extends GameObject { this._landscapeMaterial = landscapeMaterial ?? new LandscapeMaterial(101); this._dragging = dragging ?? true; this._centerCamera = centerCamera ?? true; - this._zoom = zoom ?? 1; this._floorMaterial.room = this; this._wallMaterial.room = this; @@ -85,24 +83,33 @@ export class Room extends GameObject { //this.renderer.application.ticker.maxFPS = 144; todo(): Add configurable FPS this.visualization.render(); - this.renderer.application.stage.addChild(this.camera); + this.renderer.application.stage.addChild(this.camera.container!); } public update({ parts, objects, cursor, mesher }: UpdateConfiguration): void { if (parts) this.parsedHeightMap = new RoomHeightmap(this.heightMap); - this.visualization.update({ parts, objects, cursor, mesher }); + this.visualization?.update({ parts, objects, cursor, mesher }); } public destroy(): void { - if (this.visualization !== undefined) { - this.visualization.destroy(true, true, true); - this.visualization = undefined as any; + if (this.visualization != undefined) { + this.visualization.destroy({ parts: true, objects: true, cursor: true }); + this.visualization = undefined; } + + if (this.camera != undefined) { + this.camera.destroy(); + this.camera = undefined; + } + } + + public preview(canvas: HTMLElement): void { + this.previewme = new RoomPreview({ canvas, heightMap: this._heightMap }); } public add(object: RoomObject): void { - this.visualization.add(object); + this.visualization?.add(object); } public get heightMap(): string { @@ -226,12 +233,4 @@ export class Room extends GameObject { public set centerCamera(centerCamera: boolean) { this._centerCamera = centerCamera; } - - public get zoom(): number { - return this._zoom; - } - - public set zoom(zoom: number) { - this._zoom = zoom; - } } diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index f29e6901..75865d93 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -2,7 +2,9 @@ import { Room } from './Room'; import { Container, Matrix, Point, RenderTexture } from 'pixi.js'; import { gsap } from 'gsap'; -export class RoomCamera extends Container { +export class RoomCamera { + public container: Container | undefined = new Container(); + public zooming: boolean = false; public dragging: boolean = false; public hasDragged: boolean = false; @@ -11,15 +13,12 @@ export class RoomCamera extends Container { private _clickThreshold: number = 100; constructor(public room: Room) { - super(); - - this._initializeListeners(); - - this.addChild(room.visualization.container); + this._initListeners(); + this.container!.addChild(room.visualization!.container); } // todo(): removeEventListener when destroying containers - private _initializeListeners(): void { + private _initListeners(): void { const events = this.room.renderer.application.renderer.events.domElement; if (this.room.renderer.configuration.zoom?.wheel) { @@ -33,6 +32,20 @@ export class RoomCamera extends Container { } } + private unBindListeners(): void { + const events = this.room.renderer.application.renderer.events.domElement; + + if (this.room.renderer.configuration.zoom?.wheel) { + events.removeEventListener('wheel', this._onZoom); + } + + if (this.room.dragging) { + events.removeEventListener('pointerdown', this._dragStart); + events.removeEventListener('pointerup', this._dragEnd); + events.removeEventListener('pointermove', this._dragMove); + } + } + private _onZoom = (event: WheelEvent): void => { const zoom = this.room.renderer.configuration.zoom!; const { step, level, min, max } = zoom; @@ -61,30 +74,35 @@ export class RoomCamera extends Container { private _dragMove = (event: PointerEvent): void => { if (this.dragging) { this.hasDragged = true; - this.pivot.x -= event.movementX / (this.scale.x * devicePixelRatio); - this.pivot.y -= event.movementY / (this.scale.y * devicePixelRatio); + this.container!.pivot.x -= event.movementX / (this.container!.scale.x * devicePixelRatio); + this.container!.pivot.y -= event.movementY / (this.container!.scale.y * devicePixelRatio); } }; public isOutOfBounds(): boolean { - const { x, y } = this.pivot; + const { x, y } = this.container!.pivot; const { width, height } = this.room.renderer.application.view; - const { x: scaleX, y: scaleY } = { x: this.scale.x * devicePixelRatio, y: this.scale.y * devicePixelRatio }; + const { x: scaleX, y: scaleY } = { x: this.container!.scale.x * devicePixelRatio, y: this.container!.scale.y * devicePixelRatio }; const { width: scaledWidth, height: scaledHeight } = { width: width / scaleX / 2, height: height / scaleY / 2 }; - return x - scaledWidth > this.width / scaleX || x + scaledWidth < 0 || y - scaledHeight > this.height / scaleY || y + scaledHeight < 0; + return ( + x - scaledWidth > this.container!.width / scaleX || + x + scaledWidth < 0 || + y - scaledHeight > this.container!.height / scaleY || + y + scaledHeight < 0 + ); } public centerCamera(duration: number = 0.6): void { - gsap.to(this, { + gsap.to(this.container!, { x: Math.floor(this.room.renderer.application.view.width / 2), y: Math.floor(this.room.renderer.application.view.height / 2), duration, ease: 'expo.inOut', }); - gsap.to(this.pivot, { - x: Math.floor(this.width / this.scale.x / 2), - y: Math.floor(this.height / this.scale.y / 2), + gsap.to(this.container!.pivot, { + x: Math.floor(this.container!.width / this.container!.scale.x / 2), + y: Math.floor(this.container!.height / this.container!.scale.y / 2), duration, ease: 'expo.inOut', }); @@ -106,16 +124,16 @@ export class RoomCamera extends Container { if (this.room.renderer.configuration.zoom?.direction === 'cursor') { const pointer = Object.assign({}, this.room.renderer.application.renderer.events.pointer.global); - const { x: x1, y: y1 } = this.toLocal(pointer); + const { x: x1, y: y1 } = this.container!.toLocal(pointer); options.onUpdate = () => { - const { x: x2, y: y2 } = this.toLocal(pointer); - this.pivot.x += x1 - x2; - this.pivot.y += y1 - y2; + const { x: x2, y: y2 } = this.container!.toLocal(pointer); + this.container!.pivot.x += x1 - x2; + this.container!.pivot.y += y1 - y2; }; } - gsap.to(this.scale, options); + gsap.to(this.container!.scale, options); } public async screenshot(target: HTMLElement): Promise { @@ -132,4 +150,11 @@ export class RoomCamera extends Container { return await renderer.extract.base64(renderTexture); } + + public destroy(): void { + if (this.container != undefined) { + this.container.destroy(); + this.unBindListeners(); + } + } } diff --git a/src/objects/rooms/RoomHeightmap.ts b/src/objects/rooms/RoomHeightmap.ts index 8b99fb26..42dff22d 100644 --- a/src/objects/rooms/RoomHeightmap.ts +++ b/src/objects/rooms/RoomHeightmap.ts @@ -9,21 +9,9 @@ export class RoomHeightmap { public heightMap: HeightMap; public door: Vector2D | undefined; - private stairMap: Map> = new Map(); - constructor(heightMap: string) { this.heightMap = RoomHeightmap.parse(heightMap); - - for (let y: number = 0; y < this.heightMap.length; y++) { - for (let x: number = 0; x < this.heightMap[y].length; x++) { - // Pre-compute stairs for later use - this.stairMap.set(`${x}-${y}`, this.getStair({ x, y })); - - if (this.door === undefined && this.isEntrance({ x, y })) { - this.door = { x, y }; - } - } - } + this.door = this.calculateDoor(); } public static parse(heightMap: string): HeightMap { @@ -80,7 +68,7 @@ export class RoomHeightmap { return this.getTileHeight(position1) - this.getTileHeight(position2); } - public getStair({ x, y }: Vector2D): Stair | undefined { + public getStair({ x, y }: Vector2D, axis?: 'x' | 'y'): Stair | undefined { if (!this.isTile({ x, y })) return undefined; const topLeftTile: Vector2D = { x: x - 1, y: y - 1 }; @@ -130,9 +118,9 @@ export class RoomHeightmap { if ( this.isTile(topLeftTile) && - this.getTileHeightDiff(topLeftTile, { x, y }) === 1 && - this.getTileHeightDiff(midLeftTile, { x, y }) === 1 && - this.getTileHeightDiff(topTile, { x, y }) === 1 + this.getTileHeightDiff(topLeftTile, { x, y }) >= 1 && + this.getTileHeightDiff(midLeftTile, { x, y }) >= 1 && + this.getTileHeightDiff(topTile, { x, y }) >= 1 ) return { type: StairType.INNER_CORNER_STAIR, @@ -142,18 +130,32 @@ export class RoomHeightmap { if (this.isTile(topTile) && this.getTileHeightDiff(topTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.NORTH }; - if ( + const IS_NORTH_EAST_STAIR = (): boolean => this.isTile(topRightTile) && this.getTileHeightDiff(topRightTile, midTile) === 1 && this.getTileHeightDiff(midRightTile, midTile) !== 1 && - this.getTileHeightDiff(topTile, midTile) !== 1 - ) { + this.getTileHeightDiff(topTile, midTile) !== 1; + + const IS_SOUTH_WEST_STAIR = (): boolean => + this.isTile(botLeftTile) && + !this.isEntrance(botLeftTile) && + this.getTileHeightDiff(botLeftTile, midTile) === 1 && + this.getTileHeightDiff(midLeftTile, midTile) !== 1 && + this.getTileHeightDiff(botTile, midTile) !== 1; + + if (IS_NORTH_EAST_STAIR()) { if (this.getTileHeightDiff(midLeftTile, midTile) === 1) return { type: StairType.INNER_CORNER_STAIR, direction: Direction.NORTH_EAST, }; + if (IS_SOUTH_WEST_STAIR()) + return { + type: StairType.TWIN_CORNER_STAIR, + direction: axis === 'x' ? Direction.NORTH_EAST : Direction.SOUTH_WEST, + }; + return { type: StairType.OUTER_CORNER_STAIR, direction: Direction.NORTH_EAST, @@ -177,12 +179,7 @@ export class RoomHeightmap { if (this.isTile(botTile) && this.getTileHeightDiff(botTile, midTile) === 1) return { type: StairType.STAIR, direction: Direction.SOUTH }; - if ( - this.isTile(botLeftTile) && - this.getTileHeightDiff(botLeftTile, midTile) === 1 && - this.getTileHeightDiff(midLeftTile, midTile) !== 1 && - this.getTileHeightDiff(botTile, midTile) !== 1 - ) + if (IS_SOUTH_WEST_STAIR()) return { type: StairType.OUTER_CORNER_STAIR, direction: Direction.SOUTH_WEST, @@ -205,10 +202,6 @@ export class RoomHeightmap { return undefined; } - public getComputedStair({ x, y }: Parameters[number]): ReturnType { - return this.stairMap.get(`${x}-${y}`) ?? this.getStair({ x, y }); - } - public getWall({ x, y }: Vector2D): WallType | undefined { if (!this.isTile({ x, y }) || this.isDoor({ x, y })) return; @@ -252,7 +245,7 @@ export class RoomHeightmap { } public get sizeX(): number { - return this.heightMap.sort((a, b) => b.length - a.length)[0].length; + return this.heightMap.sort((a, b): number => b.length - a.length)[0].length; } public get sizeY(): number { diff --git a/src/objects/rooms/RoomPreview.ts b/src/objects/rooms/RoomPreview.ts new file mode 100644 index 00000000..63583fcb --- /dev/null +++ b/src/objects/rooms/RoomPreview.ts @@ -0,0 +1,20 @@ +import { Application } from 'pixi.js'; + +interface Configuration { + canvas: HTMLElement; + heightMap: string; +} + +export class RoomPreview { + private _canvas: Configuration['canvas']; + private _application: Application; + + constructor(configuration: Configuration) { + this._application = new Application({ + backgroundColor: 0x000000, + }); + + this._canvas = configuration.canvas; + this._canvas.append(this._application.view as HTMLCanvasElement); + } +} diff --git a/src/objects/rooms/RoomVisualization.ts b/src/objects/rooms/RoomVisualization.ts index 4b9f2faa..a3d0efec 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -7,24 +7,23 @@ import { StairPart } from './parts/floor/StairPart'; import { GreedyMesher } from './geometry/GreedyMesher'; import { TileEvent, WallEvent } from '../../entities/Events'; import { CursorPart } from './parts/floor/CursorPart'; -import { StairMesh, TileMesh, WallMesh } from '../../types/Mesh'; +import { StairMesh, TileMesh, WallMesh, Vector3D } from '../../types'; import { WallPart } from './parts/wall/WallPart'; import { benchmark } from '../../utils/Benchmark'; -import { perf } from '../../utils/Logger'; import { LandscapePart } from './parts/wall/landscapes/LandscapePart'; import { DoorPart } from './parts/wall/DoorPart'; import { MaskLayer } from './layers/MaskLayer'; import { LandscapeWindowMask } from './parts/wall/landscapes/layers/items/LandscapeWindowMask'; import { RoomObject } from './objects/RoomObject'; -import { Vector3D } from '../../types/Vector'; import { ObjectLayer } from './layers/ObjectLayer'; -import { landscapeOrder } from '../../utils/Sorting'; +import { landscapeOrder } from '../../utils'; +import { Direction, StairType } from '../..'; -type RoomLayers = { +interface RoomLayers { parts: PartLayer; masks: MaskLayer; objects: ObjectLayer; -}; +} export interface UpdateConfiguration { parts?: boolean; @@ -35,7 +34,7 @@ export interface UpdateConfiguration { export class RoomVisualization { public container: Container = new Container(); - public layers: RoomLayers = {} as RoomLayers; + public layers = {} as RoomLayers; public furnituresTicker!: Ticker; public greedyMesher!: GreedyMesher; @@ -65,11 +64,11 @@ export class RoomVisualization { } private _registerCursor(): void { - const cursor = new CursorPart({}); + const cursor = new CursorPart(); this.layers.parts.cursor = cursor; cursor.room = this.room; cursor.render(); - this.container.addChild(cursor.container); + this.container.addChild(cursor.container!); cursor.hide(); } @@ -139,7 +138,7 @@ export class RoomVisualization { } public render(): void { - benchmark('room-visualization'); + const { perf } = benchmark('room-visualization'); this._registerCursor(); this._registerDoor(); @@ -150,18 +149,44 @@ export class RoomVisualization { this.renderWalls(); if (this.layers.masks.childrens.length > 0) this.renderLandscapes(); - perf('Room Visualization', 'room-visualization'); + perf(); // Resets room position to the top-left corner by default this.container.pivot.x = this.container.getBounds().left; this.container.pivot.y = this.container.getBounds().top; - this.room.camera.centerCamera(0); + this.room.camera!.centerCamera(0); } public renderFloors(): void { - if (!this.room.floorHidden) { - this.greedyMesher.tiles.forEach((tile: TileMesh, index: number): void => + const stair = new StairPart({ + material: this.room.floorMaterial, + position: { x: 0, y: 0, z: 0 }, + length: 1, + thickness: this.room.floorThickness, + direction: Direction.WEST, + corners: { + left: StairType.STAIR, + right: StairType.TWIN_CORNER_STAIR, + }, + }); + + const stair2 = new StairPart({ + material: this.room.floorMaterial, + position: { x: 0, y: 0, z: 0 }, + length: 1, + thickness: this.room.floorThickness, + direction: Direction.NORTH, + corners: { + left: StairType.TWIN_CORNER_STAIR, + right: StairType.STAIR, + }, + }); + + [stair, stair2].forEach(stair => this.add(stair)); + + /* if (!this.room.floorHidden) { + this.greedyMesher.tiles.forEach((tile: TileMesh): void => this._registerFloorPart( new TilePart({ material: this.room.floorMaterial, @@ -185,7 +210,7 @@ export class RoomVisualization { }), ), ); - } + } */ } public renderWalls(): void { @@ -222,7 +247,7 @@ export class RoomVisualization { } public update({ parts, objects, cursor, mesher }: UpdateConfiguration): void { - this.destroy(parts, objects, cursor); + this.destroy({ parts, objects, cursor }); if (mesher) this.greedyMesher = new GreedyMesher(this.room.parsedHeightMap); @@ -236,29 +261,35 @@ export class RoomVisualization { } } - public destroy(parts = false, objects = false, cursor = false): void { + public destroy({ parts, objects, cursor }: Omit): void { if (cursor) { - this.layers.parts.cursor.destroy(); - this.layers.parts.cursor = undefined as any; + this.layers.parts.cursor?.destroy(); + this.layers.parts.cursor = undefined; } if (parts) { - this.layers.parts.door.destroy(); - [...this.layers.parts.childrens].forEach((item: RoomPart) => { + this.layers.parts.door?.destroy(); + this.layers.parts.door = undefined; + console.log(this.layers.parts); + + [...this.layers.parts.childrens].forEach((item: RoomPart): void => { item.destroy(); this.layers.parts.remove(item); }); + + console.log(this.layers.parts); } if (objects) { - [...this.layers.masks.childrens].forEach((item: LandscapeWindowMask) => { + [...this.layers.masks.childrens].forEach((item: LandscapeWindowMask): void => { item.destroy(); this.layers.masks.remove(item); }); - [...this.layers.objects.childrens].forEach((item: RoomObject) => { + [...this.layers.objects.childrens].forEach((item: RoomObject): void => { item.destroy(); this.layers.objects.remove(item); }); + this.layers.masks.destroy(); } } @@ -266,7 +297,7 @@ export class RoomVisualization { public add(item: RoomPart | RoomObject): void { if (item instanceof RoomPart) { this.layers.parts.add(item); - this.container.addChild(item.container); + this.container.addChild(item.container!); } if (item instanceof RoomObject) { diff --git a/src/objects/rooms/geometry/Cube.ts b/src/objects/rooms/geometry/Cube.ts index e56118f1..d9246a3d 100644 --- a/src/objects/rooms/geometry/Cube.ts +++ b/src/objects/rooms/geometry/Cube.ts @@ -15,6 +15,7 @@ interface Configuration { export class Cube extends Container { public faces: Record = {}; + constructor(public configuration: Configuration) { super(); diff --git a/src/objects/rooms/geometry/GreedyMesher.ts b/src/objects/rooms/geometry/GreedyMesher.ts index 892fad0c..6bac8445 100644 --- a/src/objects/rooms/geometry/GreedyMesher.ts +++ b/src/objects/rooms/geometry/GreedyMesher.ts @@ -1,10 +1,7 @@ import { RoomHeightmap } from '../RoomHeightmap'; -import { Vector2D, Vector3D } from '../../../types/Vector'; -import { Stair } from '../../../types/Stair'; -import { StairType } from '../../../enums/StairType'; -import { Direction } from '../../../enums/Direction'; -import { StairMesh, TileMesh, WallMesh } from '../../../types/Mesh'; -import { WallType } from '../../../enums/WallType'; +import { Vector2D, Vector3D, Stair } from '../../../types'; +import { Direction, WallType, StairType } from '../../../enums'; +import { StairMesh, TileMesh, WallMesh } from '../../../types'; export class GreedyMesher { constructor(public heightMap: RoomHeightmap) {} @@ -81,25 +78,18 @@ export class GreedyMesher { for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { rowStairSizes[y] = {}; columnStairSizes[y] = {}; + for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { const stair: Stair | undefined = this.heightMap.getStair({ x, y }); if (!stair) continue; - if (stair.directions.includes(Direction.NORTH) || stair.directions.includes(Direction.SOUTH)) { - rowStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else if (stair.directions.includes(Direction.WEST) || stair.directions.includes(Direction.EAST)) { - columnStairSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - } else { - const z = this.heightMap.getTileHeight({ x, y }); + const z = this.heightMap.getTileHeight({ x, y }); + if (stair.direction === Direction.NORTH || stair.direction === Direction.SOUTH) { + rowStairSizes[y][x] = { x: 1, y: 1, z: z }; + } else if (stair.direction === Direction.WEST || stair.direction === Direction.EAST) { + columnStairSizes[y][x] = { x: 1, y: 1, z: z }; + } else { rowStairSizes[y][x] = { x: 1, y: 1, z: z }; columnStairSizes[y][x] = { x: 1, y: 1, z: z }; } @@ -108,13 +98,17 @@ export class GreedyMesher { for (let y: number = 0; y < this.heightMap.heightMap.length; y++) { for (let x: number = 1; x <= this.heightMap.heightMap[y].length; x++) { - const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }); - const stair: Stair | undefined = this.heightMap.getStair({ x: x - 1, y }); + const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }, 'x'); + const stair: Stair | undefined = this.heightMap.getStair({ x: x - 1, y }, 'x'); if (!stair || !currentStair) continue; - if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x: x - 1, y: y })) { - if (stair.directions.includes(Direction.NORTH) || stair.directions.includes(Direction.SOUTH) || stair.type !== StairType.STAIR) { - if (!(stair.type === currentStair.type && !currentStair.directions.includes(stair.directions[0]))) { + if ([Direction.NORTH, Direction.SOUTH].includes(stair.direction) || stair.type !== StairType.STAIR) { + if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x: x - 1, y })) { + if ( + (stair.type !== currentStair.type || stair.direction === currentStair.direction) && + stair.type !== StairType.TWIN_CORNER_STAIR && + currentStair.type !== StairType.TWIN_CORNER_STAIR + ) { if (rowStairSizes[y][x] && rowStairSizes[y][x - 1]) { if (rowStairSizes[y][x]?.y === rowStairSizes[y][x - 1]?.y) { rowStairSizes[y][x]!.x += rowStairSizes[y][x - 1]!.x; @@ -129,13 +123,18 @@ export class GreedyMesher { for (let y: number = 1; y < this.heightMap.heightMap.length; y++) { for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { - const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }); - const stair: Stair | undefined = this.heightMap.getStair({ x, y: y - 1 }); + const currentStair: Stair | undefined = this.heightMap.getStair({ x, y }, 'y'); + const stair: Stair | undefined = this.heightMap.getStair({ x, y: y - 1 }, 'y'); if (!stair || !currentStair) continue; - if (!(currentStair.directions.length >= 2)) { + console.log(stair, currentStair); + if ([Direction.WEST, Direction.EAST].includes(stair.direction) || stair.type !== StairType.STAIR) { if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x, y: y - 1 })) { - if (!(stair.type === currentStair.type && !currentStair.directions.includes(stair.directions[0]))) { + if ( + (stair.type !== currentStair.type || stair.direction === currentStair.direction) && + stair.type !== StairType.TWIN_CORNER_STAIR && + currentStair.type !== StairType.TWIN_CORNER_STAIR + ) { if (columnStairSizes[y][x] && columnStairSizes[y - 1][x]) { if (columnStairSizes[y][x]?.x === columnStairSizes[y - 1][x]?.x) { columnStairSizes[y][x]!.y += columnStairSizes[y - 1][x]!.y; @@ -150,32 +149,22 @@ export class GreedyMesher { for (const [y, row] of Object.entries(rowStairSizes)) { for (const [x, size] of Object.entries(row)) { - const stair: Stair = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - })!; + const stair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y) }, 'x')!; if (size) { - let directions: Direction[] = stair.directions; - - if (directions.includes(Direction.NORTH_WEST) || directions.includes(Direction.NORTH_EAST)) directions = [Direction.NORTH]; - if (directions.includes(Direction.SOUTH_WEST) || directions.includes(Direction.SOUTH_EAST)) directions = [Direction.SOUTH]; + let direction: Direction = stair.direction; - const leftStair: Stair = this.heightMap.getStair({ - x: Number(x) - size.x + 1, - y: Number(y) - size.y + 1, - })!; + if (direction === Direction.NORTH_WEST || direction === Direction.NORTH_EAST) direction = Direction.NORTH; + if (direction === Direction.SOUTH_WEST || direction === Direction.SOUTH_EAST) direction = Direction.SOUTH; - const rightStair: Stair = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - })!; + const leftStair: Stair = this.heightMap.getStair({ x: Number(x) - size.x + 1, y: Number(y) - size.y + 1 }, 'x')!; + const rightStair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y) }, 'x')!; // Check if it's a tiny stair if (size.x === 1 && size.y === 1) { - if (leftStair.directions.includes(Direction.NORTH_EAST)) { + if (leftStair.direction === Direction.SOUTH_EAST || leftStair.direction === Direction.NORTH_EAST) { rightStair.type = StairType.STAIR; - } else if (leftStair.directions.includes(Direction.NORTH_WEST)) { + } else if (leftStair.direction === Direction.SOUTH_WEST || leftStair.direction === Direction.NORTH_WEST) { leftStair.type = StairType.STAIR; } } @@ -187,7 +176,7 @@ export class GreedyMesher { z: size.z, }, length: size.x, - direction: directions[0], + direction, corners: { left: leftStair.type, right: rightStair.type, @@ -199,32 +188,23 @@ export class GreedyMesher { for (const [y, column] of Object.entries(columnStairSizes)) { for (const [x, size] of Object.entries(column)) { - const stair: Stair = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - })!; + const stair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y) }, 'y')!; if (size) { - let directions: Direction[] = stair.directions; + let direction: Direction = stair.direction; - if (directions.includes(Direction.NORTH_WEST) || directions.includes(Direction.SOUTH_WEST)) directions = [Direction.WEST]; - if (directions.includes(Direction.SOUTH_EAST) || directions.includes(Direction.NORTH_EAST)) directions = [Direction.EAST]; + if (direction == Direction.NORTH_WEST || direction == Direction.SOUTH_WEST) direction = Direction.WEST; + if (direction == Direction.SOUTH_EAST || direction == Direction.NORTH_EAST) direction = Direction.EAST; - const leftStair: Stair = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - })!; - - const rightStair: Stair = this.heightMap.getStair({ - x: Number(x) - size.x + 1, - y: Number(y) - size.y + 1, - })!; + const leftStair: Stair = this.heightMap.getStair({ x: Number(x), y: Number(y) }, 'y')!; + const rightStair: Stair = this.heightMap.getStair({ x: Number(x) - size.x + 1, y: Number(y) - size.y + 1 }, 'y')!; // Check if it's a tiny stair if (size.x === 1 && size.y === 1) { - if (leftStair.directions.includes(Direction.NORTH_WEST)) { + // || leftStair.direction === Direction.NORTH_WEST + if (leftStair.direction === Direction.NORTH_EAST || leftStair.direction === Direction.NORTH_WEST) { rightStair.type = StairType.STAIR; - } else if (leftStair.directions.includes(Direction.SOUTH_WEST)) { + } else if (leftStair.direction === Direction.SOUTH_EAST || leftStair.direction === Direction.SOUTH_WEST) { leftStair.type = StairType.STAIR; } } @@ -236,7 +216,7 @@ export class GreedyMesher { z: size.z, }, length: size.y, - direction: directions[0], + direction, corners: { left: leftStair.type, right: rightStair.type, @@ -262,39 +242,22 @@ export class GreedyMesher { const wall: WallType | undefined = this.heightMap.getWall({ x, y }); if (wall === undefined) continue; + + const z = this.heightMap.getTileHeight({ x, y }); if (wall === WallType.RIGHT_WALL) { - rowWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; + rowWallSizes[y][x] = { x: 1, y: 1, z: z }; } else if (wall === WallType.LEFT_WALL) { - columnWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; + columnWallSizes[y][x] = { x: 1, y: 1, z: z }; } else if (wall === WallType.CORNER_WALL) { - rowWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; - columnWallSizes[y][x] = { - x: 1, - y: 1, - z: this.heightMap.getTileHeight({ x, y }), - }; + rowWallSizes[y][x] = { x: 1, y: 1, z: z }; + columnWallSizes[y][x] = { x: 1, y: 1, z: z }; } } } for (let y: number = 1; y < this.heightMap.heightMap.length; y++) { for (let x: number = 0; x < this.heightMap.heightMap[y].length; x++) { - const wall: WallType | undefined = this.heightMap.getWall({ - x: x - 1, - y, - }); + const wall: WallType | undefined = this.heightMap.getWall({ x: x - 1, y }); if (wall === undefined) continue; if (wall === WallType.RIGHT_WALL || wall === WallType.CORNER_WALL) { diff --git a/src/objects/rooms/geometry/index.ts b/src/objects/rooms/geometry/index.ts new file mode 100644 index 00000000..dec89991 --- /dev/null +++ b/src/objects/rooms/geometry/index.ts @@ -0,0 +1,2 @@ +export * from './Cube'; +export * from './GreedyMesher'; diff --git a/src/objects/rooms/index.ts b/src/objects/rooms/index.ts new file mode 100644 index 00000000..d399bf19 --- /dev/null +++ b/src/objects/rooms/index.ts @@ -0,0 +1,12 @@ +export * from './geometry'; +export * from './layers'; +export * from './materials'; +export * from './objects'; +export * from './parts'; + +export * from './Room'; +export * from './RoomCamera'; +export * from './RoomEvents'; +export * from './RoomHeightmap'; +export * from './RoomPreview'; +export * from './RoomVisualization'; diff --git a/src/objects/rooms/layers/MaskLayer.ts b/src/objects/rooms/layers/MaskLayer.ts index 41a9b921..9e0b07c1 100644 --- a/src/objects/rooms/layers/MaskLayer.ts +++ b/src/objects/rooms/layers/MaskLayer.ts @@ -3,21 +3,20 @@ import { Room } from '../Room'; import { LandscapeWindowMask } from '../parts/wall/landscapes/layers/items/LandscapeWindowMask'; import { LandscapePart } from '../parts/wall/landscapes/LandscapePart'; import { Container, Sprite } from 'pixi.js'; -import { Layer } from '@pixi/layers'; import { BlackSpriteMaskFilter } from '../../filters/BlackSpriteMaskFilter'; export class MaskLayer extends RoomLayer { public childrens: LandscapeWindowMask[] = []; public container: Container = new Container(); - public sprite!: Sprite; + public sprite: Sprite | undefined; constructor(public room: Room) { super(); } public add(item: LandscapeWindowMask): void { - const landscapeParts = this.room.visualization.layers.parts.childrens.filter(children => children instanceof LandscapePart); - if (landscapeParts.length === 0) this.room.visualization.renderLandscapes(); + const landscapeParts = this.room.visualization!.layers.parts.childrens.filter(children => children instanceof LandscapePart); + if (landscapeParts.length === 0) this.room.visualization!.renderLandscapes(); this.container.addChild(item.sprite); this.childrens.push(item); this.update(); @@ -25,26 +24,27 @@ export class MaskLayer extends RoomLayer { public remove(item: LandscapeWindowMask): void { this.container.removeChild(item.sprite); - this.childrens = this.childrens.filter((filteredItem: LandscapeWindowMask) => filteredItem !== item); + const index = this.childrens.indexOf(item); + if (index !== -1) this.childrens.splice(index, 1); } public destroy(): void { if (this.sprite !== undefined) { - this.room.visualization.layers.parts.landscapes.filters = []; + this.room.visualization!.layers.parts.landscapes.filters = []; this.sprite.destroy(true); - this.sprite = undefined as any; + this.sprite = undefined; } } public update(): void { if (this.sprite) { - this.room.visualization.container.removeChild(this.sprite); + this.room.visualization!.container.removeChild(this.sprite); this.sprite.destroy(true); } this.sprite = this.landscapeSprite(); - this.room.visualization.container.addChild(this.sprite); - this.room.visualization.layers.parts.landscapes.filters = [new BlackSpriteMaskFilter(this.sprite)]; + this.room.visualization!.container.addChild(this.sprite); + this.room.visualization!.layers.parts.landscapes.filters = [new BlackSpriteMaskFilter(this.sprite)]; } public landscapeSprite(): Sprite { diff --git a/src/objects/rooms/layers/ObjectLayer.ts b/src/objects/rooms/layers/ObjectLayer.ts index 494dd669..ef0e58d4 100644 --- a/src/objects/rooms/layers/ObjectLayer.ts +++ b/src/objects/rooms/layers/ObjectLayer.ts @@ -14,6 +14,7 @@ export class ObjectLayer extends RoomLayer { } public remove(item: RoomObject): void { - this.childrens = this.childrens.filter((filteredItem: RoomObject) => filteredItem !== item); + const index = this.childrens.indexOf(item); + if (index !== -1) this.childrens.splice(index, 1); } } diff --git a/src/objects/rooms/layers/PartLayer.ts b/src/objects/rooms/layers/PartLayer.ts index 37de9161..25d46812 100644 --- a/src/objects/rooms/layers/PartLayer.ts +++ b/src/objects/rooms/layers/PartLayer.ts @@ -10,8 +10,8 @@ import { WallPart } from '../parts/wall/WallPart'; import { LandscapePart } from '../parts/wall/landscapes/LandscapePart'; export class PartLayer extends RoomLayer { - public cursor!: CursorPart; - public door!: DoorPart; + public cursor: CursorPart | undefined; + public door: DoorPart | undefined; public landscapes: Layer = new Layer(); public childrens: RoomPart[] = []; @@ -24,7 +24,8 @@ export class PartLayer extends RoomLayer { } public remove(item: RoomPart): void { - this.childrens = this.childrens.filter((filteredItem: RoomPart) => filteredItem !== item); + const index = this.childrens.indexOf(item); + if (index !== -1) this.childrens.splice(index, 1); } public clear(type?: (new () => TilePart) | (new () => StairPart) | (new () => WallPart) | (new () => LandscapePart)): void { @@ -32,7 +33,7 @@ export class PartLayer extends RoomLayer { this.childrens = []; return; } else { - this.childrens = this.childrens.filter((filteredItem: RoomPart) => !(filteredItem instanceof type)); + this.childrens = this.childrens.filter((filteredItem: RoomPart): boolean => !(filteredItem instanceof type)); } } } diff --git a/src/objects/rooms/layers/index.ts b/src/objects/rooms/layers/index.ts new file mode 100644 index 00000000..f312b1ff --- /dev/null +++ b/src/objects/rooms/layers/index.ts @@ -0,0 +1,4 @@ +export * from './MaskLayer'; +export * from './ObjectLayer'; +export * from './RoomLayer'; +export * from './PartLayer'; diff --git a/src/objects/rooms/materials/index.ts b/src/objects/rooms/materials/index.ts new file mode 100644 index 00000000..f137fb30 --- /dev/null +++ b/src/objects/rooms/materials/index.ts @@ -0,0 +1,4 @@ +export * from './FloorMaterial'; +export * from './RoomMaterial'; +export * from './LandscapeMaterial'; +export * from './WallMaterial'; diff --git a/src/objects/rooms/objects/furnitures/WallFurniture.ts b/src/objects/rooms/objects/furnitures/WallFurniture.ts index 09bf9c1e..4a6b5dab 100644 --- a/src/objects/rooms/objects/furnitures/WallFurniture.ts +++ b/src/objects/rooms/objects/furnitures/WallFurniture.ts @@ -76,7 +76,7 @@ export class WallFurniture extends RoomFurniture { this.visualization.container.y = 16 * this.position.x + 16 * this.position.y - 32 + this.position.offsets.y * 2 + 31 - wallSize + 8; } - this.room.visualization.container.addChild(this.visualization.container); + this.room.visualization!.container.addChild(this.visualization.container); } public update(): void { @@ -114,7 +114,7 @@ export class WallFurniture extends RoomFurniture { } if (this.visualization && this.visualization.data && this.visualization.data.masks && this.room) { - this.room.visualization.layers.masks.update(); + this.room.visualization!.layers.masks.update(); this.visualization.renderMasks(); } } @@ -150,7 +150,7 @@ export class WallFurniture extends RoomFurniture { if (update === undefined || update) this.visualization.update(); } - public move({ position, duration }: { position: OffsetVector2D; duration?: number }): void { + public move({ position }: { position: OffsetVector2D; duration?: number }): void { this._position = position; // todo(): implement this } diff --git a/src/objects/rooms/objects/furnitures/placeholders/WallFurniturePlaceholder.ts b/src/objects/rooms/objects/furnitures/placeholders/WallFurniturePlaceholder.ts index 3a915708..fd0d8b36 100644 --- a/src/objects/rooms/objects/furnitures/placeholders/WallFurniturePlaceholder.ts +++ b/src/objects/rooms/objects/furnitures/placeholders/WallFurniturePlaceholder.ts @@ -1,5 +1,5 @@ import { Sprite } from 'pixi.js'; -import { OffsetVector2D, Vector3D } from '../../../../../types/Vector'; +import { OffsetVector2D } from '../../../../../types/Vector'; import { asset } from '../../../../../utils/Assets'; import { Direction } from '../../../../../enums/Direction'; import { WallFurniture } from '../WallFurniture'; @@ -11,7 +11,7 @@ interface Configuration { export class WallFurniturePlaceholder { public furniture: WallFurniture; - public sprite!: Sprite; + public sprite: Sprite | undefined; public position: OffsetVector2D; constructor({ furniture, position }: Configuration) { @@ -38,13 +38,13 @@ export class WallFurniturePlaceholder { this.sprite.scale.x = -1; } - this.furniture.room.visualization.container.addChild(this.sprite); + this.furniture.room.visualization!.container.addChild(this.sprite); } public destroy(): void { if (this.sprite !== undefined) { this.sprite.destroy(); - this.sprite = undefined as any; + this.sprite = undefined; } } } diff --git a/src/objects/rooms/objects/furnitures/visualizations/FurnitureValRandomizerVisualization.ts b/src/objects/rooms/objects/furnitures/visualizations/FurnitureValRandomizerVisualization.ts index 562c4247..f7201455 100644 --- a/src/objects/rooms/objects/furnitures/visualizations/FurnitureValRandomizerVisualization.ts +++ b/src/objects/rooms/objects/furnitures/visualizations/FurnitureValRandomizerVisualization.ts @@ -22,7 +22,6 @@ export class FurnitureValRandomizerVisualization extends FurnitureAnimatedVisual } public setState(id: number): void { - console.log(id); if (id === 0) { if (!this._running) { this._running = true; diff --git a/src/objects/rooms/objects/furnitures/visualizations/FurnitureVisualization.ts b/src/objects/rooms/objects/furnitures/visualizations/FurnitureVisualization.ts index 099191f5..be638054 100644 --- a/src/objects/rooms/objects/furnitures/visualizations/FurnitureVisualization.ts +++ b/src/objects/rooms/objects/furnitures/visualizations/FurnitureVisualization.ts @@ -43,7 +43,7 @@ export class FurnitureVisualization extends RoomObjectVisualization { const storedMask = this.masks.get(mask.id); if (storedMask) { - this.furniture.room.visualization.layers.masks.remove(storedMask); + this.furniture.room.visualization!.layers.masks.remove(storedMask); storedMask.destroy(); } @@ -53,7 +53,7 @@ export class FurnitureVisualization extends RoomObjectVisualization { windowMask.render(); this.masks.set(mask.id, windowMask); - this.furniture.room.visualization.layers.masks.add(windowMask); + this.furniture.room.visualization!.layers.masks.add(windowMask); }); } } @@ -70,15 +70,17 @@ export class FurnitureVisualization extends RoomObjectVisualization { y: this.getLayerYOffset(id, this.furniture.direction), z: this.getLayerZOffset(id, this.furniture.direction), }, - blend: this.getLayerBlend(id) as any, + blend: this.getLayerBlend(id), flip: this.getLayerFlipped(id), interactive: this.getLayerInteractive(id), tag: this.getLayerTag(id), }; if (this.layers.get(id)) { + // @ts-expect-error incompatible blend type definition this.layers.get(id)!.update(layerConfiguration); } else { + // @ts-expect-error incompatible blend type definition const furnitureLayer = new FurnitureLayer(layerConfiguration); furnitureLayer.render(); this.container.addChild(furnitureLayer.sprite); @@ -180,17 +182,17 @@ export class FurnitureVisualization extends RoomObjectVisualization { return 0; } - public getLayerXOffset(id: number, direction: number): number { + public getLayerXOffset(id: number, _direction: number): number { const layer = this.data.layers.get(id); return layer ? layer.offsets.x : 0; } - public getLayerYOffset(id: number, direction: number): number { + public getLayerYOffset(id: number, _direction: number): number { const layer = this.data.layers.get(id); return layer ? layer.offsets.y : 0; } - public getLayerZOffset(id: number, direction: number): number { + public getLayerZOffset(id: number, _direction: number): number { const layer = this.data.layers.get(id); return layer ? layer.offsets.z : 0; } diff --git a/src/objects/rooms/objects/index.ts b/src/objects/rooms/objects/index.ts new file mode 100644 index 00000000..367c4480 --- /dev/null +++ b/src/objects/rooms/objects/index.ts @@ -0,0 +1,3 @@ +export * from './RoomObject'; +export * from './RoomObjectVisualization'; +export * from './RoomObjectVisualizationFactory'; diff --git a/src/objects/rooms/parts/RoomPart.ts b/src/objects/rooms/parts/RoomPart.ts index fac463eb..8d95e68d 100644 --- a/src/objects/rooms/parts/RoomPart.ts +++ b/src/objects/rooms/parts/RoomPart.ts @@ -3,7 +3,7 @@ import { Room } from '../Room'; import { EventManager } from '../../events/EventManager'; export abstract class RoomPart { - public abstract container: Container; + public abstract container: Container | undefined; public abstract room: Room; public abstract eventManager: EventManager; public abstract render(): void; diff --git a/src/objects/rooms/parts/floor/CursorPart.ts b/src/objects/rooms/parts/floor/CursorPart.ts index c1e04867..cde77824 100644 --- a/src/objects/rooms/parts/floor/CursorPart.ts +++ b/src/objects/rooms/parts/floor/CursorPart.ts @@ -1,10 +1,9 @@ +import { Container, Sprite, Texture } from 'pixi.js'; +import { cursorOrder, asset } from '../../../../utils'; +import { EventManager } from '../../../events'; +import { Vector3D } from '../../../../types'; import { RoomPart } from '../RoomPart'; import { Room } from '../../Room'; -import { Container, Sprite, Texture } from 'pixi.js'; -import { EventManager } from '../../../events/EventManager'; -import { Vector3D } from '../../../../types/Vector'; -import { asset } from '../../../../utils/Assets'; -import { cursorOrder } from '../../../../utils/Sorting'; interface Configuration { position?: Vector3D; @@ -12,16 +11,16 @@ interface Configuration { export class CursorPart extends RoomPart { public room!: Room; - public container: Container = new Container(); + public container: Container | undefined = new Container(); public eventManager!: EventManager; private _position: Vector3D; private _sprite!: Sprite; - constructor({ position }: Configuration) { + constructor(configuration?: Configuration) { super(); - this._position = position ?? { x: 0, y: 0, z: 0 }; + this._position = configuration?.position ?? { x: 0, y: 0, z: 0 }; } public render(): void { @@ -36,21 +35,21 @@ export class CursorPart extends RoomPart { this._sprite.zOrder = cursorOrder(this._position); } - this.container.addChild(this._sprite); + this.container!.addChild(this._sprite); } public show(): void { - this.container.alpha = 1; + this.container!.alpha = 1; } public hide(): void { - this.container.alpha = 0; + this.container!.alpha = 0; } public move({ x, y, z }: Vector3D): void { this._position = { x, y, z }; - this.container.x = 32 * x - 32 * y; - this.container.y = 16 * x + 16 * y - 32 * z - 20; + this.container!.x = 32 * x - 32 * y - 0.75; + this.container!.y = 16 * x + 16 * y - 32 * z - 19.25; if (this.room.parsedHeightMap.door) { if (this.room.parsedHeightMap.door.x === x && this.room.parsedHeightMap.door.y === y) { @@ -64,7 +63,7 @@ export class CursorPart extends RoomPart { public destroy(): void { if (this.container !== undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } } diff --git a/src/objects/rooms/parts/floor/StairPart.ts b/src/objects/rooms/parts/floor/StairPart.ts index 9de18c3e..45242bcb 100644 --- a/src/objects/rooms/parts/floor/StairPart.ts +++ b/src/objects/rooms/parts/floor/StairPart.ts @@ -1,15 +1,12 @@ +import { Container, FederatedPointerEvent, Graphics, Point, Polygon } from 'pixi.js'; +import { StairMesh, Vector2D, Vector3D } from '../../../../types'; +import { StairType, Direction, CubeFace } from '../../../../enums'; +import { FloorMaterial } from '../../materials'; +import { EventManager } from '../../../events'; +import { floorOrder } from '../../../../utils'; +import { Cube } from '../../geometry'; import { RoomPart } from '../RoomPart'; import { Room } from '../../Room'; -import { Container, FederatedPointerEvent, Graphics, Point, Polygon } from 'pixi.js'; -import { FloorMaterial } from '../../materials/FloorMaterial'; -import { Cube } from '../../geometry/Cube'; -import { Vector2D, Vector3D } from '../../../../types/Vector'; -import { CubeFace } from '../../../../enums/CubeFace'; -import { EventManager } from '../../../events/EventManager'; -import { StairType } from '../../../../enums/StairType'; -import { Direction } from '../../../../enums/Direction'; -import { floorOrder } from '../../../../utils/Sorting'; -import { StairMesh } from '../../../..'; interface Configuration extends StairMesh { material: FloorMaterial; @@ -21,232 +18,206 @@ export class StairPart extends RoomPart { public container: Container | undefined = new Container(); public eventManager: EventManager = new EventManager(); - private _material: Configuration['material']; - private _position: Configuration['position']; - private _thickness: Configuration['thickness']; - private _length: Configuration['length']; - private _direction: Configuration['direction']; - private _corners: Configuration['corners']; - - constructor({ material, position, thickness, length, direction, corners }: Configuration) { + constructor(public configuration: Configuration) { super(); - this._material = material; - this.container!.name = `X:${position.x}, Y: ${position.y} / ${StairType[corners.left]} ${StairType[corners.right]} ${ - Direction[direction] - }`; - - this._position = position; - this._thickness = thickness; - this._length = length; - this._direction = direction; - this._corners = corners; - this._registerEvents(); } private _registerEvents(): void { - this.container!.onpointerdown = (event: FederatedPointerEvent): void => + if (this.container == undefined) return; + + this.container.onpointerdown = (event: FederatedPointerEvent): void => this.eventManager.handlePointerDown({ position: this.getGlobalTilePosition(event.global), dragging: this.room.camera!.hasDragged, }); - this.container!.onpointerup = (event: FederatedPointerEvent): void => + this.container.onpointerup = (event: FederatedPointerEvent): void => this.eventManager.handlePointerUp({ position: this.getGlobalTilePosition(event.global), dragging: this.room.camera!.hasDragged, }); - this.container!.onpointermove = (event: FederatedPointerEvent): void => + this.container.onpointermove = (event: FederatedPointerEvent): void => this.eventManager.handlePointerMove({ position: this.getGlobalTilePosition(event.global), dragging: this.room.camera!.hasDragged, }); - this.container!.onpointerout = (event: FederatedPointerEvent): void => + this.container.onpointerout = (event: FederatedPointerEvent): void => this.eventManager.handlePointerOut({ position: this.getGlobalTilePosition(event.global), dragging: this.room.camera!.hasDragged, }); - this.container!.onpointerover = (event: FederatedPointerEvent): void => + this.container.onpointerover = (event: FederatedPointerEvent): void => this.eventManager.handlePointerOver({ position: this.getGlobalTilePosition(event.global), dragging: this.room.camera!.hasDragged, }); - this.container!.eventMode = 'static'; + this.container.eventMode = 'static'; } public render(): void { + if (this.container == undefined) return; + const position = this._containerPosition(); - this.container!.x = position.x; - this.container!.y = position.y; + this.container.x = position.x; + this.container.y = position.y; - switch (this._direction) { - case Direction.NORTH: - const graphics = new Graphics(); + if (this.configuration.direction === Direction.NORTH) { + const graphics = new Graphics(); - const polygonPoints = [ - new Point(0, 0), - new Point(32, -16), - new Point(32 * (this._length + 1), 16 * (this._length - 1)), - new Point(32 * this._length, 16 * this._length), - new Point(0, 0), - ]; + const polygonPoints = [ + new Point(0, 0), + new Point(32, -16), + new Point(32 * (this.configuration.length + 1), 16 * (this.configuration.length - 1)), + new Point(32 * this.configuration.length, 16 * this.configuration.length), + new Point(0, 0), + ]; - this.container!.hitArea = new Polygon(polygonPoints); + this.container.hitArea = new Polygon(polygonPoints); - // rectangle - /* graphics + // rectangle + /* graphics .beginFill('ffd800', 0.3) .drawPolygon(...polygonPoints) .endFill(); */ - // circles - /* for (const point of polygonPoints) { + // circles + /* for (const point of polygonPoints) { graphics.beginFill('#ffd800').drawCircle(point.x, point.y, 1).endFill(); } */ - this.container!.addChild(graphics); + this.container.addChild(graphics); - this._renderStair({ x: 8, y: -12 }); - break; - case Direction.WEST: - const graphics2 = new Graphics(); + this._renderStair({ x: 8, y: -12 }); + } else if (this.configuration.direction === Direction.WEST) { + const graphics2 = new Graphics(); - const test = [ - new Point(0, 24), - new Point(32 * this._length, -16 * this._length + 24), - new Point(64 + 32 * (this._length - 1), -16 * (this._length - 1) + 24), - new Point(32, 40), - new Point(0, 24), - ]; + const test = [ + new Point(0, 24), + new Point(32 * this.configuration.length, -16 * this.configuration.length + 24), + new Point(64 + 32 * (this.configuration.length - 1), -16 * (this.configuration.length - 1) + 24), + new Point(32, 40), + new Point(0, 24), + ]; - this.container!.y -= 24; - this.container!.hitArea = new Polygon(test); + this.container.y -= 24; + this.container.hitArea = new Polygon(test); - // rectangle - /* graphics2 + // rectangle + /* graphics2 .beginFill(0x00ff00, 0.3) .drawPolygon(...test) .endFill(); */ - // circles - /* for (const point of test) { + // circles + /* for (const point of test) { graphics2.beginFill('#ffd800').drawCircle(point.x, point.y, 1).endFill(); } */ - this.container!.addChild(graphics2); + this.container.addChild(graphics2); - this._renderStair({ x: 8, y: 12 }); - break; - case Direction.SOUTH: - this.container!.x += 24; - this.container!.y -= 12; - this.container!.hitArea = new Polygon(); - /*this.container.addChild(new Graphics().beginFill(0x00FF00, 0.3).drawPolygon( + this._renderStair({ x: 8, y: 12 }); + } else if (this.configuration.direction === Direction.SOUTH) { + this.container.x += 24; + this.container.y -= 12; + this.container.hitArea = new Polygon(); + /*this.container.addChild(new Graphics().beginFill(0x00FF00, 0.3).drawPolygon( new Point(0 - 24, 0 + 12), new Point(32 * 1 - 24, -16 * 1 + 12), - new Point(32 * (this._length + 1) + 32 * (1 - 1) - 24, -16 * (1 - 1) + 16 * (this._length - 1) + 12), - new Point(32 * this._length - 24, 16 * this._length + 12), + new Point(32 * (this.configuration.length + 1) + 32 * (1 - 1) - 24, -16 * (1 - 1) + 16 * (this.configuration.length - 1) + 12), + new Point(32 * this.configuration.length - 24, 16 * this.configuration.length + 12), new Point(0 - 24, 0 + 12) ).endFill());*/ - this._renderStair({ x: -8, y: -4 }); - break; - case Direction.EAST: - this.container!.x += 24; - this.container!.y -= 12; - this.container!.hitArea = new Polygon(); - /* this.container!.addChild( + this._renderStair({ x: -8, y: -4 }); + } else if (this.configuration.direction === Direction.EAST) { + this.container.x += 24; + this.container.y -= 12; + this.container.hitArea = new Polygon(); + /* this.container.addChild( new Graphics() .beginFill(0xff0000, 0.3) .drawPolygon( new Point(0 - 24, 24 - 12), - new Point(32 * this._length - 24, -16 * this._length + 24 - 12), - new Point(64 + 32 * (this._length - 1) - 24, -16 * (this._length - 1) + 24 - 12), + new Point(32 * this.configuration.length - 24, -16 * this.configuration.length + 24 - 12), + new Point(64 + 32 * (this.configuration.length - 1) - 24, -16 * (this.configuration.length - 1) + 24 - 12), new Point(32 - 24, 40 - 12), new Point(0 - 24, 24 - 12), ) .endFill(), ); */ - this._renderStair({ x: -8, y: 4 }); - break; + this._renderStair({ x: -8, y: 4 }); } } private _renderStair(offsets: Vector2D): void { for (let i: number = 0; i < 4; i++) { const size: Vector3D = { - x: this._direction === Direction.NORTH || this._direction === Direction.SOUTH ? this._length : 8 / 32, - y: this._direction === Direction.WEST || this._direction === Direction.EAST ? this._length : 8 / 32, - z: this._thickness / 32, + x: + this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH + ? this.configuration.length + : 8 / 32, + y: + this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST + ? this.configuration.length + : 8 / 32, + z: this.configuration.thickness / 32, }; - if ( - this._corners.left === StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) - ) { - size.x -= (8 / 32) * i; - } else if ( - this._corners.left === StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) - ) { - size.y -= (8 / 32) * (3 - i); + if (this.configuration.corners.left === StairType.OUTER_CORNER_STAIR) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + size.x -= (8 / 32) * i; + } else if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { + size.y -= (8 / 32) * (3 - i); + } } - if ( - this._corners.right == StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) - ) { - size.x -= (8 / 32) * i; - } else if ( - this._corners.right === StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) - ) { - size.y -= (8 / 32) * (3 - i); + if (this.configuration.corners.right === StairType.OUTER_CORNER_STAIR) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + size.x -= (8 / 32) * i; + } else if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { + size.y -= (8 / 32) * (3 - i); + } } - if ( - this._corners.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) - ) { - size.x -= (8 / 32) * (3 - i); - } else if ( - this._corners.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) - ) { - size.y -= (8 / 32) * i; + if (this.configuration.corners.left === StairType.INNER_CORNER_STAIR) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + size.x -= (8 / 32) * (3 - i); + } else if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { + size.y -= (8 / 32) * i; + } } - if ( - this._corners.right === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) - ) { - size.x -= (8 / 32) * (4 - i) + 0.25; - } else if ( - this._corners.right === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) - ) { - size.y -= (8 / 32) * i; + if (this.configuration.corners.right === StairType.INNER_CORNER_STAIR) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + size.x -= (8 / 32) * (4 - i) + 0.25; + } else if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { + size.y -= (8 / 32) * i; + } } - // NEEDS REFACTORING - if (this._corners.right === StairType.TWIN_CORNER_STAIR && this._direction === Direction.WEST) { - /* this._position.x === 13 && this._position.y === 3 && console.log(size.y); */ - // cuurent: [0.25, 0.5, 0.75, 1] - // expected: [0.25, 0.5, 0.5, 0.25] - size.y = i === 0 || i === 3 ? 0.25 : 0.5; - /* this._position.x === 13 && this._position.y === 3 && console.log(size.y); */ + if ( + (this.configuration.corners.left === StairType.TWIN_CORNER_STAIR || + this.configuration.corners.right === StairType.TWIN_CORNER_STAIR) && + (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) + ) { + size.y -= i === 0 || i === 3 ? 0.75 : 0.5; } - if (this._corners.left === StairType.TWIN_CORNER_STAIR && this._direction === Direction.NORTH) { - size.x -= (8 / 32) * (3 - i); + if ( + (this.configuration.corners.right === StairType.TWIN_CORNER_STAIR || + this.configuration.corners.left === StairType.TWIN_CORNER_STAIR) && + (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) + ) { + size.x -= i === 0 || i === 3 ? 0.75 : 0.5; } const textureOffset: Vector2D = { x: 0, y: 0 }; - if (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) { - switch (this._corners.left) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + switch (this.configuration.corners.left) { case StairType.STAIR: textureOffset.x = 0; textureOffset.y = 0; @@ -261,7 +232,7 @@ export class StairPart extends RoomPart { break; } } else { - switch (this._corners.left) { + switch (this.configuration.corners.left) { case StairType.STAIR: textureOffset.x = 8; textureOffset.y = 4; @@ -278,12 +249,12 @@ export class StairPart extends RoomPart { } const zOrders = { - [CubeFace.TOP]: floorOrder(this._position, size), - [CubeFace.LEFT]: floorOrder(this._position, size), - [CubeFace.RIGHT]: floorOrder(this._position, size), + [CubeFace.TOP]: floorOrder(this.configuration.position, size), + [CubeFace.LEFT]: floorOrder(this.configuration.position, size), + [CubeFace.RIGHT]: floorOrder(this.configuration.position, size), }; - if (this._direction === Direction.WEST || this._direction === Direction.EAST) { + if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { zOrders[CubeFace.TOP] -= i - 3; zOrders[CubeFace.LEFT] -= i - 3; zOrders[CubeFace.RIGHT] -= i - 3; @@ -293,12 +264,10 @@ export class StairPart extends RoomPart { zOrders[CubeFace.RIGHT] += i; } - const cubes: Cube[] = []; - const cube: Cube = new Cube({ layer: this.room.renderer.layer, - texture: this._material.texture, - color: this._material.color, + texture: this.configuration.material.texture, + color: this.configuration.material.color, zOrders: zOrders, size: size, offsets: { @@ -308,76 +277,54 @@ export class StairPart extends RoomPart { }, }); - cube.name = `Cube -> ${i}, size: ${size.x} ${size.y} ${size.z} ${zOrders[CubeFace.RIGHT]}`; - cube.x = offsets.x * i; cube.y = offsets.y * i; if ( - this._corners.left === StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) + this.configuration.corners.left === StairType.OUTER_CORNER_STAIR && + (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) ) { cube.x += 8 * i; cube.y += 4 * i; } else if ( - this._corners.left === StairType.OUTER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) + this.configuration.corners.left === StairType.OUTER_CORNER_STAIR && + (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) ) { cube.x += 8 * (3 - i); cube.y -= 4 * (3 - i); } if ( - this._corners.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) + this.configuration.corners.left === StairType.INNER_CORNER_STAIR && + (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) ) { cube.x += 8 * (3 - i); cube.y += 4 * (3 - i); } else if ( - this._corners.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) + this.configuration.corners.left === StairType.INNER_CORNER_STAIR && + (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) ) { cube.x += 8 * i; cube.y -= 4 * i; } - if (this._corners.left === StairType.TWIN_CORNER_STAIR && this._direction === Direction.NORTH) { - cube.x += 8 * (3 - i); - cube.y += 4 * (3 - i); + if ( + this.configuration.corners.left === StairType.TWIN_CORNER_STAIR && + (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) + ) { + cube.x += 8 * 2 + (i === 0 || i === 3 ? 8 : 0); + cube.y += 4 * 2 + (i === 0 || i === 3 ? 4 : 0); } - cubes.push(cube); - - // NEEDS REFACTORING if ( - this._corners.left === StairType.TWIN_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.WEST) + this.configuration.corners.left === StairType.TWIN_CORNER_STAIR && + (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) ) { - const cube: Cube = new Cube({ - layer: this.room.renderer.layer, - texture: this._material.texture, - color: this._material.color, - zOrders: zOrders, - size: size, - offsets: { - [CubeFace.TOP]: textureOffset, - [CubeFace.LEFT]: textureOffset, - [CubeFace.RIGHT]: textureOffset, - }, - }); - - // what you're doing is right - - // this._position.x === 13 && this._position.y === 3 && console.log(8 * (3 - i)); - this._position.x === 13 && this._position.y === 3 && console.log(offsets.x, offsets.y, -offsets.x + offsets.x, offsets.y * (3 - i)); - - cube.x = offsets.x + offsets.x * i; - cube.y = offsets.y * (3 - i); - - cubes.push(cube); + cube.x += 8 * 2 + (i === 0 || i === 3 ? 8 : 0); + cube.y -= 4 * 2 + (i === 0 || i === 3 ? 4 : 0); } - this.container!.addChild(...cubes); + this.container!.addChild(cube); } } @@ -389,14 +336,15 @@ export class StairPart extends RoomPart { } private _containerPosition(): Vector2D { + const { x, y, z } = this.configuration.position; const position: Vector2D = { - x: 32 * this._position.x - 32 * (this._position.y + this._length - 1), - y: 16 * this._position.x + 16 * (this._position.y + this._length - 1) - 32 * this._position.z, + x: 32 * x - 32 * (y + this.configuration.length - 1), + y: 16 * x + 16 * (y + this.configuration.length - 1) - 32 * z, }; - if (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) { - position.x = 32 * this._position.x - 32 * this._position.y; - position.y = 16 * this._position.x + 16 * this._position.y - 32 * this._position.z; + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { + position.x = 32 * x - 32 * y; + position.y = 16 * x + 16 * y - 32 * z; } return position; @@ -407,24 +355,18 @@ export class StairPart extends RoomPart { let localX: number; let localY: number; - if (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) { + if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { localX = Math.floor(localPosition.x / 64 + localPosition.y / 32); localY = Math.floor(localPosition.y / 32 - localPosition.x / 64) + 1; } else { localX = Math.floor(localPosition.x / 64 + localPosition.y / 32 + 0.3) - 1; - localY = Math.floor(localPosition.y / 32 - localPosition.x / 64 + 0.24) + this._length - 1; + localY = Math.floor(localPosition.y / 32 - localPosition.x / 64 + 0.24) + this.configuration.length - 1; } - /* console.log({ - x: localX + this._position.x, - y: localY + this._position.y, - z: this._position.z, - }) */ - return { - x: localX + this._position.x, - y: localY + this._position.y, - z: this._position.z, + x: localX + this.configuration.position.x, + y: localY + this.configuration.position.y, + z: this.configuration.position.z, }; } } diff --git a/src/objects/rooms/parts/floor/TilePart.ts b/src/objects/rooms/parts/floor/TilePart.ts index f54df6a9..c495308a 100644 --- a/src/objects/rooms/parts/floor/TilePart.ts +++ b/src/objects/rooms/parts/floor/TilePart.ts @@ -1,25 +1,23 @@ +import { Container, FederatedPointerEvent, Point, Polygon } from 'pixi.js'; import { RoomPart } from '../RoomPart'; import { Room } from '../../Room'; -import { Container, FederatedPointerEvent, Graphics, Point, Polygon } from 'pixi.js'; -import { FloorMaterial } from '../../materials/FloorMaterial'; -import { Cube } from '../../geometry/Cube'; -import { EventManager } from '../../../events/EventManager'; -import { Vector2D, Vector3D } from '../../../../types/Vector'; -import { CubeFace } from '../../../../enums/CubeFace'; -import { floorOrder } from '../../../../utils/Sorting'; +import { FloorMaterial } from '../../materials'; +import { Cube } from '../../geometry'; +import { EventManager } from '../../../events'; +import { Vector2D, Vector3D } from '../../../../types'; +import { CubeFace } from '../../../../enums'; +import { floorOrder } from '../../../../utils'; +import { TileMesh } from '../../../..'; -interface Configuration { +interface Configuration extends TileMesh { material?: FloorMaterial; - position: Vector3D; - size: Vector2D; thickness: number; - door?: boolean; } export class TilePart extends RoomPart { public room!: Room; - public container: Container = new Container(); - public eventManager: EventManager = new EventManager(); + public container: Container | undefined; + public eventManager: EventManager; private _material: FloorMaterial; private _position: Vector3D; @@ -30,6 +28,9 @@ export class TilePart extends RoomPart { constructor({ material, position, size, thickness, door }: Configuration) { super(); + this.container = new Container(); + this.eventManager = new EventManager(); + this._material = material ?? new FloorMaterial(101); this._position = position; this._size = size; @@ -40,38 +41,35 @@ export class TilePart extends RoomPart { } private _registerEvents(): void { - this.container.onpointerdown = (event: FederatedPointerEvent) => + this.container!.onpointerdown = (event: FederatedPointerEvent) => this.eventManager.handlePointerDown({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerup = (event: FederatedPointerEvent) => + this.container!.onpointerup = (event: FederatedPointerEvent) => this.eventManager.handlePointerUp({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointermove = (event: FederatedPointerEvent) => + this.container!.onpointermove = (event: FederatedPointerEvent) => this.eventManager.handlePointerMove({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerout = (event: FederatedPointerEvent) => + this.container!.onpointerout = (event: FederatedPointerEvent) => this.eventManager.handlePointerOut({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); - this.container.onpointerover = (event: FederatedPointerEvent) => + this.container!.onpointerover = (event: FederatedPointerEvent) => this.eventManager.handlePointerOver({ position: this.getGlobalTilePosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, }); } public render(): void { - let zOrder: number = floorOrder(this._position, this._size); - - if (this._door) zOrder = floorOrder(this._position, this._size, true); - + const zOrder: number = floorOrder(this._position, this._size, this._door); const position = this._containerPosition(); const cube: Cube = new Cube({ layer: this.room.renderer.layer, @@ -88,19 +86,19 @@ export class TilePart extends RoomPart { z: this._door ? 0 : this._thickness / 32, }, }); - this.container.addChild(new Graphics().lineStyle(2, 0xff0000).drawPolygon(this._hitArea()).endFill()); - this.container.hitArea = this._hitArea(); - this.container.eventMode = 'static'; - this.container.x = position.x; - this.container.y = position.y; + // this.container!.addChild(new Graphics().lineStyle(2, 0xff0000).drawPolygon(this._hitArea()).endFill()); + this.container!.hitArea = this._hitArea(); + this.container!.eventMode = 'static'; + this.container!.x = position.x; + this.container!.y = position.y; - this.container.addChild(cube); + this.container!.addChild(cube); } public destroy() { if (this.container !== undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } @@ -122,7 +120,7 @@ export class TilePart extends RoomPart { } public getGlobalTilePosition(point: Point): Vector3D { - const localPosition: Point = this.container.toLocal(point); + const localPosition: Point = this.container!.toLocal(point); const localX: number = Math.floor(localPosition.x / 64 + localPosition.y / 32), localY: number = Math.floor(localPosition.y / 32 - localPosition.x / 64 - 0.01) + this._size.y; return { diff --git a/src/objects/rooms/parts/index.ts b/src/objects/rooms/parts/index.ts new file mode 100644 index 00000000..90960ad3 --- /dev/null +++ b/src/objects/rooms/parts/index.ts @@ -0,0 +1 @@ +export * from './RoomPart'; diff --git a/src/objects/rooms/parts/wall/DoorPart.ts b/src/objects/rooms/parts/wall/DoorPart.ts index ab1d0722..2b327c38 100644 --- a/src/objects/rooms/parts/wall/DoorPart.ts +++ b/src/objects/rooms/parts/wall/DoorPart.ts @@ -13,9 +13,9 @@ interface Configuration { export class DoorPart extends RoomPart { public room!: Room; - public container: Container = new Container(); + public container: Container | undefined = new Container(); public eventManager: EventManager = new EventManager(); - public sprite!: Sprite; + public sprite: Sprite | undefined; constructor(public configuration: Configuration) { super(); @@ -28,25 +28,25 @@ export class DoorPart extends RoomPart { this.sprite.zOrder = 1000000; this.sprite.tint = 0x000000; - this.container.x = 32 * (this.configuration.position.x + 1) - 32 * this.configuration.position.y; - this.container.y = + this.container!.x = 32 * (this.configuration.position.x + 1) - 32 * this.configuration.position.y; + this.container!.y = 16 * (this.configuration.position.x + 1) + 16 * this.configuration.position.y - 32 * this.configuration.position.z - this.sprite.height + 2; - this.container.addChild(this.sprite); + this.container!.addChild(this.sprite); } public destroy(): void { - if (this.sprite !== undefined) { + if (this.sprite != undefined) { this.sprite.destroy(); - this.sprite = undefined as any; + this.sprite = undefined; } - if (this.container !== undefined) { + if (this.container != undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } } diff --git a/src/objects/rooms/parts/wall/WallPart.ts b/src/objects/rooms/parts/wall/WallPart.ts index 8aa7d948..23c59e1a 100644 --- a/src/objects/rooms/parts/wall/WallPart.ts +++ b/src/objects/rooms/parts/wall/WallPart.ts @@ -9,21 +9,17 @@ import { WallMaterial } from '../../materials/WallMaterial'; import { Direction } from '../../../../enums/Direction'; import { ReverseSpriteMaskFilter } from '../../../filters/ReverseSpriteMaskFilter'; import { wallOrder } from '../../../../utils/Sorting'; +import { WallMesh } from '../../../..'; -interface Configuration { - material?: WallMaterial; - position: Vector3D; - length: number; - thickness?: number; - height?: number; - direction: Direction; - corner: boolean; - dorr?: number; +interface Configuration extends WallMesh { + material: WallMaterial; + thickness: number; + height: number; } export class WallPart extends RoomPart { public room!: Room; - public container: Container = new Container(); + public container: Container | undefined = new Container(); public eventManager: EventManager = new EventManager(); public material: WallMaterial; @@ -37,7 +33,7 @@ export class WallPart extends RoomPart { constructor({ material, position, length, thickness, height, direction, corner }: Configuration) { super(); - this.material = material ?? new WallMaterial(101); + this.material = material; this.position = position; this.length = length; this.thickness = thickness ?? 8; @@ -49,34 +45,34 @@ export class WallPart extends RoomPart { } private _registerEvents(): void { - this.container.onpointerdown = (event: FederatedPointerEvent) => + this.container!.onpointerdown = (event: FederatedPointerEvent) => this.eventManager.handlePointerDown({ position: this.getGlobalWallPosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, direction: this.direction, }); - this.container.onpointerup = (event: FederatedPointerEvent) => + this.container!.onpointerup = (event: FederatedPointerEvent) => this.eventManager.handlePointerUp({ position: this.getGlobalWallPosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, direction: this.direction, }); - this.container.onpointermove = (event: FederatedPointerEvent) => + this.container!.onpointermove = (event: FederatedPointerEvent) => this.eventManager.handlePointerMove({ position: this.getGlobalWallPosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, direction: this.direction, }); - this.container.onpointerout = (event: FederatedPointerEvent) => + this.container!.onpointerout = (event: FederatedPointerEvent) => this.eventManager.handlePointerOut({ position: this.getGlobalWallPosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, direction: this.direction, }); - this.container.onpointerover = (event: FederatedPointerEvent) => + this.container!.onpointerover = (event: FederatedPointerEvent) => this.eventManager.handlePointerOver({ position: this.getGlobalWallPosition(event.global), - dragging: this.room.camera.hasDragged, + dragging: this.room.camera!.hasDragged, direction: this.direction, }); } @@ -99,29 +95,29 @@ export class WallPart extends RoomPart { }); if (this._isDoor()) { - const filter: ReverseSpriteMaskFilter = new ReverseSpriteMaskFilter(this.room.visualization.layers.parts.door.sprite); + const filter: ReverseSpriteMaskFilter = new ReverseSpriteMaskFilter(this.room.visualization!.layers.parts.door.sprite); cube.faces[CubeFace.RIGHT].filters = [filter]; } - this.container.hitArea = this._hitArea(this.direction, size); - this.container.eventMode = 'static'; - this.container.x = position.x; - this.container.y = position.y; + this.container!.hitArea = this._hitArea(this.direction, size); + this.container!.eventMode = 'static'; + this.container!.x = position.x; + this.container!.y = position.y; - this.container.addChild(cube); + this.container!.addChild(cube); } public destroy() { if (this.container !== undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } private _isDoor(): boolean { return ( (this.room.parsedHeightMap.door && - this.room.visualization.layers.parts.door && + this.room.visualization!.layers.parts.door && this.position.x - 1 === this.room.parsedHeightMap.door.x && this.position.y <= this.room.parsedHeightMap.door.y && this.room.parsedHeightMap.door.y <= this.position.y + this.length - 1 && @@ -177,7 +173,7 @@ export class WallPart extends RoomPart { } public getGlobalWallPosition(point: Point): OffsetVector2D { - const localPosition: Point = this.container.toLocal(point); + const localPosition: Point = this.container!.toLocal(point); let x = this.position.x; let y = this.length - (this.position.y + Math.floor(Math.abs(localPosition.x - this.thickness - 31) / 32)) + 1; diff --git a/src/objects/rooms/parts/wall/landscapes/LandscapePart.ts b/src/objects/rooms/parts/wall/landscapes/LandscapePart.ts index 79e96254..4511c319 100644 --- a/src/objects/rooms/parts/wall/landscapes/LandscapePart.ts +++ b/src/objects/rooms/parts/wall/landscapes/LandscapePart.ts @@ -20,14 +20,16 @@ interface Configuration { export class LandscapePart extends RoomPart { public room!: Room; - public container: Container = new Container(); + public container: Container | undefined; public eventManager: EventManager = new EventManager(); - private _mask!: Cube; + private _mask: Cube | undefined; private _layers: LandscapeLayer[] = []; constructor(public configuration: Configuration) { super(); + + this.container = new Container(); } public get mask(): Cube { @@ -70,22 +72,22 @@ export class LandscapePart extends RoomPart { material.layers.forEach((layer: any) => { const landscapeLayer: LandscapeLayer = new layer.layer({ ...layer.params, ...{ part: this } }); this._layers.push(landscapeLayer); - this.container.addChild(landscapeLayer.container); + this.container!.addChild(landscapeLayer.container); landscapeLayer.render(); }); - this.container.interactiveChildren = false; - this.container.addChild(this.mask); - this.container.mask = this.mask; - this.container.parentLayer = this.room.visualization.layers.parts.landscapes; - this.container.x = baseX; - this.container.y = baseY - 32 * position.z - size.z * 32 + floorThickness; + this.container!.interactiveChildren = false; + this.container!.addChild(this.mask); + this.container!.mask = this.mask; + this.container!.parentLayer = this.room.visualization!.layers.parts.landscapes; + this.container!.x = baseX; + this.container!.y = baseY - 32 * position.z - size.z * 32 + floorThickness; } public destroy() { if (this._mask !== undefined) { this._mask.destroy(); - this._mask = undefined as any; + this._mask = undefined; } if (this._layers.length > 0) { @@ -95,7 +97,7 @@ export class LandscapePart extends RoomPart { if (this.container !== undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } } diff --git a/src/objects/rooms/parts/wall/landscapes/layers/LandscapeLayer.ts b/src/objects/rooms/parts/wall/landscapes/layers/LandscapeLayer.ts index 5508541e..16485cfb 100644 --- a/src/objects/rooms/parts/wall/landscapes/layers/LandscapeLayer.ts +++ b/src/objects/rooms/parts/wall/landscapes/layers/LandscapeLayer.ts @@ -35,7 +35,7 @@ export abstract class LandscapeLayer { return ( (room.parsedHeightMap.door && - room.visualization.layers.parts.door && + room.visualization!.layers.parts.door && configuration.position.x - 1 === room.parsedHeightMap.door.x && configuration.position.y <= room.parsedHeightMap.door.y && room.parsedHeightMap.door.y <= configuration.position.y + configuration.length - 1 && @@ -45,10 +45,9 @@ export abstract class LandscapeLayer { } public render(): void { - const { visualization, renderer } = this.part.room; - const { door } = visualization.layers.parts; + const { door } = this.part.room.visualization!.layers.parts; const cube: Cube = new Cube({ - layer: this.part.container.parentLayer, + layer: this.part.container!.parentLayer, size: this.size, zOrders: { [CubeFace.TOP]: -3, diff --git a/src/types/Mesh.ts b/src/types/Mesh.ts index 7bbb45c7..ca01b881 100644 --- a/src/types/Mesh.ts +++ b/src/types/Mesh.ts @@ -2,13 +2,13 @@ import { Vector2D, Vector3D } from './Vector'; import { Direction } from '../enums/Direction'; import { StairType } from '../enums/StairType'; -export type TileMesh = { +export interface TileMesh { position: Vector3D; size: Vector2D; door: boolean; -}; +} -export type StairMesh = { +export interface StairMesh { position: Vector3D; length: number; direction: Direction; @@ -16,12 +16,12 @@ export type StairMesh = { left: StairType; right: StairType; }; -}; +} -export type WallMesh = { +export interface WallMesh { position: Vector3D; length: number; direction: Direction; corner: boolean; door?: number; -}; +} diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 00000000..89dccfc2 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,5 @@ +export * from './HeightMap'; +export * from './Material'; +export * from './Mesh'; +export * from './Stair'; +export * from './Vector'; diff --git a/src/utils/Assets.ts b/src/utils/Assets.ts index 4f37280d..0fefbda9 100644 --- a/src/utils/Assets.ts +++ b/src/utils/Assets.ts @@ -9,8 +9,7 @@ let assetsPath: string; async function register(key: string, path: string, onUncached?: () => void): Promise { if (loadedKeys[key] !== undefined) { - await loadedKeys[key]; - return; + return await loadedKeys[key]; } if (!Cache.has(key)) { diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..6f26e434 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,3 @@ +export * from './Logger'; +export * from './Sorting'; +export * from './Assets'; diff --git a/tsconfig.json b/tsconfig.json index d50a3737..47a7728b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "skipLibCheck": true, /* Bundler mode */ - "types": ["./src/types/Globals.d.ts"], + "types": ["./src/types/Globals.d.ts", "vite/client"], "moduleResolution": "bundler", "isolatedModules": true, "noEmit": true, @@ -22,6 +22,6 @@ "noPropertyAccessFromIndexSignature": true, "noImplicitAny": true }, - "include": ["src"], + "include": ["**/*.ts"], "exclude": ["node_modules", "dist"] } diff --git a/tsup.config.ts b/tsup.config.ts index b425f84c..284ba4f8 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,12 +1,13 @@ -import { Options } from 'tsup'; +import { Options, defineConfig } from 'tsup'; -export const tsup = { - target: 'esnext', - format: 'esm', - clean: true, - bundle: true, - minify: true, - noExternal: [/(.*)/], - entry: ['src/index.ts'], - dts: true, -} satisfies Options; +export default defineConfig( + (options): Options => ({ + target: 'esnext', + format: 'esm', + clean: true, + minify: !options.watch, + noExternal: [/(.*)/], + entry: ['src/**/index.ts'], + dts: true, + }), +); From f17ca72c66667774eeaafe07ea97703923f33818 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Tue, 27 Feb 2024 17:58:44 +0100 Subject: [PATCH 08/13] =?UTF-8?q?feat(=F0=9F=94=A5):=20implement=20HMR=20+?= =?UTF-8?q?=20externalize=20pixi=20stats=20from=20bundle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 37 +++++++++++++---- package.json | 5 +-- public/assets/dev.ts | 22 ---------- public/assets/logo.png | Bin 0 -> 6266 bytes public/assets/main.ts | 60 ++++++++++----------------- public/assets/test.ts | 40 ++++++++++++++++++ public/assets/{main2.ts => test2.ts} | 0 public/assets/{main3.ts => test3.ts} | 0 public/assets/vite.svg | 1 - public/index.html | 9 ++-- public/vite.config.js | 1 + src/Scuti.ts | 34 ++++++++------- src/ScutiConfiguration.ts | 41 ++++++++++-------- src/types/Globals.d.ts | 5 --- src/types/Stair.ts | 4 +- tsconfig.json | 1 - 16 files changed, 144 insertions(+), 116 deletions(-) delete mode 100644 public/assets/dev.ts create mode 100644 public/assets/logo.png create mode 100644 public/assets/test.ts rename public/assets/{main2.ts => test2.ts} (100%) rename public/assets/{main3.ts => test3.ts} (100%) delete mode 100644 public/assets/vite.svg delete mode 100644 src/types/Globals.d.ts diff --git a/package-lock.json b/package-lock.json index 1ee60bbe..ac3aac31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "@pixi/layers": "^2.1.0", "buffer": "^6.0.3", "gsap": "^3.12.4", - "pixi-stats": "^1.2.2", "pixi.js": "^7.2.4", "scuti-bundle": "^1.0.7", "seedrandom": "^3.0.5" @@ -23,6 +22,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.1", + "pixi-stats": "^1.2.2", "prettier": "^3.1.1", "tsup": "^8.0.1", "typescript": "^5.3.3", @@ -499,6 +499,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/@jacekpietal/gstats/-/gstats-0.1.0.tgz", "integrity": "sha512-52ILOmtGRZdunCFXE/wxNaGs/CsP0mF7QbNKvpviSI8cnznognB65zWG2r+k+2SNhYPCDg+FTi3/pj5JSxeh3A==", + "dev": true, "peerDependencies": { "pixi.js": "*" } @@ -1150,6 +1151,17 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/node": { + "version": "20.11.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.20.tgz", + "integrity": "sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@types/offscreencanvas": { "version": "2019.7.0", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", @@ -3128,6 +3140,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/pixi-stats/-/pixi-stats-1.2.2.tgz", "integrity": "sha512-wajlyv3nl/xha7H5TuSHZr+iYclynLilF37H0IWhxsWtTOIF7EAe/oVXyY2nPVY6CE+s2MsB3Te+g9OcofrrAg==", + "dev": true, "dependencies": { "@jacekpietal/gstats": "^0.1.0" }, @@ -3177,9 +3190,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -3792,6 +3805,14 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -3829,13 +3850,13 @@ } }, "node_modules/vite": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz", - "integrity": "sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", "dev": true, "dependencies": { "esbuild": "^0.19.3", - "postcss": "^8.4.32", + "postcss": "^8.4.35", "rollup": "^4.2.0" }, "bin": { diff --git a/package.json b/package.json index 286a5a3f..c237c95c 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,7 @@ "scripts": { "build": "tsup", "dev": "vite serve public", - "preview": "vite preview public", - "build:production": "vite build public", + "preview": "vite build public vite preview public", "lint": "eslint --fix . --ignore-path .gitignore --ext .js,.ts src", "format": "prettier --ignore-path .gitignore --write \"**/*.+(ts|html|css)\"" }, @@ -20,7 +19,6 @@ "@pixi/layers": "^2.1.0", "buffer": "^6.0.3", "gsap": "^3.12.4", - "pixi-stats": "^1.2.2", "pixi.js": "^7.2.4", "scuti-bundle": "^1.0.7", "seedrandom": "^3.0.5" @@ -29,6 +27,7 @@ "@types/seedrandom": "^3.0.8", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", + "pixi-stats": "^1.2.2", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.1", diff --git a/public/assets/dev.ts b/public/assets/dev.ts deleted file mode 100644 index d2e04132..00000000 --- a/public/assets/dev.ts +++ /dev/null @@ -1,22 +0,0 @@ -// HMR -// https://stackoverflow.com/questions/71743027/how-to-use-vite-hmr-api-with-pixi-js -/* if (import.meta.hot) { - import.meta.hot.accept((): void => { - room.destroy(); - }); -} */ - -import { StatsJSAdapter, addStats } from 'pixi-stats'; -import { renderer } from './main'; -import { Ticker, UPDATE_PRIORITY } from 'pixi.js'; - -setTimeout(() => { - // Pixi stats - const stats: StatsJSAdapter = addStats(document, renderer.application); - const ticker: Ticker = Ticker.shared; - - ticker.add(stats.update, stats, UPDATE_PRIORITY.UTILITY); - - // Pixi devtools - globalThis.__PIXI_APP__ = renderer.application; -}, 1000); diff --git a/public/assets/logo.png b/public/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..56b8afbde40c80700aba2aa9608ac9e9298b380b GIT binary patch literal 6266 zcmZWuXEYp6v=_ZagdikJ5GBegL9}I+usVqrQKE+EHF{QWv3f5dI#E{dCBh=C8di_8 zI?)!pmgoQNz4PXr+h*p>ow@g(`{6gyI$A3C$(hLU@bK<~Rh9Jar0X4pk`mu>eN_JS zow(Yx#!Do0tJG*=w zXh`4p`Idw&O{|0f68p2L6NibS|MgbzY1<~38{5A_Vf&*?tqSs4>*=_rV1?bH%x{XQ zGAFJ`nO>F=&DB?%U&0H1W7Fbmi`-+Q7H-`3lIhdDV-UHYk-pD`s9Qcob-1X?Q*GqB zNa_Vz_9?yR^G`Gh8i|ASgg-mE0l*7*PT@_uPc}f7)Lf?GcHdf`kme9;%rA7syD~a; zvw6bqPb#H>AJx$&8>yES?Ty4jdRnP{%@s3hCj=NWs%-T(cqmK(G<9IP{R>VaKI;?z+_XB*(bmWG8H+el!kCnGrvHpo_kx)66gc0IiI#ysTe$%y!9+VC14N5Xydp!@yb7xW3 z=SEufh%`PyF-YX~$-2!Hd3)TPA!*pdL?7b{c86@ZBK?3haHyrLz&(MFBLPUHmQkK<}*sEk_6&&D!d0W;uFToIzyf z;N$=XbLu+J^O2Bt!Gi18(I)!lj8*z~(Xx98njXDn_Dd|M$)+QX(TKgCPxQ03Yr+D- z(ip@^mtEXUObZ&lkd1Cyur^_=Qg2NYvTu$STKOL41TIoroWk3n;~ITjFADq9a}o=@ zwvusirSdDw?nXmvKD}Od6J`3EMFKn(dj-Irko|c_to1GpOd9h22Rq_IB1*?r7cN9g z_JKckyUspZ%YKBpbS0H{#ea6e_Qzphv+tFoi%IJyZ517UbOju1ZJUR$MW00tCktVN zV&`6wotExBI&`D_Fv-@EhWIF9-#DR*;{*7YiwjCCt;M6B0Y1k%@+Aja2vEPWZ#J82 zFgexy7}6ys0T^Q=+kbIB6e6l)eKl$apFG*Qujb?ktHBzj9{`7eQ$-Wr@bslEa%VI0 zN*oK%$r!XpFY2l(md;Z|WyF>)QJ&V1=V^t`ue=L|g%G8MV`b;@PVKqt>#e=6$iPLJ zeaE2QAv-hSDiq}-U)I>wq-Q3|i=+7zrkwp&_mmEG!iKtx#QD^Zqba9w8n>1Ye{n~@ zxnCK0G~&T}2s@ab^xevR2Q&m?dmKi4*busOO{Qz#>eXKs@Q0gGsU&)F;j2(7=UvY@ z(|CCrcmXR!%`ji74A4V6!*;pP+OxAcR-{6WCiV#`g$cM1G+F;XZp;SgMh(%Cj%XB) zLY5x}HF3M42*K#%4u*rdHsSY5IlCM%fRq^R5_X>1&)|K*g)Bp#1BcE=Ze&!U%@oW# ziqN#EU-rKHGR17k@Uc z(I62hq)()u$w2r|kPM{N?xZX6FhOrpiMuW}9N8RTwH~6mz6|v@Zy2mTA1j%_xnv2^ z)fBe(7A>7X-in#pcIaQQuKfmWv$h@)C4PXg(JKmbn0@?i)$qn;FoCN*I`m!Fk-T;) z_84-|lIe>fb1<2WoBf*gl@(Xr?w&!c;ZLkJ&)RLyUjGF~bW*0Mkuq+tf;!=$u>|*5 zJFzHStzEu9qxMEeN<2JcCE-SP21-9q&qGQ`?49-`@=@I|{RGviIi9u2X7mf#xQ;geP|8UyFxAmxHQhco`GRoQ{R$Ug(HCR1Ha z8cY4m>$ktF0b`$)r=L)~-0H;QfhU9IGaG3g`@$t3z!?n^U8bVt<*Lh`#YNSz>Oc4K zOeS<8+RUCVI(yV;x?(T^iOyK;fU}R0WmHGA+Q!RAMbYp*e8FE(M~A#8*Jk6=<|5SL;!@V3 z)L|9Qv`0`8p4u7ji$J`Q(wCOnUm%F@p_`85^(uYL)=8tlIlqIZH%0zN^RW1=z$8`v zyMrYG!b*8^lyon@{xA%mR+g;d()Pknvp$2S+AQ4*_9Uv3XvpDP7Dkg?NL2oaVKQ!m0QzxS%Bsg9Yzz%nj z-*}S!Djp(>%e|E*q4H9W9}>+nQFV)NIh5xTCcbme=p6D;Nj(=`37Z2gSE$h94xZ)~ zB2V`nGnNt^au5|aqiFK(iO{?wrpK%pBc;|A0s4cMFlygh_TF-RXH4PO`t*JiW00jr zbx2Jc{@+WBIydphK>>K3-;B#%wY+`0Dq^iI0q3-FcIETR(9W5KVcLoMA9DdyM0Oe( z!v^LYvn;E&i#@`b*01~Wjaga6m+lJDgY%?8!YQ5tbkT_YCM6OQ!E~?8ER~6I)ib6` zoJVN)Z`=K*C1rP(*vE*i-&|B~1LL4eOhT7f>Bp_N!hF@-@A@)=oFC+VuL&o|gx)+- z9*;oP4u->2FVos6|8*=pxrw$)5g6{6azpjb` zfGX`k`{-1)>{4AloQB!%B~~+JdS~k#))4~$kx>x*s^6G4FpcfEdJm4@5DpMz-Uq^1&<$$USyO#i%! z>(>wd;1C149(!L&UOr*D{+PYgLb`uInbRQmSr%VY&t_ys*oW%H*i#Z=v($5kYP2yc zT{niz+_tbgOyS=)t1$y3cP`$acCpKU2=_m;nHBGH9+)P1oQo361q9?JSY0*!@jX@@ zM082MKL4q*E=(0fZ8}>Snx=IiufJJ~^XIAFr>7r1W4Y^82JCrmSpu`3Q?ZWY;m3W+ zOlZf{vK8&WlXgyoVR01Ff~gOC`n`AuLB&krC(4+eFnOk=-v|%Or{z*-Tgsx(>~<=> zefnMruB1q{G*ZEdg#5-?*W>;;wjajZ2CPCxFTW6^LfS8Q>OKxG^%vo8jD@8@ov)uT zXg5W+^i3;z_N1>I$CeTCd%1SUseO(9_WOYWa?;7cH4KfPH&uo_*%TPXggy|1>?y7G zwu4ufjTBOSZ@)yrB!@g!LGyLROhiwV+ss>E;6{25ZNM~^nr2curH{QedOzIT@9W@y zrGSOJH*?9kim$e)+UfT?7-~q%l25#-$RJZ+PCx5Vi6i6Oqeqi>*i|Yf&NPxG{KZ`B z;S%&>#+eW}PjJ)3a-4*0k7WD* z+Lac9&QF)1j?RCW-Bs&@ein?jg;Gt@_^FECvALQXXDI;|^=!xup$Q1N$bq=0SI*ya zXvpLZ);5fEsEoIE+%Yx5?}QCy=5{eNzOT^0By$I9_@u(lM;diQR<6jKqKc=ZL_T;pwyU*zG2>*FFo0}1zZ)@X#_eIG+?%8!k(vfc)g)6{ilw*)f(vzH9ExN*VGYgnljfs@C}E8(a=JVd`|cwvL{GAr zf0*oH3mzB1Z#x22h3F8fJT-q(f$e+a?qDwT<{KP!pHRGlx1ASlePxWOD@!|2cbu63 z#qaT?3+M(in+{zDAstt$J0mOFcyaBYlKuMm3cJUAN7ZkPvr`n$;(QW{@=mGdsWB0X zSzaVAAA=72y9-V`X!luADpxG)zn~KanTB2$O-Y{SA3N5hp0ur)_6`KHJL$KH7lmO{ ztSRZbQzJCnR*Z+5hA|<7{3bQi?qFVg9->*S_Zfe+!EFQc%`8&fUOb->z`nBnvUF(7 zpt87V{;E<-9mLWyNN~1F`Sg<#v1uuRjT|F-cEmb(2*>##MMnMvPwZru7wdL;o@ z2bRoy<4I$b8&$m4jRleAl_{fWvtk#%T%s>^2`U|LY18uf2J{iWsr%BoPL4X3&-)~T z2%LF`2-MXqMu(A#iOb-<;kKa8d0o^_dt}`1j08&H*_f&g&Wk z$BiDzjPmcz((c06leliEK{AE!Th4~Kn_)h=#p}tD+t6JW)4$cVMT8>esKXZPaBY?W z%U>Jtx5YYs>8U_LmM1G%c4kRq;1i+9F8^Fb-h$Cni97c zl-9ohuB?27Y6I2?wlb!EF1r@+FTvGgiaA|9(Txl3#(K8(Ut?op#k60{L=f^y{jRxv zOWj(zykXJG?G++R;+)c{1rOjn&gH0tLkGjy@2AL|0H)=b1f@4OKU5l)Sv2QLYwZ5L z#Yj3JVP{4s{%oR~@7N-Gf2g;qa&zE(+4R0%F4S=I#`X?e zIVdXF6b(PMl4oDQ!Kn{aI*%%icGWJJ&?vH#3N+RHp6Hhjwdw%>ZNhxMlM{n&b9Skz zKB#=@5RY^l6*WXlGRgd^k~}m0s3C3ulc)(}tcj(w!C_Dtr_~;nfoPGmO-}VVFjjWS zhxDoXO6pODKV9*~5J-=t>73GI9+OKrZN8rFT>MH=MfT)vz9L)jrSqcW^>*`;L%vN9 zEcYXsuzk%|FXKmyVV7vgNb2urWSJ3^UAj$4bE786%4+xNd`~Mx&bKXTd4KLyx4ktk zxBaW7+x<+ckx(01B#k^W{lVCxY0agN#*6o_!AeOV*23C`C5y^iszazA%uvP$Ra1Gs z{gVr?iQ+`jmQl)h6LtHIHW)H`26K$3N6U2Imbd7ys>2#EZlDPAN(qLfM$sQ`G1d!; zPVqtURF|LXC%IkjRdM=Sh&_B|-;K2-5i86s>ro7|p|>#H=TW6oaLU&s6cL_5mD#D6 zj%iH=!@bhyJpbM&C4MJdRZYn`zAprj_7PuQ5-}nU(DV7YX^vFgAvL^rRyq4~0-;89 za+&+b)aqTAX!jbe5ob!EjQo}-;1;3t=_>SV-ux0`|GQ<8;?;ysm&z>&Q^79jL1Rud zN91|5;5h-UYVGPXQf5@mN(f{}j1*RkwOPYQSVR`&yANH{wbfkDM7_$?uv0^{CDAfM zVzgJhI_OR|{mx~l*r1Q0yzk_*JP%>DMd>=$kqjg4>ln7Tsp{$MN;u&;;~wt*leVY$OA6!X)VCz1;A!X)&rG- zpG%JW~ zR7aj|B*<{(V5)_V@WD@wwkhAl+W(eM9IVOav%*}6a_h__mWNi*U@(M1Q?&Yq+$^;8 zDlDCbcY#q$*O{Z?ur?n|rJ^SAh5N~D@9XV--BSTVVuEe8HeH~HOqEVUIZ%5J9i)$6 zf{qeMBbB`pdgvs!uNRMHCc9Qz-Z^Rx+f)t`a(Foo%4&)1=S!X|E=gn$(;6FR^g|rXXfp~a!!mL;PknDl zFlQKAB>CzDEtOC)& z3jx?9iBuj{? zGA3tpO-D$|aB~~(wUm>~6tve){0qCiCI)550U5FS6 z%?w2ANf5gwA<>7W!Teoq0tA?-A z@470_|L1e~Ea7OL#P_?c92k!MfmjZ+^ESd}q)~`LzKAh*nc<>amGaK}PjMs<+3q86 zf0FIZ`~@>)zp6#tRs+8!+R$7YL@aG z@YdKWVnl@x5_|{fBr2Q!TXH5NQl8H#3>`|o=>RxSxv@RapoNSnz_Xx1;x|_)NC&V) zm>QMP-9F%)Vkd28bG;ecFK_l>>S^57&?{<*|AVFfKXg5iRP*#!wccfn(W^)9?pJ`y g#t3YysfqXEPA9#i|HkB- -export const renderer: Scuti = new Scuti({ - canvas: document.getElementById('app')!, - resources: 'http://127.0.0.1:8081', - backgroundColor: 0x0c567c, - zoom: { direction: 'center' }, -}); +import { type Application, Ticker, UPDATE_PRIORITY, type ICanvas } from 'pixi.js'; +import { addStats } from 'pixi-stats'; -await renderer.load(); +import('./test'); -const heightMap: string = ` -x10012xxxxxxxxxx -x20000xxxxxxxxxx -000000xxx0000012 -0000000000022000 -x000000000001000 -x10003xxx0000000 -x10002xxx0000000 -x20001xxx1200000 -xxxxxxxxx0330000 -`; +declare global { + // eslint-disable-next-line no-var + var __PIXI_APP__: Application; +} -const room: Room = new Room({ - heightMap: heightMap, - dragging: true, - centerCamera: true, - floorMaterial: new FloorMaterial(101), - floorThickness: 8, - wallHidden: true, - wallMaterial: new WallMaterial(108), - wallThickness: 8, - wallHeight: -1, - landscapeMaterial: new LandscapeMaterial(101), -}); +export function preload(app: Application): void { + // pixi-stats + const stats = addStats(document, app); + const ticker = Ticker.shared; + ticker.add(stats.update, stats, UPDATE_PRIORITY.UTILITY); -renderer.add(room); + // pixi dev-tools + globalThis.__PIXI_APP__ = app; +} + +if (import.meta.hot) { + import.meta.hot.accept(() => { + const stats = document.getElementById('stats'); + stats?.remove(); + }); +} diff --git a/public/assets/test.ts b/public/assets/test.ts new file mode 100644 index 00000000..29efc0e1 --- /dev/null +++ b/public/assets/test.ts @@ -0,0 +1,40 @@ +import { FloorMaterial, WallMaterial } from '../../src/objects/rooms/materials'; +import { Room } from '../../src/objects/rooms'; +import { Scuti } from '../../src/Scuti'; +import { preload } from './main'; + +export const renderer: Scuti = new Scuti({ + canvas: document.getElementById('app') as HTMLCanvasElement, + resources: 'http://127.0.0.1:8081', + backgroundColor: 0x0c567c, + zoom: { direction: 'center' }, + preload, +}); + +await renderer.load(); + +const heightMap: string = ` +x10012xxxxxxxxxx +x20000xxxxxxxxxx +000000xxx0000012 +0000000000022000 +x000000000001000 +x10003xxx0000000 +x10002xxx0000000 +x20001xxx1200000 +xxxxxxxxx0330000 +`; + +const room: Room = new Room({ + heightMap: heightMap, + dragging: true, + centerCamera: true, + floorMaterial: new FloorMaterial(101), + floorThickness: 8, + wallHidden: true, + wallMaterial: new WallMaterial(108), + wallThickness: 8, + wallHeight: -1, +}); + +renderer.add(room); diff --git a/public/assets/main2.ts b/public/assets/test2.ts similarity index 100% rename from public/assets/main2.ts rename to public/assets/test2.ts diff --git a/public/assets/main3.ts b/public/assets/test3.ts similarity index 100% rename from public/assets/main3.ts rename to public/assets/test3.ts diff --git a/public/assets/vite.svg b/public/assets/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/public/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/index.html b/public/index.html index 40be0fe2..ccfcaa61 100644 --- a/public/index.html +++ b/public/index.html @@ -1,15 +1,14 @@ - Vite + TS + Scuti (Pixi + TS) - + + -
-
-
+ diff --git a/public/vite.config.js b/public/vite.config.js index 2fdc7a24..2cbd0394 100644 --- a/public/vite.config.js +++ b/public/vite.config.js @@ -2,5 +2,6 @@ import { defineConfig } from 'vite'; export default defineConfig({ root: 'public', + clearScreen: false, build: { target: 'esnext' }, }); diff --git a/src/Scuti.ts b/src/Scuti.ts index 71bc58e7..1761acaf 100644 --- a/src/Scuti.ts +++ b/src/Scuti.ts @@ -1,40 +1,44 @@ -import { Application, BaseTexture, Color, Container, extensions, SCALE_MODES, settings, Ticker, UPDATE_PRIORITY } from 'pixi.js'; +import { Application, BaseTexture, Color, Container, extensions, SCALE_MODES, settings } from 'pixi.js'; import { GameObject } from './objects/GameObject'; import { register } from './utils/Assets'; import { Layer, Stage } from '@pixi/layers'; -import { addStats, StatsJSAdapter } from 'pixi-stats'; import { Configuration, ScutiConfiguration } from './ScutiConfiguration'; import { loadBundle } from './objects/parsers/BundleParser'; import { log } from './utils/Logger'; import { benchmark } from './utils/Benchmark'; import { loadData } from './objects/parsers/DataParser'; import { ScutiData } from './ScutiData'; +import { Room } from '.'; export class Scuti { public configuration: ScutiConfiguration; - public canvas!: HTMLElement; + public canvas!: ScutiConfiguration['canvas']; public application!: Application; public layer: Layer = new Layer(); public data!: ScutiData; + private _rooms: Room[] = []; + constructor(configuration: Omit) { log('🚀 SCUTI', 'v0.0.0'); + console.log(this.application); + this.configuration = new ScutiConfiguration({ ...configuration, ...{ renderer: this } }); this._initialize(); } private _initialize(): void { const { perf } = benchmark('renderer'); - // Pixi settings + extensions.add(loadBundle); extensions.add(loadData); settings.ROUND_PIXELS = true; Container.defaultSortableChildren = false; BaseTexture.defaultOptions.scaleMode = SCALE_MODES.NEAREST; - // Application this.application = new Application({ + view: this.configuration.canvas, width: this.configuration.width, height: this.configuration.height, antialias: false, @@ -45,17 +49,9 @@ export class Scuti { resizeTo: this.configuration.resizeTo, eventMode: 'passive', }); - this.application.stage = new Stage(); - globalThis.__PIXI_APP__ = this.application; // Pixi dev-tools - this.canvas = this.configuration.canvas; - this.canvas.append(this.application.view as HTMLCanvasElement); - - // Pixi stats - const stats: StatsJSAdapter = addStats(document, this.application); - const ticker: Ticker = Ticker.shared; - - ticker.add(stats.update, stats, UPDATE_PRIORITY.UTILITY); + this.configuration.preloadFn(this); + this.application.stage = new Stage(); this.layer.group.enableSort = true; this.application.stage.addChild(this.layer); @@ -79,5 +75,13 @@ export class Scuti { public add(item: GameObject): void { item.renderer = this; item.render(); + + if (item instanceof Room) { + this._rooms.push(item); + } + } + + public get rooms(): Room[] { + return this.rooms; } } diff --git a/src/ScutiConfiguration.ts b/src/ScutiConfiguration.ts index 0d384602..65e08125 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -5,13 +5,14 @@ import { registerPath } from './utils/Assets'; export interface Configuration { renderer: Scuti; resources: string; - canvas: HTMLElement; + canvas: HTMLCanvasElement; width?: number; height?: number; backgroundColor?: number; backgroundAlpha?: number; resizeTo?: HTMLElement | Window; zoom?: Partial; + preload?: (app: Scuti['application']) => void; } interface ZoomConfiguration { @@ -27,15 +28,16 @@ interface ZoomConfiguration { export class ScutiConfiguration { public renderer: Scuti; - private _canvas: HTMLElement; - private _width: number; - private _height: number; - private _backgroundColor: number; - private _backgroundAlpha: number; + private _canvas: Configuration['canvas']; + private _width: Configuration['width']; + private _height: Configuration['height']; + private _backgroundColor: Configuration['backgroundColor']; + private _backgroundAlpha: Configuration['backgroundAlpha']; private _resizeTo: Configuration['resizeTo']; + private _preload: Configuration['preload']; private _zoom: Configuration['zoom']; - constructor({ canvas, width, height, backgroundColor, backgroundAlpha, resizeTo, resources, renderer, zoom }: Configuration) { + constructor({ canvas, width, height, backgroundColor, backgroundAlpha, resizeTo, resources, renderer, preload, zoom }: Configuration) { this.renderer = renderer; this._canvas = canvas; @@ -45,52 +47,53 @@ export class ScutiConfiguration { this._backgroundAlpha = backgroundAlpha ?? 1; this._resizeTo = resizeTo ?? window; this._zoom = { wheel: true, level: 2, min: 0.5, max: 8, step: 0.5, duration: 0.125, direction: 'center', ...zoom }; + this._preload = preload; registerPath(resources); } - public get canvas(): HTMLElement { + public get canvas(): Configuration['canvas'] { return this._canvas; } - public set canvas(element: HTMLElement) { + public set canvas(element: Configuration['canvas']) { this._canvas = element; this.renderer.canvas = element; this.renderer.canvas.append(this.renderer.application.view as HTMLCanvasElement); } - public get width(): number { + public get width(): Configuration['width'] { return this._width; } - public set width(width: number) { + public set width(width: NonNullable) { this._width = width; this.renderer.application.renderer.view.width = width; } - public get height(): number { + public get height(): Configuration['height'] { return this._height; } - public set height(height: number) { + public set height(height: NonNullable) { this._height = height; this.renderer.application.renderer.view.height = height; } - public get backgroundColor(): number { + public get backgroundColor(): Configuration['backgroundColor'] { return this._backgroundColor; } - public set backgroundColor(color: number) { + public set backgroundColor(color: NonNullable) { this._backgroundColor = color; this.renderer.application.renderer.background.color = new Color(color); } - public get backgroundAlpha(): number { + public get backgroundAlpha(): Configuration['backgroundAlpha'] { return this._backgroundAlpha; } - public set backgroundAlpha(alpha: number) { + public set backgroundAlpha(alpha: NonNullable) { this._backgroundAlpha = alpha; this.renderer.application.renderer.background.alpha = alpha; } @@ -103,6 +106,10 @@ export class ScutiConfiguration { this.renderer.application.resizeTo = element; } + public preloadFn(app: Scuti): void { + this._preload?.(app.application); + } + public get zoom(): Configuration['zoom'] { return this._zoom; } diff --git a/src/types/Globals.d.ts b/src/types/Globals.d.ts deleted file mode 100644 index 03456924..00000000 --- a/src/types/Globals.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { Application, ICanvas } from 'pixi.js'; - -declare global { - var __PIXI_APP__: Application; -} diff --git a/src/types/Stair.ts b/src/types/Stair.ts index 8e5ca3f7..2d44d404 100644 --- a/src/types/Stair.ts +++ b/src/types/Stair.ts @@ -1,7 +1,7 @@ import { StairType } from '../enums/StairType'; import { Direction } from '../enums/Direction'; -export type Stair = { +export interface Stair { type: StairType; direction: Direction; -}; +} diff --git a/tsconfig.json b/tsconfig.json index 47a7728b..02a41127 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,6 @@ "skipLibCheck": true, /* Bundler mode */ - "types": ["./src/types/Globals.d.ts", "vite/client"], "moduleResolution": "bundler", "isolatedModules": true, "noEmit": true, From 20a574766bb1fe879801fb140dd1c2e997bf32d8 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Fri, 8 Mar 2024 15:41:22 +0100 Subject: [PATCH 09/13] refactor(objects/rooms/camera): improvement of life + misc --- .eslintrc.cjs | 31 -------- .eslintrc.json | 31 ++++++++ public/assets/main.ts | 5 +- public/assets/style.css | 1 + public/assets/test.ts | 27 ++++--- public/{vite.config.js => vite.config.ts} | 0 src/Scuti.ts | 2 - src/ScutiConfiguration.ts | 33 ++++++++- src/objects/rooms/Room.ts | 14 +--- src/objects/rooms/RoomCamera.ts | 87 ++++++++++++----------- src/objects/rooms/RoomVisualization.ts | 38 +--------- 11 files changed, 136 insertions(+), 133 deletions(-) delete mode 100644 .eslintrc.cjs create mode 100644 .eslintrc.json rename public/{vite.config.js => vite.config.ts} (100%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 8f09bb5a..00000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - }, - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], - overrides: [ - { - env: { - node: true, - }, - files: ['.eslintrc.{js,cjs}'], - parserOptions: { - sourceType: 'script', - }, - }, - ], - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - plugins: ['@typescript-eslint', 'prettier'], - ignorePatterns: ['/node_modules/', '**/*.d.ts'], - rules: { - 'prettier/prettier': 'error', - 'prefer-const': ['error'], - 'linebreak-style': ['error', 'unix'], - 'object-curly-spacing': ['error', 'always'], - }, -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..f2b93b68 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,31 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], + "overrides": [ + { + "env": { + "node": true + }, + "files": [".eslintrc.{js,cjs}"], + "parserOptions": { + "sourceType": "script" + } + } + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint", "prettier"], + "ignorePatterns": ["/node_modules/", "**/*.d.ts"], + "rules": { + "prettier/prettier": "error", + "prefer-const": ["error"], + "linebreak-style": ["error", "unix"], + "object-curly-spacing": ["error", "always"] + } +} diff --git a/public/assets/main.ts b/public/assets/main.ts index c69f4d75..fc5e4134 100644 --- a/public/assets/main.ts +++ b/public/assets/main.ts @@ -21,8 +21,9 @@ export function preload(app: Application): void { } if (import.meta.hot) { - import.meta.hot.accept(() => { + import.meta.hot.accept((): void => { + console.clear(); const stats = document.getElementById('stats'); - stats?.remove(); + stats!.remove(); }); } diff --git a/public/assets/style.css b/public/assets/style.css index b9323b35..52b5387a 100644 --- a/public/assets/style.css +++ b/public/assets/style.css @@ -12,6 +12,7 @@ div#stats { width: max(200px, 10vw, 10vh); height: max(100px, 6vh, 6vw); opacity: 0.8; + pointer-events: none; user-select: none; } diff --git a/public/assets/test.ts b/public/assets/test.ts index 29efc0e1..a1be1f75 100644 --- a/public/assets/test.ts +++ b/public/assets/test.ts @@ -8,6 +8,7 @@ export const renderer: Scuti = new Scuti({ resources: 'http://127.0.0.1:8081', backgroundColor: 0x0c567c, zoom: { direction: 'center' }, + // camera: { position: { x: 200, y: 200 } }, preload, }); @@ -16,19 +17,29 @@ await renderer.load(); const heightMap: string = ` x10012xxxxxxxxxx x20000xxxxxxxxxx -000000xxx0000012 -0000000000022000 -x000000000001000 -x10003xxx0000000 -x10002xxx0000000 -x20001xxx1200000 -xxxxxxxxx0330000 +000000xxx0000000 +0000000000021000 +x000111111111000 +x100020000010000 +x10001x000010100 +x20001x000010000 +xxxxx00001030000 +xxxx1002241xxxxx +xxxx00006100xxxx +xxxx1000000000xx +xxxxxxx0x0000xxx +xxxx200000x00xxx +xxxx100010xxxxxx +xxxx000001xxxxxx +xxxx020000xxxxxx +xxx2112001xxxxxx +xxx000011xxxxxxx +xxx00xxxxxxxxxxx `; const room: Room = new Room({ heightMap: heightMap, dragging: true, - centerCamera: true, floorMaterial: new FloorMaterial(101), floorThickness: 8, wallHidden: true, diff --git a/public/vite.config.js b/public/vite.config.ts similarity index 100% rename from public/vite.config.js rename to public/vite.config.ts diff --git a/src/Scuti.ts b/src/Scuti.ts index 1761acaf..72103dfc 100644 --- a/src/Scuti.ts +++ b/src/Scuti.ts @@ -22,8 +22,6 @@ export class Scuti { constructor(configuration: Omit) { log('🚀 SCUTI', 'v0.0.0'); - console.log(this.application); - this.configuration = new ScutiConfiguration({ ...configuration, ...{ renderer: this } }); this._initialize(); } diff --git a/src/ScutiConfiguration.ts b/src/ScutiConfiguration.ts index 65e08125..9168c2f8 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -1,6 +1,7 @@ import { Scuti } from './Scuti'; import { Color } from 'pixi.js'; import { registerPath } from './utils/Assets'; +import { Vector2D } from '.'; export interface Configuration { renderer: Scuti; @@ -12,6 +13,7 @@ export interface Configuration { backgroundAlpha?: number; resizeTo?: HTMLElement | Window; zoom?: Partial; + camera?: Partial; preload?: (app: Scuti['application']) => void; } @@ -25,6 +27,11 @@ interface ZoomConfiguration { direction: 'cursor' | 'center'; } +interface CameraConfiguration { + center: boolean; + position: Partial; +} + export class ScutiConfiguration { public renderer: Scuti; @@ -36,8 +43,21 @@ export class ScutiConfiguration { private _resizeTo: Configuration['resizeTo']; private _preload: Configuration['preload']; private _zoom: Configuration['zoom']; - - constructor({ canvas, width, height, backgroundColor, backgroundAlpha, resizeTo, resources, renderer, preload, zoom }: Configuration) { + private _camera: Configuration['camera']; + + constructor({ + canvas, + width, + height, + backgroundColor, + backgroundAlpha, + resizeTo, + resources, + renderer, + preload, + zoom, + camera, + }: Configuration) { this.renderer = renderer; this._canvas = canvas; @@ -47,6 +67,7 @@ export class ScutiConfiguration { this._backgroundAlpha = backgroundAlpha ?? 1; this._resizeTo = resizeTo ?? window; this._zoom = { wheel: true, level: 2, min: 0.5, max: 8, step: 0.5, duration: 0.125, direction: 'center', ...zoom }; + this._camera = { center: true, ...camera, position: { x: 0, y: 0, ...camera?.position } }; this._preload = preload; registerPath(resources); @@ -117,4 +138,12 @@ export class ScutiConfiguration { public set zoom(zoom: Configuration['zoom']) { this._zoom = zoom; } + + public get camera(): Configuration['camera'] { + return this._camera; + } + + public set camera(camera: Configuration['camera']) { + this._camera = camera; + } } diff --git a/src/objects/rooms/Room.ts b/src/objects/rooms/Room.ts index 49334406..cac4a962 100644 --- a/src/objects/rooms/Room.ts +++ b/src/objects/rooms/Room.ts @@ -21,7 +21,6 @@ interface Configuration { wallHidden?: boolean; landscapeMaterial?: LandscapeMaterial; dragging?: boolean; - centerCamera?: boolean; } export class Room extends GameObject { @@ -42,7 +41,6 @@ export class Room extends GameObject { private _wallHeight: number; private _landscapeMaterial: LandscapeMaterial; private _dragging: boolean; - private _centerCamera: boolean; constructor({ heightMap, @@ -55,7 +53,6 @@ export class Room extends GameObject { wallHidden, landscapeMaterial, dragging, - centerCamera, }: Configuration) { super(); @@ -69,7 +66,6 @@ export class Room extends GameObject { this._wallHeight = wallHeight ?? 0; this._landscapeMaterial = landscapeMaterial ?? new LandscapeMaterial(101); this._dragging = dragging ?? true; - this._centerCamera = centerCamera ?? true; this._floorMaterial.room = this; this._wallMaterial.room = this; @@ -83,7 +79,7 @@ export class Room extends GameObject { //this.renderer.application.ticker.maxFPS = 144; todo(): Add configurable FPS this.visualization.render(); - this.renderer.application.stage.addChild(this.camera.container!); + this.renderer.application.stage.addChild(this.visualization.container); } public update({ parts, objects, cursor, mesher }: UpdateConfiguration): void { @@ -225,12 +221,4 @@ export class Room extends GameObject { public set dragging(dragging: boolean) { this._dragging = dragging; } - - public get centerCamera(): boolean { - return this._centerCamera; - } - - public set centerCamera(centerCamera: boolean) { - this._centerCamera = centerCamera; - } } diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 75865d93..8931fdbb 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -1,10 +1,8 @@ import { Room } from './Room'; -import { Container, Matrix, Point, RenderTexture } from 'pixi.js'; +import { Matrix, Point, RenderTexture } from 'pixi.js'; import { gsap } from 'gsap'; export class RoomCamera { - public container: Container | undefined = new Container(); - public zooming: boolean = false; public dragging: boolean = false; public hasDragged: boolean = false; @@ -14,10 +12,8 @@ export class RoomCamera { constructor(public room: Room) { this._initListeners(); - this.container!.addChild(room.visualization!.container); } - // todo(): removeEventListener when destroying containers private _initListeners(): void { const events = this.room.renderer.application.renderer.events.domElement; @@ -46,7 +42,7 @@ export class RoomCamera { } } - private _onZoom = (event: WheelEvent): void => { + private _onZoom(event: WheelEvent): void { const zoom = this.room.renderer.configuration.zoom!; const { step, level, min, max } = zoom; @@ -55,54 +51,64 @@ export class RoomCamera { if (level === zoom.level && (level === min || level === max)) return; this.zoom(zoom.level!, zoom.duration!); - }; + } - private _dragStart = (): void => { + private _dragStart(): void { if (Date.now() - this._lastClickTime > this._clickThreshold) { this.dragging = true; } - }; + } - private _dragEnd = (): void => { + private _dragEnd(): void { this.hasDragged = false; this.dragging = false; this._lastClickTime = Date.now(); - if (this.isOutOfBounds() && this.room.centerCamera) this.centerCamera(); - }; + if (this.isOutOfBounds() && this.room.renderer.configuration.camera?.center) this.centerCamera(); + } - private _dragMove = (event: PointerEvent): void => { + private _dragMove(event: PointerEvent): void { if (this.dragging) { + const container = this.room.visualization!.container; + this.hasDragged = true; - this.container!.pivot.x -= event.movementX / (this.container!.scale.x * devicePixelRatio); - this.container!.pivot.y -= event.movementY / (this.container!.scale.y * devicePixelRatio); + + container.pivot.x -= event.movementX / (container.scale.x * devicePixelRatio); + container.pivot.y -= event.movementY / (container.scale.y * devicePixelRatio); } - }; + } + + public _positionate(): void { + const container = this.room.visualization!.container; + const camera = this.room.renderer.configuration.camera!; + const bounds = container.getBounds(); + + // ts is dumb, camera.position values are always defined in scuticonfig + container.pivot.x = bounds.right - container.width / 2 - camera.position.x; + container.pivot.y = bounds.bottom - container.height / 2 - camera.position.y; + container.x = this.room.renderer.application.view.width / 2; + container.y = this.room.renderer.application.view.height / 2; + } public isOutOfBounds(): boolean { - const { x, y } = this.container!.pivot; + const container = this.room.visualization!.container; + const containerBounds = container.getBounds(); const { width, height } = this.room.renderer.application.view; - const { x: scaleX, y: scaleY } = { x: this.container!.scale.x * devicePixelRatio, y: this.container!.scale.y * devicePixelRatio }; - const { width: scaledWidth, height: scaledHeight } = { width: width / scaleX / 2, height: height / scaleY / 2 }; return ( - x - scaledWidth > this.container!.width / scaleX || - x + scaledWidth < 0 || - y - scaledHeight > this.container!.height / scaleY || - y + scaledHeight < 0 + containerBounds.right < 0 || + containerBounds.left > width / container.scale.x || + containerBounds.top > height / container.scale.y || + containerBounds.bottom < 0 ); } public centerCamera(duration: number = 0.6): void { - gsap.to(this.container!, { - x: Math.floor(this.room.renderer.application.view.width / 2), - y: Math.floor(this.room.renderer.application.view.height / 2), - duration, - ease: 'expo.inOut', - }); - gsap.to(this.container!.pivot, { - x: Math.floor(this.container!.width / this.container!.scale.x / 2), - y: Math.floor(this.container!.height / this.container!.scale.y / 2), + const container = this.room.visualization!.container; + + gsap.to(container.pivot, { + x: Math.floor(container._localBounds.maxX - container.width / 2), + y: Math.floor(container._localBounds.maxY - container.height / 2), duration, ease: 'expo.inOut', }); @@ -117,23 +123,25 @@ export class RoomCamera { this.zooming = true; }, onComplete: () => { - if (this.isOutOfBounds() && this.room.centerCamera) this.centerCamera(); + if (this.isOutOfBounds() && this.room.renderer.configuration.camera?.center) this.centerCamera(); this.zooming = false; }, }; + const container = this.room.visualization!.container; + if (this.room.renderer.configuration.zoom?.direction === 'cursor') { const pointer = Object.assign({}, this.room.renderer.application.renderer.events.pointer.global); - const { x: x1, y: y1 } = this.container!.toLocal(pointer); + const { x: x1, y: y1 } = container.toLocal(pointer); options.onUpdate = () => { - const { x: x2, y: y2 } = this.container!.toLocal(pointer); - this.container!.pivot.x += x1 - x2; - this.container!.pivot.y += y1 - y2; + const { x: x2, y: y2 } = container.toLocal(pointer); + container.pivot.x += x1 - x2; + container.pivot.y += y1 - y2; }; } - gsap.to(this.container!.scale, options); + gsap.to(container.scale, options); } public async screenshot(target: HTMLElement): Promise { @@ -152,8 +160,7 @@ export class RoomCamera { } public destroy(): void { - if (this.container != undefined) { - this.container.destroy(); + if (this.room.visualization?.container != undefined) { this.unBindListeners(); } } diff --git a/src/objects/rooms/RoomVisualization.ts b/src/objects/rooms/RoomVisualization.ts index a3d0efec..00580272 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -17,7 +17,6 @@ import { LandscapeWindowMask } from './parts/wall/landscapes/layers/items/Landsc import { RoomObject } from './objects/RoomObject'; import { ObjectLayer } from './layers/ObjectLayer'; import { landscapeOrder } from '../../utils'; -import { Direction, StairType } from '../..'; interface RoomLayers { parts: PartLayer; @@ -147,45 +146,14 @@ export class RoomVisualization { this.renderFloors(); this.renderWalls(); + this.room.camera!._positionate(); if (this.layers.masks.childrens.length > 0) this.renderLandscapes(); perf(); - - // Resets room position to the top-left corner by default - this.container.pivot.x = this.container.getBounds().left; - this.container.pivot.y = this.container.getBounds().top; - - this.room.camera!.centerCamera(0); } public renderFloors(): void { - const stair = new StairPart({ - material: this.room.floorMaterial, - position: { x: 0, y: 0, z: 0 }, - length: 1, - thickness: this.room.floorThickness, - direction: Direction.WEST, - corners: { - left: StairType.STAIR, - right: StairType.TWIN_CORNER_STAIR, - }, - }); - - const stair2 = new StairPart({ - material: this.room.floorMaterial, - position: { x: 0, y: 0, z: 0 }, - length: 1, - thickness: this.room.floorThickness, - direction: Direction.NORTH, - corners: { - left: StairType.TWIN_CORNER_STAIR, - right: StairType.STAIR, - }, - }); - - [stair, stair2].forEach(stair => this.add(stair)); - - /* if (!this.room.floorHidden) { + if (!this.room.floorHidden) { this.greedyMesher.tiles.forEach((tile: TileMesh): void => this._registerFloorPart( new TilePart({ @@ -210,7 +178,7 @@ export class RoomVisualization { }), ), ); - } */ + } } public renderWalls(): void { From 28a52bd3d4b575c226beeb60c7a2aa9bf0e5ba59 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Fri, 8 Mar 2024 17:40:28 +0100 Subject: [PATCH 10/13] test: something ain't right --- public/assets/test.ts | 2 - src/ScutiConfiguration.ts | 57 +++++++++++---------- src/objects/rooms/RoomCamera.ts | 22 ++++---- src/objects/rooms/RoomVisualization.ts | 3 +- src/objects/rooms/geometry/Cube.ts | 2 - src/objects/rooms/geometry/GreedyMesher.ts | 2 - src/objects/rooms/parts/floor/CursorPart.ts | 4 +- src/objects/rooms/parts/floor/StairPart.ts | 6 ++- 8 files changed, 51 insertions(+), 47 deletions(-) diff --git a/public/assets/test.ts b/public/assets/test.ts index a1be1f75..97cc4ad6 100644 --- a/public/assets/test.ts +++ b/public/assets/test.ts @@ -7,8 +7,6 @@ export const renderer: Scuti = new Scuti({ canvas: document.getElementById('app') as HTMLCanvasElement, resources: 'http://127.0.0.1:8081', backgroundColor: 0x0c567c, - zoom: { direction: 'center' }, - // camera: { position: { x: 200, y: 200 } }, preload, }); diff --git a/src/ScutiConfiguration.ts b/src/ScutiConfiguration.ts index 9168c2f8..2f95eb27 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -17,6 +17,10 @@ export interface Configuration { preload?: (app: Scuti['application']) => void; } +type Require = { + [K in keyof T]: T[K] extends object ? Required : T[K]; +}; + interface ZoomConfiguration { wheel: boolean; level: number; @@ -36,14 +40,14 @@ export class ScutiConfiguration { public renderer: Scuti; private _canvas: Configuration['canvas']; - private _width: Configuration['width']; - private _height: Configuration['height']; - private _backgroundColor: Configuration['backgroundColor']; - private _backgroundAlpha: Configuration['backgroundAlpha']; - private _resizeTo: Configuration['resizeTo']; + private _width: NonNullable; + private _height: NonNullable; + private _backgroundColor: NonNullable; + private _backgroundAlpha: NonNullable; + private _resizeTo: NonNullable; private _preload: Configuration['preload']; - private _zoom: Configuration['zoom']; - private _camera: Configuration['camera']; + private _zoom: Require; + private _camera: Require; constructor({ canvas, @@ -73,77 +77,78 @@ export class ScutiConfiguration { registerPath(resources); } + public preloadFn(app: Scuti): void { + if (this._preload == undefined) return; + this._preload(app.application); + } + public get canvas(): Configuration['canvas'] { return this._canvas; } - public set canvas(element: Configuration['canvas']) { + public set canvas(element: typeof this._canvas) { this._canvas = element; this.renderer.canvas = element; this.renderer.canvas.append(this.renderer.application.view as HTMLCanvasElement); } - public get width(): Configuration['width'] { + public get width(): typeof this._width { return this._width; } - public set width(width: NonNullable) { + public set width(width: typeof this._width) { this._width = width; this.renderer.application.renderer.view.width = width; } - public get height(): Configuration['height'] { + public get height(): typeof this._height { return this._height; } - public set height(height: NonNullable) { + public set height(height: typeof this._height) { this._height = height; this.renderer.application.renderer.view.height = height; } - public get backgroundColor(): Configuration['backgroundColor'] { + public get backgroundColor(): typeof this._backgroundColor { return this._backgroundColor; } - public set backgroundColor(color: NonNullable) { + public set backgroundColor(color: typeof this._backgroundColor) { this._backgroundColor = color; this.renderer.application.renderer.background.color = new Color(color); } - public get backgroundAlpha(): Configuration['backgroundAlpha'] { + public get backgroundAlpha(): typeof this._backgroundAlpha { return this._backgroundAlpha; } - public set backgroundAlpha(alpha: NonNullable) { + public set backgroundAlpha(alpha: typeof this._backgroundAlpha) { this._backgroundAlpha = alpha; this.renderer.application.renderer.background.alpha = alpha; } - public get resizeTo(): Configuration['resizeTo'] { + public get resizeTo(): typeof this._resizeTo { return this._resizeTo; } - public set resizeTo(element: NonNullable) { + public set resizeTo(element: typeof this._resizeTo) { this.renderer.application.resizeTo = element; } - public preloadFn(app: Scuti): void { - this._preload?.(app.application); - } - - public get zoom(): Configuration['zoom'] { + public get zoom(): typeof this._zoom { return this._zoom; } - public set zoom(zoom: Configuration['zoom']) { + public set zoom(zoom: typeof this._zoom) { this._zoom = zoom; } - public get camera(): Configuration['camera'] { + public get camera(): typeof this._camera { return this._camera; } - public set camera(camera: Configuration['camera']) { + public set camera(camera: typeof this._camera) { this._camera = camera; } } diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 8931fdbb..5d004b51 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -17,7 +17,7 @@ export class RoomCamera { private _initListeners(): void { const events = this.room.renderer.application.renderer.events.domElement; - if (this.room.renderer.configuration.zoom?.wheel) { + if (this.room.renderer.configuration.zoom.wheel) { events.addEventListener('wheel', this._onZoom, { passive: true }); } @@ -31,7 +31,7 @@ export class RoomCamera { private unBindListeners(): void { const events = this.room.renderer.application.renderer.events.domElement; - if (this.room.renderer.configuration.zoom?.wheel) { + if (this.room.renderer.configuration.zoom.wheel) { events.removeEventListener('wheel', this._onZoom); } @@ -43,14 +43,15 @@ export class RoomCamera { } private _onZoom(event: WheelEvent): void { - const zoom = this.room.renderer.configuration.zoom!; + console.log(this); + const zoom = this.room.renderer.configuration.zoom; const { step, level, min, max } = zoom; - zoom.level = Math.max(min!, Math.min(max!, level! + (event.deltaY > 0 ? -step! : step!))); + zoom.level = Math.max(min, Math.min(max, level + (event.deltaY > 0 ? -step : step))); if (level === zoom.level && (level === min || level === max)) return; - this.zoom(zoom.level!, zoom.duration!); + this.zoom(zoom.level, zoom.duration); } private _dragStart(): void { @@ -64,7 +65,7 @@ export class RoomCamera { this.dragging = false; this._lastClickTime = Date.now(); - if (this.isOutOfBounds() && this.room.renderer.configuration.camera?.center) this.centerCamera(); + if (this.isOutOfBounds() && this.room.renderer.configuration.camera.center) this.centerCamera(); } private _dragMove(event: PointerEvent): void { @@ -80,10 +81,9 @@ export class RoomCamera { public _positionate(): void { const container = this.room.visualization!.container; - const camera = this.room.renderer.configuration.camera!; + const camera = this.room.renderer.configuration.camera; const bounds = container.getBounds(); - // ts is dumb, camera.position values are always defined in scuticonfig container.pivot.x = bounds.right - container.width / 2 - camera.position.x; container.pivot.y = bounds.bottom - container.height / 2 - camera.position.y; container.x = this.room.renderer.application.view.width / 2; @@ -123,14 +123,14 @@ export class RoomCamera { this.zooming = true; }, onComplete: () => { - if (this.isOutOfBounds() && this.room.renderer.configuration.camera?.center) this.centerCamera(); + if (this.isOutOfBounds() && this.room.renderer.configuration.camera.center) this.centerCamera(); this.zooming = false; }, }; const container = this.room.visualization!.container; - if (this.room.renderer.configuration.zoom?.direction === 'cursor') { + if (this.room.renderer.configuration.zoom.direction === 'cursor') { const pointer = Object.assign({}, this.room.renderer.application.renderer.events.pointer.global); const { x: x1, y: y1 } = container.toLocal(pointer); @@ -160,7 +160,7 @@ export class RoomCamera { } public destroy(): void { - if (this.room.visualization?.container != undefined) { + if (this.room.visualization!.container != undefined) { this.unBindListeners(); } } diff --git a/src/objects/rooms/RoomVisualization.ts b/src/objects/rooms/RoomVisualization.ts index 00580272..ad1e0f1b 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -146,9 +146,10 @@ export class RoomVisualization { this.renderFloors(); this.renderWalls(); - this.room.camera!._positionate(); if (this.layers.masks.childrens.length > 0) this.renderLandscapes(); + this.room.camera!._positionate(); + perf(); } diff --git a/src/objects/rooms/geometry/Cube.ts b/src/objects/rooms/geometry/Cube.ts index d9246a3d..5e6a341a 100644 --- a/src/objects/rooms/geometry/Cube.ts +++ b/src/objects/rooms/geometry/Cube.ts @@ -38,8 +38,6 @@ export class Cube extends Container { -0.5, this.configuration.offsets?.[CubeFace.TOP]?.x ?? 0, this.configuration.offsets?.[CubeFace.TOP]?.y ?? 0, - //1 % 2 === 0 ? 32 : 64, - //1 % 2 === 0 ? 16 : 0 ), }) .moveTo(0, 0) diff --git a/src/objects/rooms/geometry/GreedyMesher.ts b/src/objects/rooms/geometry/GreedyMesher.ts index 6bac8445..6fbb32ef 100644 --- a/src/objects/rooms/geometry/GreedyMesher.ts +++ b/src/objects/rooms/geometry/GreedyMesher.ts @@ -127,7 +127,6 @@ export class GreedyMesher { const stair: Stair | undefined = this.heightMap.getStair({ x, y: y - 1 }, 'y'); if (!stair || !currentStair) continue; - console.log(stair, currentStair); if ([Direction.WEST, Direction.EAST].includes(stair.direction) || stair.type !== StairType.STAIR) { if (this.heightMap.getTileHeight({ x, y }) === this.heightMap.getTileHeight({ x, y: y - 1 })) { if ( @@ -201,7 +200,6 @@ export class GreedyMesher { // Check if it's a tiny stair if (size.x === 1 && size.y === 1) { - // || leftStair.direction === Direction.NORTH_WEST if (leftStair.direction === Direction.NORTH_EAST || leftStair.direction === Direction.NORTH_WEST) { rightStair.type = StairType.STAIR; } else if (leftStair.direction === Direction.SOUTH_EAST || leftStair.direction === Direction.SOUTH_WEST) { diff --git a/src/objects/rooms/parts/floor/CursorPart.ts b/src/objects/rooms/parts/floor/CursorPart.ts index cde77824..76813ae9 100644 --- a/src/objects/rooms/parts/floor/CursorPart.ts +++ b/src/objects/rooms/parts/floor/CursorPart.ts @@ -48,8 +48,8 @@ export class CursorPart extends RoomPart { public move({ x, y, z }: Vector3D): void { this._position = { x, y, z }; - this.container!.x = 32 * x - 32 * y - 0.75; - this.container!.y = 16 * x + 16 * y - 32 * z - 19.25; + this.container!.x = 32 * x - 32 * y - 1; + this.container!.y = 16 * x + 16 * y - 32 * z - 19; if (this.room.parsedHeightMap.door) { if (this.room.parsedHeightMap.door.x === x && this.room.parsedHeightMap.door.y === y) { diff --git a/src/objects/rooms/parts/floor/StairPart.ts b/src/objects/rooms/parts/floor/StairPart.ts index 45242bcb..df6b50f6 100644 --- a/src/objects/rooms/parts/floor/StairPart.ts +++ b/src/objects/rooms/parts/floor/StairPart.ts @@ -21,6 +21,10 @@ export class StairPart extends RoomPart { constructor(public configuration: Configuration) { super(); + this.container!.name = `x: ${this.configuration.position.x}, y: ${this.configuration.position.y} | ${ + StairType[this.configuration.corners.left] + } -- ${StairType[this.configuration.corners.right]}`; + this._registerEvents(); } @@ -192,7 +196,7 @@ export class StairPart extends RoomPart { if (this.configuration.corners.right === StairType.INNER_CORNER_STAIR) { if (this.configuration.direction === Direction.NORTH || this.configuration.direction === Direction.SOUTH) { - size.x -= (8 / 32) * (4 - i) + 0.25; + size.x -= (8 / 32) * (3 - i); } else if (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) { size.y -= (8 / 32) * i; } From 14d10771acb1db4239a80a230bd3f480f35e36fb Mon Sep 17 00:00:00 2001 From: Walidoux Date: Sat, 9 Mar 2024 13:28:42 +0100 Subject: [PATCH 11/13] fix: functions are not functions ? js is dumb --- src/objects/rooms/Room.ts | 1 + src/objects/rooms/RoomCamera.ts | 27 ++++++++++++-------------- src/objects/rooms/RoomVisualization.ts | 2 -- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/objects/rooms/Room.ts b/src/objects/rooms/Room.ts index cac4a962..04cb59d1 100644 --- a/src/objects/rooms/Room.ts +++ b/src/objects/rooms/Room.ts @@ -79,6 +79,7 @@ export class Room extends GameObject { //this.renderer.application.ticker.maxFPS = 144; todo(): Add configurable FPS this.visualization.render(); + this.camera._positionate(); this.renderer.application.stage.addChild(this.visualization.container); } diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 5d004b51..976d5f9b 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -14,7 +14,7 @@ export class RoomCamera { this._initListeners(); } - private _initListeners(): void { + private _initListeners() { const events = this.room.renderer.application.renderer.events.domElement; if (this.room.renderer.configuration.zoom.wheel) { @@ -42,8 +42,7 @@ export class RoomCamera { } } - private _onZoom(event: WheelEvent): void { - console.log(this); + private _onZoom = (event: WheelEvent): void => { const zoom = this.room.renderer.configuration.zoom; const { step, level, min, max } = zoom; @@ -52,23 +51,23 @@ export class RoomCamera { if (level === zoom.level && (level === min || level === max)) return; this.zoom(zoom.level, zoom.duration); - } + }; - private _dragStart(): void { + private _dragStart = (): void => { if (Date.now() - this._lastClickTime > this._clickThreshold) { this.dragging = true; } - } + }; - private _dragEnd(): void { + private _dragEnd = (): void => { this.hasDragged = false; this.dragging = false; this._lastClickTime = Date.now(); if (this.isOutOfBounds() && this.room.renderer.configuration.camera.center) this.centerCamera(); - } + }; - private _dragMove(event: PointerEvent): void { + private _dragMove = (event: PointerEvent): void => { if (this.dragging) { const container = this.room.visualization!.container; @@ -77,7 +76,7 @@ export class RoomCamera { container.pivot.x -= event.movementX / (container.scale.x * devicePixelRatio); container.pivot.y -= event.movementY / (container.scale.y * devicePixelRatio); } - } + }; public _positionate(): void { const container = this.room.visualization!.container; @@ -90,7 +89,7 @@ export class RoomCamera { container.y = this.room.renderer.application.view.height / 2; } - public isOutOfBounds(): boolean { + public isOutOfBounds = (): boolean => { const container = this.room.visualization!.container; const containerBounds = container.getBounds(); const { width, height } = this.room.renderer.application.view; @@ -101,7 +100,7 @@ export class RoomCamera { containerBounds.top > height / container.scale.y || containerBounds.bottom < 0 ); - } + }; public centerCamera(duration: number = 0.6): void { const container = this.room.visualization!.container; @@ -160,8 +159,6 @@ export class RoomCamera { } public destroy(): void { - if (this.room.visualization!.container != undefined) { - this.unBindListeners(); - } + this.unBindListeners(); } } diff --git a/src/objects/rooms/RoomVisualization.ts b/src/objects/rooms/RoomVisualization.ts index ad1e0f1b..6e4f4393 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -148,8 +148,6 @@ export class RoomVisualization { this.renderWalls(); if (this.layers.masks.childrens.length > 0) this.renderLandscapes(); - this.room.camera!._positionate(); - perf(); } From 2016d933b08c8b2d39b99c8c36434cca91987b0b Mon Sep 17 00:00:00 2001 From: Walidoux Date: Sat, 9 Mar 2024 15:41:40 +0100 Subject: [PATCH 12/13] fix(objects/rooms/camera): devicePixelRatio --- src/objects/rooms/RoomCamera.ts | 42 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 976d5f9b..33a1e61b 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -21,6 +21,14 @@ export class RoomCamera { events.addEventListener('wheel', this._onZoom, { passive: true }); } + window.addEventListener('resize', () => { + // refactor(): ugly workaround + setTimeout(() => { + this._positionate(); + this.centerCamera(0); + }, 10); + }); + if (this.room.dragging) { events.addEventListener('pointerdown', this._dragStart); events.addEventListener('pointerup', this._dragEnd); @@ -43,6 +51,8 @@ export class RoomCamera { } private _onZoom = (event: WheelEvent): void => { + if (event.ctrlKey) return event.stopPropagation(); + const zoom = this.room.renderer.configuration.zoom; const { step, level, min, max } = zoom; @@ -73,32 +83,34 @@ export class RoomCamera { this.hasDragged = true; - container.pivot.x -= event.movementX / (container.scale.x * devicePixelRatio); - container.pivot.y -= event.movementY / (container.scale.y * devicePixelRatio); + container.pivot.x -= event.movementX / container.scale.x; + container.pivot.y -= event.movementY / container.scale.y; } }; - public _positionate(): void { + public _positionate = (): void => { const container = this.room.visualization!.container; const camera = this.room.renderer.configuration.camera; + const { width: screenWidth, height: screenHeight } = this.room.renderer.application.view; + const resolution = this.room.renderer.application.renderer.resolution; const bounds = container.getBounds(); container.pivot.x = bounds.right - container.width / 2 - camera.position.x; container.pivot.y = bounds.bottom - container.height / 2 - camera.position.y; - container.x = this.room.renderer.application.view.width / 2; - container.y = this.room.renderer.application.view.height / 2; - } + container.x = screenWidth / resolution / 2; + container.y = screenHeight / resolution / 2; + }; public isOutOfBounds = (): boolean => { const container = this.room.visualization!.container; - const containerBounds = container.getBounds(); - const { width, height } = this.room.renderer.application.view; + const bounds = container.getBounds(); + const { width: screenWidth, height: screenHeight } = this.room.renderer.application.view; return ( - containerBounds.right < 0 || - containerBounds.left > width / container.scale.x || - containerBounds.top > height / container.scale.y || - containerBounds.bottom < 0 + bounds.right < 0 || + bounds.left > screenWidth / container.scale.x || + bounds.top > screenHeight / container.scale.y || + bounds.bottom < 0 ); }; @@ -106,14 +118,14 @@ export class RoomCamera { const container = this.room.visualization!.container; gsap.to(container.pivot, { - x: Math.floor(container._localBounds.maxX - container.width / 2), - y: Math.floor(container._localBounds.maxY - container.height / 2), + x: Math.floor(container._localBounds.maxX - container.width / container.scale.x / 2), + y: Math.floor(container._localBounds.maxY - container.height / container.scale.y / 2), duration, ease: 'expo.inOut', }); } - public zoom(zoom: number, duration: number = 0.8): void { + public zoom(zoom: number, duration: number = this.room.renderer.configuration.zoom.duration): void { const options: gsap.TweenVars = { x: zoom, y: zoom, From 7f5ab1efa6802eb04f9df9fcd7cc4f48a763a5cb Mon Sep 17 00:00:00 2001 From: Walidoux Date: Sat, 9 Mar 2024 15:48:52 +0100 Subject: [PATCH 13/13] fix(objects/rooms/camera): pre-zooming level --- src/ScutiConfiguration.ts | 3 ++- src/objects/rooms/Room.ts | 2 +- src/objects/rooms/RoomCamera.ts | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ScutiConfiguration.ts b/src/ScutiConfiguration.ts index 2f95eb27..23eaf6c2 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -33,6 +33,7 @@ interface ZoomConfiguration { interface CameraConfiguration { center: boolean; + speed: number; position: Partial; } @@ -71,7 +72,7 @@ export class ScutiConfiguration { this._backgroundAlpha = backgroundAlpha ?? 1; this._resizeTo = resizeTo ?? window; this._zoom = { wheel: true, level: 2, min: 0.5, max: 8, step: 0.5, duration: 0.125, direction: 'center', ...zoom }; - this._camera = { center: true, ...camera, position: { x: 0, y: 0, ...camera?.position } }; + this._camera = { center: true, speed: 0.6, ...camera, position: { x: 0, y: 0, ...camera?.position } }; this._preload = preload; registerPath(resources); diff --git a/src/objects/rooms/Room.ts b/src/objects/rooms/Room.ts index 04cb59d1..c7e6af57 100644 --- a/src/objects/rooms/Room.ts +++ b/src/objects/rooms/Room.ts @@ -79,7 +79,7 @@ export class Room extends GameObject { //this.renderer.application.ticker.maxFPS = 144; todo(): Add configurable FPS this.visualization.render(); - this.camera._positionate(); + this.camera.render(); this.renderer.application.stage.addChild(this.visualization.container); } diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 33a1e61b..1a562076 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -24,7 +24,7 @@ export class RoomCamera { window.addEventListener('resize', () => { // refactor(): ugly workaround setTimeout(() => { - this._positionate(); + this.render(); this.centerCamera(0); }, 10); }); @@ -88,7 +88,7 @@ export class RoomCamera { } }; - public _positionate = (): void => { + public render = (): void => { const container = this.room.visualization!.container; const camera = this.room.renderer.configuration.camera; const { width: screenWidth, height: screenHeight } = this.room.renderer.application.view; @@ -99,6 +99,8 @@ export class RoomCamera { container.pivot.y = bounds.bottom - container.height / 2 - camera.position.y; container.x = screenWidth / resolution / 2; container.y = screenHeight / resolution / 2; + + this.zoom(this.room.renderer.configuration.zoom.level); }; public isOutOfBounds = (): boolean => { @@ -114,7 +116,7 @@ export class RoomCamera { ); }; - public centerCamera(duration: number = 0.6): void { + public centerCamera(duration: number = this.room.renderer.configuration.camera.speed): void { const container = this.room.visualization!.container; gsap.to(container.pivot, {