diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index e46baaed..00000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,63 +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': { - 'indent': [ - 'error', - 2 - ], - 'linebreak-style': [ - 'error', - 'unix' - ], - 'quotes': [ - 'error', - 'single' - ], - 'semi': [ - 'error', - 'always' - ], - 'object-curly-spacing': [ - 'error', - 'always' - ], - 'prettier/prettier': 'error', - 'prefer-const': [ - 'error' - ] - } -}; 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/.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-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 f79bf331..c237c95c 100644 --- a/package.json +++ b/package.json @@ -9,17 +9,16 @@ "dist/*" ], "scripts": { - "dev": "vite --host", "build": "tsup", - "preview": "vite preview", + "dev": "vite serve public", + "preview": "vite build public vite preview 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", "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" @@ -28,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/logo.png b/public/assets/logo.png new file mode 100644 index 00000000..56b8afbd Binary files /dev/null and b/public/assets/logo.png differ diff --git a/public/assets/main.ts b/public/assets/main.ts index 33e1217f..fc5e4134 100644 --- a/public/assets/main.ts +++ b/public/assets/main.ts @@ -1,283 +1,29 @@ -import './style.css'; -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, - resources: 'http://127.0.0.1:8081', - backgroundColor: 0x0c567c, - //backgroundColor: 0x000000, - zoom: { type: 'both', direction: 'cursor' }, -}); +import { type Application, Ticker, UPDATE_PRIORITY, type ICanvas } from 'pixi.js'; +import { addStats } from 'pixi-stats'; -// @ts-ignore -await renderer.load(); +import('./test'); -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 -`; - -const room: Room = new Room({ - heightMap: heightMap, - dragging: true, - centerCamera: true, - floorMaterial: new FloorMaterial(101), - floorThickness: 16, - wallMaterial: new WallMaterial(108), - wallThickness: 8, - 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); +declare global { + // eslint-disable-next-line no-var + var __PIXI_APP__: Application; +} - setTimeout(() => { - room.wallHidden = false; - }, 7000); +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); - setTimeout(() => { - room.heightMap = ` -xxxxxx -x00000 -x00000 -102222 -x01111 -x00000 -x00000 -x00000 -x00000 - `; - }, 9000); + // pixi dev-tools + globalThis.__PIXI_APP__ = app; +} - 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); - } - } +if (import.meta.hot) { + import.meta.hot.accept((): void => { + console.clear(); + const stats = document.getElementById('stats'); + stats!.remove(); + }); } -*/ diff --git a/public/assets/style.css b/public/assets/style.css index 8a42b879..52b5387a 100644 --- a/public/assets/style.css +++ b/public/assets/style.css @@ -12,5 +12,14 @@ div#stats { width: max(200px, 10vw, 10vh); height: max(100px, 6vh, 6vw); opacity: 0.8; + pointer-events: none; user-select: none; } + +#preview { + position: fixed; + inset: 0; + width: 600px; + height: 250px; + overflow: auto; +} diff --git a/public/assets/test.ts b/public/assets/test.ts new file mode 100644 index 00000000..97cc4ad6 --- /dev/null +++ b/public/assets/test.ts @@ -0,0 +1,49 @@ +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, + preload, +}); + +await renderer.load(); + +const heightMap: string = ` +x10012xxxxxxxxxx +x20000xxxxxxxxxx +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, + 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 8ef5e5a9..ccfcaa61 100644 --- a/public/index.html +++ b/public/index.html @@ -1,13 +1,14 @@ + Scuti (Pixi + TS) - - Vite + TS + + + -
- + diff --git a/vite.config.js b/public/vite.config.ts similarity index 62% rename from vite.config.js rename to public/vite.config.ts index ab6e49f7..2cbd0394 100644 --- a/vite.config.js +++ b/public/vite.config.ts @@ -2,4 +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 31cde9a5..72103dfc 100644 --- a/src/Scuti.ts +++ b/src/Scuti.ts @@ -1,22 +1,24 @@ -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, perf } from './utils/Logger'; +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'); @@ -25,16 +27,16 @@ export class Scuti { } private _initialize(): void { - benchmark('renderer'); - // Pixi settings + const { perf } = benchmark('renderer'); + 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,24 +47,17 @@ export class Scuti { resizeTo: this.configuration.resizeTo, eventMode: 'passive', }); - this.application.stage = new Stage(); - globalThis.__PIXI_APP__ = this.application; // Support for PIXI.js dev-tool. - 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); - 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,11 +67,19 @@ export class Scuti { this.data = new ScutiData(); - perf('Resources', 'resources'); + perf(); } 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 0192204c..23eaf6c2 100644 --- a/src/ScutiConfiguration.ts +++ b/src/ScutiConfiguration.ts @@ -1,19 +1,26 @@ import { Scuti } from './Scuti'; import { Color } from 'pixi.js'; import { registerPath } from './utils/Assets'; +import { Vector2D } from '.'; export interface Configuration { renderer: Scuti; - canvas: HTMLElement; - width: number; - height: number; resources: string; + canvas: HTMLCanvasElement; + width?: number; + height?: number; backgroundColor?: number; backgroundAlpha?: number; resizeTo?: HTMLElement | Window; zoom?: Partial; + camera?: Partial; + preload?: (app: Scuti['application']) => void; } +type Require = { + [K in keyof T]: T[K] extends object ? Required : T[K]; +}; + interface ZoomConfiguration { wheel: boolean; level: number; @@ -24,90 +31,125 @@ interface ZoomConfiguration { direction: 'cursor' | 'center'; } +interface CameraConfiguration { + center: boolean; + speed: number; + position: Partial; +} + export class ScutiConfiguration { public renderer: Scuti; - private _canvas: HTMLElement; - private _width: number; - private _height: number; - private _backgroundColor: number; - private _backgroundAlpha: number; - private _resizeTo: Configuration['resizeTo']; - private _zoom: Configuration['zoom']; - - constructor({ canvas, width, height, backgroundColor, backgroundAlpha, resizeTo, resources, renderer, zoom }: Configuration) { + private _canvas: Configuration['canvas']; + private _width: NonNullable; + private _height: NonNullable; + private _backgroundColor: NonNullable; + private _backgroundAlpha: NonNullable; + private _resizeTo: NonNullable; + private _preload: Configuration['preload']; + private _zoom: Require; + private _camera: Require; + + constructor({ + canvas, + width, + height, + backgroundColor, + backgroundAlpha, + resizeTo, + resources, + renderer, + preload, + zoom, + camera, + }: Configuration) { 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 }; + this._camera = { center: true, speed: 0.6, ...camera, position: { x: 0, y: 0, ...camera?.position } }; + this._preload = preload; registerPath(resources); } - public get canvas(): HTMLElement { + 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: HTMLElement) { + 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(): number { + public get width(): typeof this._width { return this._width; } - public set width(width: number) { + public set width(width: typeof this._width) { this._width = width; this.renderer.application.renderer.view.width = width; } - public get height(): number { + public get height(): typeof this._height { return this._height; } - public set height(height: number) { + public set height(height: typeof this._height) { this._height = height; this.renderer.application.renderer.view.height = height; } - public get backgroundColor(): number { + public get backgroundColor(): typeof this._backgroundColor { return this._backgroundColor; } - public set backgroundColor(color: number) { + public set backgroundColor(color: typeof this._backgroundColor) { this._backgroundColor = color; this.renderer.application.renderer.background.color = new Color(color); } - public get backgroundAlpha(): number { + public get backgroundAlpha(): typeof this._backgroundAlpha { return this._backgroundAlpha; } - public set backgroundAlpha(alpha: number) { + 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 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(): typeof this._camera { + return this._camera; + } + + public set camera(camera: typeof this._camera) { + this._camera = camera; + } } 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..c7e6af57 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; @@ -20,16 +21,15 @@ interface Configuration { wallHidden?: boolean; 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; @@ -41,8 +41,6 @@ export class Room extends GameObject { private _wallHeight: number; private _landscapeMaterial: LandscapeMaterial; private _dragging: boolean; - private _centerCamera: boolean; - private _zoom: number; constructor({ heightMap, @@ -55,8 +53,6 @@ export class Room extends GameObject { wallHidden, landscapeMaterial, dragging, - centerCamera, - zoom, }: Configuration) { super(); @@ -70,8 +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._zoom = zoom ?? 1; this._floorMaterial.room = this; this._wallMaterial.room = this; @@ -85,24 +79,34 @@ 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.camera.render(); + this.renderer.application.stage.addChild(this.visualization.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 { @@ -218,20 +222,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; - } - - 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..1a562076 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -1,8 +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 extends Container { +export class RoomCamera { public zooming: boolean = false; public dragging: boolean = false; public hasDragged: boolean = false; @@ -11,21 +11,24 @@ export class RoomCamera extends Container { private _clickThreshold: number = 100; constructor(public room: Room) { - super(); - - this._initializeListeners(); - - this.addChild(room.visualization.container); + this._initListeners(); } - // todo(): removeEventListener when destroying containers - private _initializeListeners(): void { + private _initListeners() { 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 }); } + window.addEventListener('resize', () => { + // refactor(): ugly workaround + setTimeout(() => { + this.render(); + this.centerCamera(0); + }, 10); + }); + if (this.room.dragging) { events.addEventListener('pointerdown', this._dragStart); events.addEventListener('pointerup', this._dragEnd); @@ -33,15 +36,31 @@ 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!; + if (event.ctrlKey) return event.stopPropagation(); + + 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 => { @@ -55,42 +74,60 @@ export class RoomCamera extends Container { 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 => { if (this.dragging) { + const container = this.room.visualization!.container; + this.hasDragged = true; - this.pivot.x -= event.movementX / (this.scale.x * devicePixelRatio); - this.pivot.y -= event.movementY / (this.scale.y * devicePixelRatio); + + container.pivot.x -= event.movementX / container.scale.x; + container.pivot.y -= event.movementY / container.scale.y; } }; - public isOutOfBounds(): boolean { - const { x, y } = this.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 { width: scaledWidth, height: scaledHeight } = { width: width / scaleX / 2, height: height / scaleY / 2 }; + 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; + const resolution = this.room.renderer.application.renderer.resolution; + const bounds = container.getBounds(); - return x - scaledWidth > this.width / scaleX || x + scaledWidth < 0 || y - scaledHeight > this.height / scaleY || y + scaledHeight < 0; - } + container.pivot.x = bounds.right - container.width / 2 - camera.position.x; + container.pivot.y = bounds.bottom - container.height / 2 - camera.position.y; + container.x = screenWidth / resolution / 2; + container.y = screenHeight / resolution / 2; - public centerCamera(duration: number = 0.6): void { - gsap.to(this, { - 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), + this.zoom(this.room.renderer.configuration.zoom.level); + }; + + public isOutOfBounds = (): boolean => { + const container = this.room.visualization!.container; + const bounds = container.getBounds(); + const { width: screenWidth, height: screenHeight } = this.room.renderer.application.view; + + return ( + bounds.right < 0 || + bounds.left > screenWidth / container.scale.x || + bounds.top > screenHeight / container.scale.y || + bounds.bottom < 0 + ); + }; + + public centerCamera(duration: number = this.room.renderer.configuration.camera.speed): void { + const container = this.room.visualization!.container; + + gsap.to(container.pivot, { + 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, @@ -99,23 +136,25 @@ export class RoomCamera extends Container { 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; }, }; - if (this.room.renderer.configuration.zoom?.direction === 'cursor') { + 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.toLocal(pointer); + const { x: x1, y: y1 } = 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 } = container.toLocal(pointer); + container.pivot.x += x1 - x2; + container.pivot.y += y1 - y2; }; } - gsap.to(this.scale, options); + gsap.to(container.scale, options); } public async screenshot(target: HTMLElement): Promise { @@ -132,4 +171,8 @@ export class RoomCamera extends Container { return await renderer.extract.base64(renderTexture); } + + public destroy(): void { + this.unBindListeners(); + } } diff --git a/src/objects/rooms/RoomHeightmap.ts b/src/objects/rooms/RoomHeightmap.ts index 5b008d2a..42dff22d 100644 --- a/src/objects/rooms/RoomHeightmap.ts +++ b/src/objects/rooms/RoomHeightmap.ts @@ -18,32 +18,34 @@ export class RoomHeightmap { 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 +64,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 { + 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 }; 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 +84,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 +95,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 +106,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,85 +117,89 @@ 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 }) && + const IS_NORTH_EAST_STAIR = (): boolean => this.isTile(topRightTile) && - this.getTileDifference(topRightTile, { x, y }) === 1 && - this.getTileDifference(midRightTile, { x, y }) !== 1 && - this.getTileDifference(topTile, { x, y }) !== 1 - ) { - if (this.getTileDifference(midLeftTile, { x, y }) === 1) + this.getTileHeightDiff(topRightTile, midTile) === 1 && + this.getTileHeightDiff(midRightTile, 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, }; } - 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 - ) + if (IS_SOUTH_WEST_STAIR()) 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 getWall({ x, y }: Vector2D): WallType | undefined { @@ -239,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..6e4f4393 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -7,24 +7,22 @@ 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'; -type RoomLayers = { +interface RoomLayers { parts: PartLayer; masks: MaskLayer; objects: ObjectLayer; -}; +} export interface UpdateConfiguration { parts?: boolean; @@ -35,7 +33,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 +63,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 +137,7 @@ export class RoomVisualization { } public render(): void { - benchmark('room-visualization'); + const { perf } = benchmark('room-visualization'); this._registerCursor(); this._registerDoor(); @@ -150,18 +148,12 @@ export class RoomVisualization { this.renderWalls(); if (this.layers.masks.childrens.length > 0) this.renderLandscapes(); - perf('Room Visualization', 'room-visualization'); - - // 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); + perf(); } public renderFloors(): void { if (!this.room.floorHidden) { - this.greedyMesher.tiles.forEach((tile: TileMesh, index: number): void => + this.greedyMesher.tiles.forEach((tile: TileMesh): void => this._registerFloorPart( new TilePart({ material: this.room.floorMaterial, @@ -222,7 +214,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 +228,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 +264,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..5e6a341a 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(); @@ -37,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 9d7f1705..6fbb32ef 100644 --- a/src/objects/rooms/geometry/GreedyMesher.ts +++ b/src/objects/rooms/geometry/GreedyMesher.ts @@ -1,30 +1,22 @@ 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) {} 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 +39,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; } @@ -88,171 +78,146 @@ 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) { - 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; + + 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 }; } } } - 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 }, 'x'); + const stair: Stair | undefined = this.heightMap.getStair({ x: x - 1, y }, 'x'); + + if (!stair || !currentStair) continue; + 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; + 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 }, 'y'); + const stair: Stair | undefined = this.heightMap.getStair({ x, y: y - 1 }, 'y'); + + if (!stair || !currentStair) continue; + 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 || 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; + columnStairSizes[y - 1][x] = undefined; + } + } } } } } } - for (const y in rowStairSizes) { - for (const x in rowStairSizes[y]) { - const stair: Stair | undefined = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - }); - if (rowStairSizes[y][x] && stair) { - const length: number = Number(rowStairSizes[y][x]!.x); + 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) }, 'x')!; + + if (size) { 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; - const leftStair: Stair | undefined = this.heightMap.getStair({ - x: Number(x) - rowStairSizes[y][x]!.x + 1, - y: Number(y) - rowStairSizes[y][x]!.y + 1, - }); - - const rightStair: Stair | undefined = 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 (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.direction === Direction.SOUTH_EAST || leftStair.direction === Direction.NORTH_EAST) { + rightStair.type = StairType.STAIR; + } else if (leftStair.direction === Direction.SOUTH_WEST || leftStair.direction === 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, 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({ - x: Number(x), - y: Number(y), - }); - if (columnStairSizes[y][x] && stair) { - const length: number = Number(columnStairSizes[y][x]!.y); - let direction: Direction = stair.direction; + 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) }, 'y')!; - 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 direction: Direction = stair.direction; - const leftStair: Stair | undefined = this.heightMap.getStair({ - x: Number(x), - y: Number(y), - }); + 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 rightStair: Stair | undefined = this.heightMap.getStair({ - x: Number(x) - columnStairSizes[y][x]!.x + 1, - y: Number(y) - columnStairSizes[y][x]!.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 (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.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) { + 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, corners: { - left: leftStair ? leftStair.type : StairType.STAIR, - right: rightStair ? rightStair.type : StairType.STAIR, + left: leftStair.type, + right: rightStair.type, }, }); } @@ -273,47 +238,30 @@ 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; + + const z = this.heightMap.getTileHeight({ x, y }); + if (wall === WallType.RIGHT_WALL) { + rowWallSizes[y][x] = { x: 1, y: 1, z: z }; + } else if (wall === WallType.LEFT_WALL) { + columnWallSizes[y][x] = { x: 1, y: 1, z: z }; + } else if (wall === WallType.CORNER_WALL) { + 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, - }); - 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; - } + const wall: WallType | undefined = this.heightMap.getWall({ x: x - 1, y }); + + 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 +269,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 +298,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, }); 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..76813ae9 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 - 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) { @@ -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 cf72fa96..df6b50f6 100644 --- a/src/objects/rooms/parts/floor/StairPart.ts +++ b/src/objects/rooms/parts/floor/StairPart.ts @@ -1,224 +1,227 @@ +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, 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'; - -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; - - constructor({ material, position, thickness, length, direction, corners }: Configuration) { + constructor(public configuration: Configuration) { super(); - this._material = material ?? new FloorMaterial(101); - this._position = position; - this._thickness = thickness; - this._length = length; - this._direction = direction; - this._corners = corners; + 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(); } private _registerEvents(): void { - this.container.onpointerdown = (event: FederatedPointerEvent) => + if (this.container == undefined) return; + + 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 { + if (this.container == undefined) return; + const position = this._containerPosition(); this.container.x = position.x; this.container.y = position.y; - switch (this._direction) { - case Direction.NORTH: - this._renderStair({ - x: 8, - y: -12, - }); - break; - case Direction.WEST: - this.container.y -= 24; - 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.configuration.direction === Direction.NORTH) { + const graphics = new Graphics(); - if (this._direction === Direction.NORTH) { - this.container.hitArea = new Polygon( + const polygonPoints = [ 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(32 * (this.configuration.length + 1), 16 * (this.configuration.length - 1)), + new Point(32 * this.configuration.length, 16 * this.configuration.length), new Point(0, 0), - ); - } else if (this._direction === Direction.WEST) { - this.container.hitArea = new Polygon( + ]; + + 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 }); + } 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 * 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), - ); - } else if (this._direction === Direction.SOUTH) { + ]; + + 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 }); + } 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());*/ - } else if (this._direction === Direction.EAST) { + + 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 - 24, 40 - 12), - new Point(0 - 24, 24 - 12) - ).endFill());*/ + /* this.container.addChild( + new Graphics() + .beginFill(0xff0000, 0.3) + .drawPolygon( + new Point(0 - 24, 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 }); } - - this.container.eventMode = 'static'; } 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, - 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) * (i - 3); + 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.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.configuration.corners.right === 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.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) + (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.x += (8 / 32) * (i - 4); - } else if ( - this._corners.left === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.WEST || this._direction === Direction.EAST) - ) { - size.y -= (8 / 32) * i; + size.y -= i === 0 || i === 3 ? 0.75 : 0.5; } if ( - this._corners.right === StairType.INNER_CORNER_STAIR && - (this._direction === Direction.NORTH || this._direction === Direction.SOUTH) + (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 += (8 / 32) * (i - 4) + 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; + size.x -= i === 0 || i === 3 ? 0.75 : 0.5; } - const textureOffset: Vector2D = { - x: 0, - y: 0, - }; + 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; @@ -233,7 +236,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; @@ -250,30 +253,26 @@ 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) { - zOrders[CubeFace.TOP] += 3 + i; - zOrders[CubeFace.LEFT] += 3 + i; - zOrders[CubeFace.RIGHT] += 3 + i; - - if (this._direction === Direction.EAST) zOrders[CubeFace.RIGHT] -= 100; + 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; } 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 cube: Cube = new Cube({ layer: this.room.renderer.layer, + texture: this.configuration.material.texture, + color: this.configuration.material.color, zOrders: zOrders, - texture: material.texture, - color: material.color, size: size, offsets: { [CubeFace.TOP]: textureOffset, @@ -286,75 +285,92 @@ export class StairPart extends RoomPart { 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._direction === Direction.EAST) cube.zIndex = -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); + } - this.container.addChild(cube); + if ( + this.configuration.corners.left === StairType.TWIN_CORNER_STAIR && + (this.configuration.direction === Direction.WEST || this.configuration.direction === Direction.EAST) + ) { + cube.x += 8 * 2 + (i === 0 || i === 3 ? 8 : 0); + cube.y -= 4 * 2 + (i === 0 || i === 3 ? 4 : 0); + } + + this.container!.addChild(cube); } } - public destroy() { - if (this.container !== undefined) { + public destroy(): void { + if (this.container != undefined) { this.container.destroy(); - this.container = undefined as any; + this.container = undefined; } } 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; } 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) { + + 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; } + 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/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/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/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/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/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 }; 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 }; 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 8921d538..02a41127 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,9 +7,7 @@ "skipLibCheck": true, /* Bundler mode */ - "types": ["./src/types/Globals.d.ts"], "moduleResolution": "bundler", - "allowImportingTsExtensions": true, "isolatedModules": true, "noEmit": true, @@ -23,6 +21,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, + }), +);