From bbb1376f95e6e537fb57b48d1c74bd04b2f6ddd2 Mon Sep 17 00:00:00 2001 From: Walidoux Date: Mon, 31 Jul 2023 10:56:12 +0100 Subject: [PATCH] fix(objects/RoomCamera): not being centered correctly --- TODO.md | 24 ++- public/rooms/stairs.txt | 32 ++++ public/script.ts | 99 +++++++------ src/objects/rooms/RoomCamera.ts | 198 ++++++++++++++----------- src/objects/rooms/RoomVisualization.ts | 24 ++- 5 files changed, 232 insertions(+), 145 deletions(-) create mode 100644 public/rooms/stairs.txt diff --git a/TODO.md b/TODO.md index d1460fb..8c41657 100644 --- a/TODO.md +++ b/TODO.md @@ -1,14 +1,28 @@ # ๐Ÿ To-do's -## Rooms +- [ ] Register interactions with walls in `RoomVisualization` +- [ ] Implement Habbo-like Camera wheeling effect +- [ ] Room Camera Container not being resized when resize window event is triggered +- [ ] Hide cursor when it's out of room + Cursor broken and no interactions +- [x] Fix duplicate doors and door walls being renderer for no reason +- [x] Fix & Resolve `WallTypes` being parsed accurately on tiles. Wallw were drawn where they shoudn't. +- [x] Fix & walls of the right-hand side of the door tile +- [x] Animations `gsap.EaseFunction` not satisfied -- [ ] Jaaj +## ๐Ÿงน Future fixes + +- [ ] Stairs acting weird, see [Stairs problem](public/rooms/stairs.txt) +- [ ] `centerObject` doesn't work for furniture + +## โœจ Refactors + +- Double-check type conditions and performance with recursive in `RoomTileMap` and `RoomVisualization` ## ๐Ÿ› Patch Notes +### ๐Ÿ“† 22/07/2023 - 23/07/2023 + - Door walls: In order for the game to render the top-front wall of a door, it needs to make sure that the tile is actually a door in the first place, then it needs to check if the two neighboor tiles have walls too. - Duplicate doors: If it appears to be more than one door in a single room the game logic will pick the first one in a concurrent way. -## ๐Ÿงน Refactors - -- Look for `hasWall` method that has O(nยฒ) loop conditionals, and fix enum `WallType` type condition in `RoomTileMap` +### ๐Ÿ“† 23/07/2023 diff --git a/public/rooms/stairs.txt b/public/rooms/stairs.txt new file mode 100644 index 0000000..b61cc1a --- /dev/null +++ b/public/rooms/stairs.txt @@ -0,0 +1,32 @@ + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxxxxxxx00000000000000000000000\n' + + 'xxxxx555xxxxxxxxx0000000000000000\n' + + 'xxxxx5555555555550000000000000000\n' + + '0xxxx5555555555550000000000000000\n' + + 'xxxxx5555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'xxxxxx555555555550000000000000000\n' + + 'x00000000004400000000000000000000\n' + + 'x00000000004400000000000000000000\n' + + 'x00000000003322110000000000000000\n' + + 'x00000000003322110000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' + + 'x00000000000000000000000000000000\n' diff --git a/public/script.ts b/public/script.ts index c92ef1a..dd5ef55 100644 --- a/public/script.ts +++ b/public/script.ts @@ -4,7 +4,7 @@ import { FloorMaterial } from '../src/objects/rooms/materials/FloorMaterial' import { WallMaterial } from '../src/objects/rooms/materials/WallMaterial' import { FloorFurniture } from '../src/objects/furnitures/FloorFurniture' import { WiredSelectionFilter } from '../src/objects/filters/WiredSelectionFilter' -import { WallFurniture } from '../src' +import { Avatar, AvatarAction, WallFurniture } from '../src' // Initialising Scuti Engine ;(async () => { @@ -38,42 +38,41 @@ import { WallFurniture } from '../src' wallMaterial: new WallMaterial(renderer, 2301) }) - const furniture = new FloorFurniture({ - //id: 4950, - //id: 1619, - id: 4967, + const avatar = new Avatar({ + //figure: "hr-100-61.hd-180-7.ch-210-66.lg-270-82.sh-290-80", + // police figure: "hr-892-46.hd-209-8.ch-225-81.lg-270-64.sh-300-64.ca-1804-64.wa-2012", + figure: 'hd-209-14.ch-3688-1408.lg-280-1408.sh-290-1408.ha-1008.ea-3578.ca-1806-82.cc-3360-1408', + //figure: "hd-180-1.ch-255-66.lg-280-110.sh-305-62.ha-1012-110.hr-828-61", position: { - x: 5, + x: 4, y: 4, z: 0 }, - direction: 2, - state: 1 + bodyDirection: 6, + headDirection: 6, + actions: [ + //AvatarAction.Idle, + //AvatarAction.Walk, + AvatarAction.Talk, + AvatarAction.Wave, + //AvatarAction.Walk, + AvatarAction.CarryItem, + AvatarAction.Sit + ], + handItem: 55 }) - room.objects.add(furniture) - furniture.onPointerDown = () => { + + // ids: 4950, 1619 + const furniture = new FloorFurniture({ id: 4967, position: { x: 5, y: 4, z: 0 }, direction: 2, state: 1 }) + + // room.objects.add(avatar) + + /* furniture.onPointerDown = () => { console.log('clicked') - } - const furniture3 = new FloorFurniture({ - id: 8916, - position: { - x: 10, - y: 10, - z: 0 - }, - direction: 2, - state: 1 - }) - const furniture2 = new FloorFurniture({ - id: 8916, - position: { - x: 8, - y: 10, - z: 0 - }, - direction: 2, - state: 1 - }) + } */ + + const furniture3 = new FloorFurniture({ id: 8916, position: { x: 10, y: 10, z: 0 }, direction: 2, state: 1 }) + const furniture2 = new FloorFurniture({ id: 8916, position: { x: 8, y: 10, z: 0 }, direction: 2, state: 1 }) const wallFurniture = new WallFurniture({ id: 4625, position: { @@ -85,21 +84,21 @@ import { WallFurniture } from '../src' direction: 2, state: 2 }) + + room.objects.add(wallFurniture) + const wallFurniture2 = new WallFurniture({ id: 4032, - position: { - x: 3, - y: -1, - offsetX: 4, - offsetY: -30 - }, + position: { x: 3, y: -1, offsetX: 4, offsetY: -30 }, direction: 4, state: 1 }) - room.objects.add(furniture3) + + /* room.objects.add(furniture3) room.objects.add(furniture2) room.objects.add(wallFurniture) - room.objects.add(wallFurniture2) + room.objects.add(wallFurniture2) */ + setTimeout(() => { return wallFurniture.move({ x: -1, @@ -116,16 +115,20 @@ import { WallFurniture } from '../src' offsetY: -25 }) }, 5000) + //setTimeout(() => room.objects.add(furniture), 6000); - furniture3.onLoadComplete = () => { + + /* furniture3.onLoadComplete = () => { console.log('loaded!') } room.tiles.onPointerDown = (event) => { furniture.move(event.position) //room.tileMap = tileMap; - } + } */ + //dice(room, 5, 5, 2); - document.onkeydown = (e) => { + + /* document.onkeydown = (e) => { e = e || window.event if (e.keyCode == '38') { @@ -146,12 +149,12 @@ import { WallFurniture } from '../src' const filter = new WiredSelectionFilter(0xffffff, 0x999999) furniture.addFilter(filter) } - } + } */ })().catch((error) => { return console.error(error) }) -function dice(room, x, y, z) { +/* function dice(room, x, y, z) { const furni5 = new FloorFurniture({ position: { x, @@ -176,13 +179,11 @@ function dice(room, x, y, z) { timeout = setTimeout(() => { furni5.state = Math.floor(Math.random() * 6) + 1 }, 1000) - /*setTimeout(() => { - furni5.state = 0 - }, 2000);*/ + //setTimeout(() => furni5.state = 0, 2000) + } else { clearTimeout(timeout) furni5.state = 0 } - //x@} } -} +} */ diff --git a/src/objects/rooms/RoomCamera.ts b/src/objects/rooms/RoomCamera.ts index 0fb226c..0f9277b 100644 --- a/src/objects/rooms/RoomCamera.ts +++ b/src/objects/rooms/RoomCamera.ts @@ -1,10 +1,11 @@ -import { Container, EventBoundary, FederatedPointerEvent } from 'pixi.js'; -import { Expo, gsap } from 'gsap'; +import { Container, EventBoundary, FederatedPointerEvent, Point } from 'pixi.js' +import { Expo, gsap } from 'gsap' -import type { Room } from './Room'; -import type { Tile } from './parts/Tile'; -import type { Stair } from './parts/Stair'; -import type { RoomObject } from './objects/RoomObject'; +import type { Room } from './Room' +import type { Tile } from './parts/Tile' +import type { Stair } from './parts/Stair' +import type { RoomObject } from './objects/RoomObject' +import type { Nullable } from '../../types' /** * RoomCamera class that manage things like the room dragging or detecting if the room is out of bounds. @@ -19,7 +20,7 @@ export class RoomCamera extends Container { * @member {Room} * @private */ - private readonly _room: Room; + private readonly _room: Room /** * A boolean indicating if the room is being dragged. @@ -27,7 +28,23 @@ export class RoomCamera extends Container { * @member {boolean} * @private */ - private _dragging!: boolean; + private _dragging!: boolean + + /** + * The container that will act as a trigger to drag the room container. + * + * @member {Container} + * @private + */ + private readonly _viewContainer: Container + + /** + * The container that will contain the room. + * + * @member {Container} + * @private + */ + private readonly _roomContainer: Container /** * The current selected tile. @@ -35,7 +52,7 @@ export class RoomCamera extends Container { * @member {Tile | Stair} * @private */ - private _selectedTile!: Tile | Stair; + private _selectedTile!: Tile | Stair /** * The current zoom level. @@ -43,50 +60,58 @@ export class RoomCamera extends Container { * @member {number} * @private */ - private _zoomLevel: number; + private _zoomLevel: number /** * @param {Room} [room] - The room instance that will be managed by this camera. */ constructor(room: Room) { - super(); + super() - this._room = room; - this._zoomLevel = 1; + this._room = room + this._zoomLevel = 1 - this.addChild(this._room); + /** Initialise the view container */ + this._viewContainer = new Container() + + /** Initialise the room container */ + this._roomContainer = new Container() + this._roomContainer.addChild(this._room) + this._viewContainer.addChild(this._roomContainer) + + this.addChild(this._viewContainer) /** Handle interactions */ - this._room.engine.application.renderer.events.domElement.addEventListener('pointerdown', this._dragStart); - this._room.engine.application.renderer.events.domElement.addEventListener('pointerup', this._dragEnd); - this._room.engine.application.renderer.events.domElement.addEventListener('pointermove', this._dragMove); + this._room.engine.application.renderer.events.domElement.addEventListener('pointerdown', this._dragStart) + this._room.engine.application.renderer.events.domElement.addEventListener('pointerup', this._dragEnd) + this._room.engine.application.renderer.events.domElement.addEventListener('pointermove', this._dragMove) /** Handle tile interactions */ - this._room.engine.application.renderer.events.domElement.addEventListener('pointerdown', this._tilePointerDown); - this._room.engine.application.renderer.events.domElement.addEventListener('pointerup', this._tilePointerUp); - this._room.engine.application.renderer.events.domElement.addEventListener('pointermove', this._tilePointerMove); + this._room.engine.application.renderer.events.domElement.addEventListener('pointerdown', this._tilePointerDown) + this._room.engine.application.renderer.events.domElement.addEventListener('pointerup', this._tilePointerUp) + this._room.engine.application.renderer.events.domElement.addEventListener('pointermove', this._tilePointerMove) window.addEventListener( 'wheel', (event) => { - if (event.ctrlKey) event.preventDefault(); + if (event.ctrlKey) event.preventDefault() - const delta = Math.sign(event.deltaY); - const zoomLevel = parseFloat((-delta / 8).toFixed(2)); - if (this.zoomLevel + zoomLevel <= 0.8 || this.zoomLevel + zoomLevel >= 2.8) return; + /* const delta = Math.sign(event.deltaY) + const zoomLevel = parseFloat((-delta / 8).toFixed(2)) + if (this.zoomLevel + zoomLevel <= 0.8 || this.zoomLevel + zoomLevel >= 2.8) return - this.zoomLevel += zoomLevel; + this.zoomLevel += zoomLevel */ }, { passive: false } - ); + ) window.addEventListener('resize', () => { - this._room.engine.application.view.height = window.innerHeight; - this._room.engine.application.view.width = window.innerWidth; - }); + this._room.engine.application.view.height = window.innerHeight + this._room.engine.application.view.width = window.innerWidth + }) - this._updateBounds(); - this.centerCamera(); + this._updateBounds() + this.centerCamera(null, 0) } /** @@ -96,8 +121,8 @@ export class RoomCamera extends Container { * @private */ private _updateBounds(): void { - this.pivot.x = this._room.visualization.getBounds().x; - this.pivot.y = this._room.visualization.getBounds().y; + this._roomContainer.pivot.x = this._room.visualization.objectContainer.getBounds().x + this._roomContainer.pivot.y = this._room.visualization.objectContainer.getBounds().y } /** @@ -106,26 +131,24 @@ export class RoomCamera extends Container { * @return {void} * @public */ - public centerCamera(object?: RoomObject): void { - if (object === null || object === undefined) - gsap.to(this, { - x: Math.floor(this._room.engine.application.view.width / 2 - this._room.visualization.width / 2), - y: Math.floor(this._room.engine.application.view.height / 2 - this._room.visualization.height / 2), - duration: 0.8, - ease: 'easeOut' - }); - // TODO: Reimplement this part with the new room object - /*else { - const globalPos: Point = object.getGlobalPosition(new Point(object.width / 2, object.height / 2)); - const diffX: number = globalPos.x - this._room.engine.application.view.width / 2; - const diffY: number = globalPos.y - this._room.engine.application.view.height / 2; + public centerCamera(object?: Nullable, duration = 1): void { + if (object == null) { + const xAxis = this._room.engine.application.view.width / 2 - this._room.visualization.objectContainer.width / 2 + const yAxis = this._room.engine.application.view.height / 2 - this._room.visualization.objectContainer.height / 2 + + gsap.to(this._roomContainer, { x: Math.floor(xAxis), y: Math.floor(yAxis), duration, ease: Expo.easeOut }) + } else { + const globalPos = object.getGlobalPosition(new Point(object.width / 2, object.height / 2)) + const diffX = globalPos.x - this._roomContainer.width / 2 + const diffY = globalPos.y - this._roomContainer.height / 2 + gsap.to(this._roomContainer, { x: Math.floor(this._roomContainer.x - diffX), y: Math.floor(this._roomContainer.y - diffY), - duration: 0.8, - ease: 'easeOut' - }); - }*/ + duration, + ease: Expo.easeOut + }) + } } /** @@ -135,9 +158,8 @@ export class RoomCamera extends Container { * @private */ private readonly _dragStart = (): void => { - // console.log(event.movementX); - this._dragging = true; - }; + this._dragging = true + } /** * This method is called when the user stop dragging the room. @@ -146,9 +168,9 @@ export class RoomCamera extends Container { * @private */ private readonly _dragEnd = (): void => { - this._dragging = false; - if (this._isOutOfBounds()) this.centerCamera(); - }; + this._dragging = false + if (this._isOutOfBounds()) this.centerCamera() + } /** * This method is called when the user is moving the dragged room in the canvas. @@ -158,10 +180,10 @@ export class RoomCamera extends Container { * @private */ private readonly _dragMove = (event: PointerEvent): void => { - if (!this._dragging) return; - this.x = Math.floor(this.x + event.movementX * (1 / this._zoomLevel)); - this.y = Math.floor(this.y + event.movementY * (1 / this._zoomLevel)); - }; + if (!this._dragging) return + this._roomContainer.x = Math.floor(this._roomContainer.x + event.movementX * (1 / this._zoomLevel)) + this._roomContainer.y = Math.floor(this._roomContainer.y + event.movementY * (1 / this._zoomLevel)) + } /** * Indicate if the room container is out of bounds of the PixiJS view. @@ -171,15 +193,15 @@ export class RoomCamera extends Container { */ private _isOutOfBounds(): boolean { /** Out of bounds on the right */ - if (this.x > this._room.engine.application.view.width) return true; + if (this._roomContainer.x > this._room.engine.application.view.width) return true /** Out of bounds on the left */ - if (this.x + this.width < 0) return true; + if (this._roomContainer.x + this._roomContainer.width < 0) return true /** Out of bounds on the bottom */ - if (this.y > this._room.engine.application.view.height) return true; + if (this._roomContainer.y > this._room.engine.application.view.height) return true /** Out of bounds on the top */ - if (this.y + this.height < 0) return true; + if (this._roomContainer.y + this._roomContainer.height < 0) return true /** It is not out of bounds */ - return false; + return false } /** @@ -189,10 +211,10 @@ export class RoomCamera extends Container { * @private */ private readonly _tilePointerDown = (event: PointerEvent): void => { - const tile = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }); + const tile = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }) - if (tile != null) tile.emit('pointerdown', new FederatedPointerEvent(new EventBoundary())); - }; + if (tile != null) tile.emit('pointerdown', new FederatedPointerEvent(new EventBoundary())) + } /** * Manage pointer up event on the canvas for tile interaction. @@ -201,10 +223,10 @@ export class RoomCamera extends Container { * @private */ private readonly _tilePointerUp = (event: PointerEvent): void => { - const tile = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }); + const tile = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }) - if (tile != null) tile.emit('pointerup', new FederatedPointerEvent(new EventBoundary())); - }; + if (tile != null) tile.emit('pointerup', new FederatedPointerEvent(new EventBoundary())) + } /** * Manage pointer move event on the canvas for tile interaction. @@ -213,18 +235,18 @@ export class RoomCamera extends Container { * @private */ private readonly _tilePointerMove = (event: PointerEvent): void => { - const objectPart = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }); + const objectPart = this._room.parts.getFromGlobal({ x: event.clientX, y: event.clientY }) - if (objectPart == null) return; + if (objectPart == null) return if (this._selectedTile === objectPart) { - objectPart.emit('pointermove', new FederatedPointerEvent(new EventBoundary())); + objectPart.emit('pointermove', new FederatedPointerEvent(new EventBoundary())) } else { if (this._selectedTile != null) - this._selectedTile.emit('pointerout', new FederatedPointerEvent(new EventBoundary())); - if (objectPart != null) objectPart.emit('pointerover', new FederatedPointerEvent(new EventBoundary())); - this._selectedTile = objectPart; + this._selectedTile.emit('pointerout', new FederatedPointerEvent(new EventBoundary())) + if (objectPart != null) objectPart.emit('pointerover', new FederatedPointerEvent(new EventBoundary())) + this._selectedTile = objectPart } - }; + } /** * Zoom the room container. @@ -233,27 +255,27 @@ export class RoomCamera extends Container { * @public */ public set zoomLevel(zoomLevel: number) { - const origWidth = this.width / this._zoomLevel; - const origHeight = this.height / this._zoomLevel; + const origWidth = this.width / this._zoomLevel + const origHeight = this.height / this._zoomLevel - this._zoomLevel = zoomLevel; + this._zoomLevel = zoomLevel // pivot's container property must be changed // because by default things are centered and scaled from the top corner // this.pivot.x = ... / this.pivot.y = ... - gsap.set(this.scale, { x: zoomLevel, y: zoomLevel, ease: Expo.easeOut }); + gsap.set(this.scale, { x: zoomLevel, y: zoomLevel, ease: Expo.easeOut }) - const diffWidth = origWidth - this.width; - const diffHeight = origHeight - this.height; - const offsetX = this._room.engine.application.view.width / 2 - (this.x + origWidth / 2); - const offsetY = this._room.engine.application.view.height / 2 - (this.y + origHeight / 2); + const diffWidth = origWidth - this.width + const diffHeight = origHeight - this.height + const offsetX = this._room.engine.application.view.width / 2 - (this.x + origWidth / 2) + const offsetY = this._room.engine.application.view.height / 2 - (this.y + origHeight / 2) gsap.to(this, { x: this.x + Math.floor(diffWidth / 2 + offsetX), y: this.y + Math.floor(diffHeight / 2 + offsetY), duration: 0.8, ease: 'easeOut' - }); + }) } /** @@ -264,6 +286,6 @@ export class RoomCamera extends Container { * @public */ public get zoomLevel(): number { - return this._zoomLevel; + return this._zoomLevel } } diff --git a/src/objects/rooms/RoomVisualization.ts b/src/objects/rooms/RoomVisualization.ts index 108112b..3d518fa 100644 --- a/src/objects/rooms/RoomVisualization.ts +++ b/src/objects/rooms/RoomVisualization.ts @@ -75,6 +75,8 @@ export class RoomVisualization extends Container { */ private readonly _animationTicker = new Ticker() + private readonly _objectContainer!: Container + /** * @param {Room} [room] - The room instance that we want to visualize. */ @@ -85,6 +87,11 @@ export class RoomVisualization extends Container { this._objectLayer = new RoomObjectLayer(this._room) this._partLayer = new RoomPartLayer(this._room) + this._objectContainer = new Container() + + /** Add layers to the visualization */ + this.addChild(this._objectContainer) + /** Start the animation ticker */ this._animationTicker.maxFPS = 4 this._animationTicker.start() @@ -222,7 +229,7 @@ export class RoomVisualization extends Container { this._createCursor(part._position) } - this.addChild(part) + this._objectContainer.addChild(part) } /** @@ -242,7 +249,7 @@ export class RoomVisualization extends Container { const cursor = new Cursor(this._room, { position }) - this.addChild(cursor) + this._objectContainer.addChild(cursor) this._cursor = cursor } @@ -275,7 +282,7 @@ export class RoomVisualization extends Container { // todo!(): register event interactions for walls */ - this.addChild(wall) + this._objectContainer.addChild(wall) this._walls.push(wall) } @@ -312,6 +319,17 @@ export class RoomVisualization extends Container { return this._partLayer } + /** + * Reference to the object container. + * + * @member {RoomObjectContainer} + * @readonly + * @public + */ + public get objectContainer(): Container { + return this._objectContainer + } + /** * Reference to the room animation ticker instance. *