fix(objects/RoomCamera): not being centered correctly

This commit is contained in:
Walid 2023-07-31 10:56:12 +01:00
parent c217245058
commit bbb1376f95
Signed by: Walidoux
GPG Key ID: CCF21881FE8BEBAF
5 changed files with 232 additions and 145 deletions

24
TODO.md
View File

@ -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

32
public/rooms/stairs.txt Normal file
View File

@ -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'

View File

@ -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@}
}
}
} */

View File

@ -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<RoomObject>, 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
}
}

View File

@ -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.
*