Fix: Move Floorplan out of Pixi and make it full selectable

This commit is contained in:
duckietm 2024-03-18 14:22:08 +01:00
parent 8c244f1132
commit 304e945c13
17 changed files with 401 additions and 179 deletions

21
src/common/Slider.tsx Normal file
View File

@ -0,0 +1,21 @@
import { FC } from 'react';
import ReactSlider, { ReactSliderProps } from 'react-slider';
import { Button } from './Button';
import { Flex } from './Flex';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
export interface SliderProps extends ReactSliderProps
{
disabledButton?: boolean;
}
export const Slider: FC<SliderProps> = props =>
{
const { disabledButton, max, min, value, onChange, ...rest } = props;
return <Flex fullWidth gap={ 1 }>
{ !disabledButton && <Button disabled={ min >= value } onClick={ () => onChange(min < value ? value - 1 : min, 0) }><FaAngleLeft /></Button> }
<ReactSlider className={ 'nitro-slider' } max={ max } min={ min } value={ value } onChange={ onChange } { ...rest } />
{ !disabledButton && <Button disabled={ max <= value } onClick={ () => onChange(max > value ? value + 1 : max, 0) }><FaAngleRight /></Button> }
</Flex>;
}

View File

@ -16,6 +16,7 @@ export * from './HorizontalRule';
export * from './InfiniteScroll'; export * from './InfiniteScroll';
export * from './layout'; export * from './layout';
export * from './layout/limited-edition'; export * from './layout/limited-edition';
export * from "./Slider";
export * from './Text'; export * from './Text';
export * from './transitions'; export * from './transitions';
export * from './types'; export * from './types';

View File

@ -4,6 +4,6 @@
} }
.floorplan-import-export { .floorplan-import-export {
width: 500px; width: 630px;
height: 475px; height: 475px;
} }

View File

@ -3,11 +3,11 @@ import { FC, useEffect, useState } from 'react';
import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api'; import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { Button, ButtonGroup, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { Button, ButtonGroup, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { useMessageEvent, useRoomEngineEvent } from '../../hooks'; import { useMessageEvent, useRoomEngineEvent } from '../../hooks';
import { FloorplanEditorContextProvider } from './FloorplanEditorContext';
import { FloorplanEditor } from './common/FloorplanEditor'; import { FloorplanEditor } from './common/FloorplanEditor';
import { IFloorplanSettings } from './common/IFloorplanSettings'; import { IFloorplanSettings } from './common/IFloorplanSettings';
import { IVisualizationSettings } from './common/IVisualizationSettings'; import { IVisualizationSettings } from './common/IVisualizationSettings';
import { convertNumbersForSaving, convertSettingToNumber } from './common/Utils'; import { convertNumbersForSaving, convertSettingToNumber } from './common/Utils';
import { FloorplanEditorContextProvider } from './FloorplanEditorContext';
import { FloorplanCanvasView } from './views/FloorplanCanvasView'; import { FloorplanCanvasView } from './views/FloorplanCanvasView';
import { FloorplanImportExportView } from './views/FloorplanImportExportView'; import { FloorplanImportExportView } from './views/FloorplanImportExportView';
import { FloorplanOptionsView } from './views/FloorplanOptionsView'; import { FloorplanOptionsView } from './views/FloorplanOptionsView';
@ -135,11 +135,6 @@ export const FloorplanEditorView: FC<{}> = props =>
return () => RemoveLinkEventTracker(linkTracker); return () => RemoveLinkEventTracker(linkTracker);
}, []); }, []);
useEffect(() =>
{
FloorplanEditor.instance.initialize();
}, []);
return ( return (
<FloorplanEditorContextProvider value={ { originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings } }> <FloorplanEditorContextProvider value={ { originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings } }>
{ isVisible && { isVisible &&
@ -162,4 +157,4 @@ export const FloorplanEditorView: FC<{}> = props =>
<FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false) } /> } <FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false) } /> }
</FloorplanEditorContextProvider> </FloorplanEditorContextProvider>
); );
} }

View File

@ -1,5 +1,5 @@
export const TILE_SIZE = 32; export const TILE_SIZE = 32;
export const MAX_NUM_TILE_PER_AXIS = 64; export const MAX_NUM_TILE_PER_AXIS = 100;
export const HEIGHT_SCHEME: string = 'x0123456789abcdefghijklmnopq'; export const HEIGHT_SCHEME: string = 'x0123456789abcdefghijklmnopq';

View File

@ -1,10 +1,11 @@
import { GetAssetManager, IGraphicAssetCollection, NitroPoint, NitroTilemap, PixiApplicationProxy, PixiInteractionEventProxy, POINT_STRUCT_SIZE } from '@nitrots/nitro-renderer'; import { NitroPoint } from '@nitrots/nitro-renderer';
import { ActionSettings } from './ActionSettings'; import { ActionSettings } from './ActionSettings';
import { FloorAction, HEIGHT_SCHEME, MAX_NUM_TILE_PER_AXIS, TILE_SIZE } from './Constants'; import { FloorAction, HEIGHT_SCHEME, MAX_NUM_TILE_PER_AXIS, TILE_SIZE } from './Constants';
import { imageBase64, spritesheet } from './FloorplanResource';
import { Tile } from './Tile'; import { Tile } from './Tile';
import { getScreenPositionForTile, getTileFromScreenPosition } from './Utils'; import { getScreenPositionForTile } from './Utils';
export class FloorplanEditor extends PixiApplicationProxy export class FloorplanEditor
{ {
private static _INSTANCE: FloorplanEditor = null; private static _INSTANCE: FloorplanEditor = null;
@ -14,160 +15,107 @@ export class FloorplanEditor extends PixiApplicationProxy
private _tilemap: Tile[][]; private _tilemap: Tile[][];
private _width: number; private _width: number;
private _height: number; private _height: number;
private _isHolding: boolean; private _isPointerDown: boolean;
private _doorLocation: NitroPoint; private _doorLocation: NitroPoint;
private _lastUsedTile: NitroPoint; private _lastUsedTile: NitroPoint;
private _tilemapRenderer: NitroTilemap; private _renderer: CanvasRenderingContext2D;
private _actionSettings: ActionSettings; private _actionSettings: ActionSettings;
private _isInitialized: boolean;
private _assetCollection: IGraphicAssetCollection; private _image: HTMLImageElement;
constructor() constructor()
{ {
const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20; const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
const height = (TILE_SIZE * MAX_NUM_TILE_PER_AXIS) / 2 + 100; const height = (TILE_SIZE * MAX_NUM_TILE_PER_AXIS) / 2 + 100;
super({ const canvas = document.createElement('canvas');
width: width,
height: height, canvas.height = height;
backgroundColor: 0x000000, canvas.width = width;
antialias: true,
autoDensity: true, canvas.style.touchAction = 'none';
resolution: 1,
sharedLoader: true, this._renderer = canvas.getContext('2d');
sharedTicker: true
}); this._image = new Image();
this._image.src = imageBase64;
this._tilemap = []; this._tilemap = [];
this._doorLocation = new NitroPoint(0, 0); this._doorLocation = new NitroPoint(0, 0);
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
this._isHolding = false; this._isPointerDown = false;
this._lastUsedTile = new NitroPoint(-1, -1); this._lastUsedTile = new NitroPoint(-1, -1);
this._actionSettings = new ActionSettings(); this._actionSettings = new ActionSettings();
} }
public initialize(): void public onPointerRelease(): void
{ {
if(this._isInitialized) return; this._isPointerDown = false;
}
const collection = GetAssetManager().getCollection('floor_editor'); public onPointerDown(event: PointerEvent): void
{
if(event.button === 2) return;
if(!collection) return; const location = new NitroPoint(event.offsetX, event.offsetY);
this._assetCollection = collection; this._isPointerDown = true;
this._tilemapRenderer = new NitroTilemap(collection.baseTexture);
this.registerEventListeners();
this.stage.addChild(this._tilemapRenderer);
this._isInitialized = true; this.tileHitDetection(location, true);
} }
private registerEventListeners(): void public onPointerMove(event: PointerEvent): void
{ {
//this._tilemapRenderer.interactive = true; if(!this._isPointerDown) return;
const tempPoint = new NitroPoint(); const location = new NitroPoint(event.offsetX, event.offsetY);
// @ts-ignore this.tileHitDetection(location, false);
this._tilemapRenderer.containsPoint = (position) =>
{
this._tilemapRenderer.worldTransform.applyInverse(position, tempPoint);
return this.tileHitDetection(tempPoint, false);
};
this._tilemapRenderer.on('pointerup', () =>
{
this._isHolding = false;
});
this._tilemapRenderer.on('pointerout', () =>
{
this._isHolding = false;
});
this._tilemapRenderer.on('pointerdown', (event: PixiInteractionEventProxy) =>
{
if(!(event.data.originalEvent instanceof PointerEvent) && !(event.data.originalEvent instanceof TouchEvent)) return;
const pointerEvent = event.data.originalEvent;
if((pointerEvent instanceof MouseEvent) && pointerEvent.button === 2) return;
const location = event.data.global;
this.tileHitDetection(location, true);
});
this._tilemapRenderer.on('click', (event: PixiInteractionEventProxy) =>
{
if(!(event.data.originalEvent instanceof PointerEvent)) return;
const pointerEvent = event.data.originalEvent;
if(pointerEvent.button === 2) return;
const location = event.data.global;
this.tileHitDetection(location, true, true);
});
} }
private tileHitDetection(tempPoint: NitroPoint, setHolding: boolean, isClick: boolean = false): boolean private tileHitDetection(tempPoint: NitroPoint, isClick: boolean = false): boolean
{ {
// @ts-ignore const mousePositionX = Math.floor(tempPoint.x);
const buffer = this._tilemapRenderer.pointsBuf; const mousePositionY = Math.floor(tempPoint.y);
const bufSize = POINT_STRUCT_SIZE;
const len = buffer.length; const width = TILE_SIZE;
const height = TILE_SIZE / 2;
if(setHolding) for(let y = 0; y < this._tilemap.length; y++)
{ {
this._isHolding = true; for(let x = 0; x < this.tilemap[y].length; x++)
}
for(let j = 0; j < len; j += bufSize)
{
const bufIndex = j + bufSize;
const data = buffer.slice(j, bufIndex);
const width = TILE_SIZE;
const height = TILE_SIZE / 2;
const mousePositionX = Math.floor(tempPoint.x);
const mousePositionY = Math.floor(tempPoint.y);
const tileStartX = data[2];
const tileStartY = data[3];
const centreX = tileStartX + (width / 2);
const centreY = tileStartY + (height / 2);
const dx = Math.abs(mousePositionX - centreX);
const dy = Math.abs(mousePositionY - centreY);
const solution = (dx / (width * 0.5) + dy / (height * 0.5) <= 1);//todo: improve this
if(solution)
{ {
if(this._isHolding) const [ tileStartX, tileStartY ] = getScreenPositionForTile(x, y);
const centreX = tileStartX + (width / 2);
const centreY = tileStartY + (height / 2);
const dx = Math.abs(mousePositionX - centreX);
const dy = Math.abs(mousePositionY - centreY);
const solution = (dx / (width * 0.5) + dy / (height * 0.5) <= 1);//todo: improve this
if(solution)
{ {
const [ realX, realY ] = getTileFromScreenPosition(tileStartX, tileStartY); if(this._isPointerDown)
if(isClick)
{ {
this.onClick(realX, realY); if(isClick)
} {
this.onClick(x, y);
}
else if(this._lastUsedTile.x !== realX || this._lastUsedTile.y !== realY) else if(this._lastUsedTile.x !== x || this._lastUsedTile.y !== y)
{ {
this._lastUsedTile.x = realX; this._lastUsedTile.x = x;
this._lastUsedTile.y = realY; this._lastUsedTile.y = y;
this.onClick(realX, realY); this.onClick(x, y);
} }
}
return true;
} }
return true;
} }
} }
return false; return false;
} }
@ -221,7 +169,7 @@ export class FloorplanEditor extends PixiApplicationProxy
if(!newHeight) return; if(!newHeight) return;
if(tile.isBlocked) return; // if(tile.isBlocked) return;
this._tilemap[y][x].height = newHeight; this._tilemap[y][x].height = newHeight;
@ -230,7 +178,7 @@ export class FloorplanEditor extends PixiApplicationProxy
public renderTiles(): void public renderTiles(): void
{ {
this.tilemapRenderer.clear(); this.clearCanvas();
for(let y = 0; y < this._tilemap.length; y++) for(let y = 0; y < this._tilemap.length; y++)
{ {
@ -244,10 +192,13 @@ export class FloorplanEditor extends PixiApplicationProxy
if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED; if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
//if((tile.height === 'x') || tile.height === 'X') continue; if ((tile.height === 'x' || tile.height === 'X') && tile.isBlocked) assetName = 'x';
const [ positionX, positionY ] = getScreenPositionForTile(x, y);
this._tilemapRenderer.tile(this._assetCollection.getTexture(`floor_editor_${ assetName }`), positionX, positionY); const [ positionX, positionY ] = getScreenPositionForTile(x, y);
const asset = spritesheet.frames[assetName];
this.renderer.drawImage(this._image, asset.frame.x, asset.frame.y, asset.frame.w, asset.frame.h, positionX, positionY, asset.frame.w, asset.frame.h);
} }
} }
} }
@ -372,20 +323,25 @@ export class FloorplanEditor extends PixiApplicationProxy
public clear(): void public clear(): void
{ {
this._tilemapRenderer.interactive = false;
this._tilemap = []; this._tilemap = [];
this._doorLocation.set(-1, -1); this._doorLocation.set(-1, -1);
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
this._isHolding = false; this._isPointerDown = false;
this._lastUsedTile.set(-1, -1); this._lastUsedTile.set(-1, -1);
this._actionSettings.clear(); this._actionSettings.clear();
this._tilemapRenderer.clear(); this.clearCanvas();
} }
public get tilemapRenderer(): NitroTilemap public clearCanvas(): void
{ {
return this._tilemapRenderer; this.renderer.fillStyle = '0x000000';
this.renderer.fillRect(0, 0, this._renderer.canvas.width, this._renderer.canvas.height);
}
public get renderer(): CanvasRenderingContext2D
{
return this._renderer;
} }
public get tilemap(): Tile[][] public get tilemap(): Tile[][]
@ -417,4 +373,4 @@ export class FloorplanEditor extends PixiApplicationProxy
return FloorplanEditor._INSTANCE; return FloorplanEditor._INSTANCE;
} }
} }

View File

@ -0,0 +1,227 @@
export const imageBase64 =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAAC+CAMAAADnThrbAAAAYFBMVEUAAAAiIiIAZf8A6P8A/5MZ/wCb/wD/tQD/MgD/AHr/APxDXocAkf8A/+oA/2hE/wDy/wD/iQD/BwD/AKXWAP////8AvP8A/78A/z1w/wD/4AD/XgD/ACP/ANGqAP8QEBBSz3qJAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEwAACxMBAJqcGAAABJxJREFUeNrt1tuOszoMBeDpD7QFBloKDGf6/m+51UTj1PUhN1uWOup3vSQLkSzn6+vV4fAV9X9lLIcdDv/+xWKHw/d3PPPzE8k8Rj1osceoBz3z4yiZ31HauN9R2rjfUcq451HSuOdR0rjnUcK411HcuNdR3LjXUcw4btTrOG7U6zhu1Ms4adTzOGnU8zhpVBh30Eb5cQ/fKp/5UR1+51l9mfU/Mz6NxvfMuEGMu9G49f/y8vzLz4Ikif/8qopnhiF6FhNHP9aVo2cGR71lCZAvbAXkzADE/kgQvooqhM8MCNuMCUFLtiJoZiBI5ycsvD4qFs4MLLTNElFYjJUoZAYRPAsSlV/5lcpnBhU8C6y+zPqfGZ9G43tm3CDG3Wjc+p9N/Z7PgjSN//y6jmfGMXoWU0c/1rWjZ0ZHvWUpkC9sDeTMCMT+SBG+imqEz4wI24wpQUu2JmhmJEjnpyy8PmoWzowstM1SUViMtShkRhE8C1KVX/m1ymdGFTwLrL7M+p8Zn0bje2bcIMbdaNz6n039ns+CLIv//Mslnpmm6FnMHP1YXxw9MznqLcuAfGEvQM5MQOyPDOGr6ILwmQlhmzEjaMleCJqZCNL5GQuvjwsLZyYW2maZKCzGiyhkJhE8CzKVX/kXlc9MKngWWH2Z9T8zPo3G98y4QYy70bj1P5v6PZ8Fx2P851+v8cw8R8/i0dGP9dXRM7Oj3rIjkC/sFciZGYj9cUT4KroifGZG2GY8ErRkrwTNzATp/CMLr48rC2dmFtpmR1FYjFdRyMwieBYcVX7lX1U+M6vgWWD1Zdb/zPg0Gt8z4wYx7kbj1v9s6vd8FpxO8Z/fNPHMskTP4snRj3Xj6JnFUW/ZCcgXtgFyZgFif5wQvooahM8sCNuMJ4KWbEPQzEKQzj+x8PpoWDizsNA2O4nCYmxEIbOI4FlwUvmV36h8ZlHBs8Dqy6z/mfFpNL5nxg1i3I3Grf/Z1O/5LDif4z//dotn1jV6Fs+Ofqxvjp5ZHfWWnYF8YW9AzqxA7I8zwlfRDeEzK8I245mgJXsjaGYlSOefWXh93Fg4s7LQNjuLwmK8iUJmFcGz4KzyK/+m8plVBc8Cqy+z/mfGp9H4nhk3iHE3Grf+Z1O/57Mgz+M/v23jmW2LnsXc0Y916+iZzVFvWQ7kC9sCObMBsT9yhK+iFuEzG8I2Y07Qkm0JmtkI0vk5C6+PloUzGwtts1wUFmMrCplNBM+CXOVXfqvymU0FzwKrL7P+Z8an0fieGTeIcTcat/5nU7/ns6Ao4j+/6+KZfY+excLRj3Xn6JndUW9ZAeQL2wE5swOxPwqEr6IO4TM7wjZjQdCS7Qia2QnS+QULr4+OhTM7C22zQhQWYycKmV0Ez4JC5Vd+p/KZXQXPAqsvs/5nxqfR+J4ZN4hxNxq3/mdTv+ezoCzjP7/v45n7PXoWS0c/1r2jZ+6OestKIF/YHsiZOxD7o0T4KuoRPnNH2GYsCVqyPUEzd4J0fsnC66Nn4cydhbZZKQqLsReFzF0Ez4JS5Vd+r/KZuwqeBVZfZv3PjE+j8T0zbhDjbjRu/b+0PP8DZwi9QurvbfwAAAAASUVORK5CYII=';
export const spritesheet = {
frames: {
'0': {
frame: { x: 1, y: 1, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'1': {
frame: { x: 37, y: 1, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'2': {
frame: { x: 73, y: 1, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'3': {
frame: { x: 1, y: 20, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'4': {
frame: { x: 37, y: 20, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'5': {
frame: { x: 73, y: 20, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'6': {
frame: { x: 1, y: 39, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'7': {
frame: { x: 37, y: 39, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'8': {
frame: { x: 73, y: 39, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'9': {
frame: { x: 1, y: 58, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'a': {
frame: { x: 37, y: 58, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'b': {
frame: { x: 73, y: 58, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'c': {
frame: { x: 1, y: 77, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'd': {
frame: { x: 37, y: 77, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'e': {
frame: { x: 73, y: 77, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'f': {
frame: { x: 1, y: 96, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'g': {
frame: { x: 37, y: 96, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'h': {
frame: { x: 73, y: 96, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'i': {
frame: { x: 1, y: 115, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'j': {
frame: { x: 37, y: 115, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'k': {
frame: { x: 73, y: 115, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'l': {
frame: { x: 1, y: 134, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'm': {
frame: { x: 37, y: 134, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'n': {
frame: { x: 73, y: 134, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'o': {
frame: { x: 1, y: 153, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'p': {
frame: { x: 37, y: 153, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'q': {
frame: { x: 73, y: 153, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'r_blocked': {
frame: { x: 1, y: 172, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'r_door': {
frame: { x: 37, y: 172, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
'x': {
frame: { x: 73, y: 172, w: 34, h: 17 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
},
meta: {
app: 'https://www.codeandweb.com/texturepacker',
version: '1.0',
image: 'tiles.png',
format: 'RGBA8888',
size: { w: 108, h: 190 },
scale: '1',
smartupdate:
'$TexturePacker:SmartUpdate:6d0f8373580629749f786a0b0f6c6bb9:96dff9df69bdc6938cf02f254bbe028b:accbe1e7e294ded8391337fc1c446319$',
},
};

View File

@ -5,14 +5,14 @@ export const getScreenPositionForTile = (x: number, y: number): [number , number
let positionX = (x * TILE_SIZE / 2) - (y * TILE_SIZE / 2); let positionX = (x * TILE_SIZE / 2) - (y * TILE_SIZE / 2);
const positionY = (x * TILE_SIZE / 4) + (y * TILE_SIZE / 4); const positionY = (x * TILE_SIZE / 4) + (y * TILE_SIZE / 4);
positionX = positionX + 1024; // center the map in the canvas positionX = positionX + 1600; // center the map in the canvas
return [ positionX, positionY ]; return [ positionX, positionY ];
} }
export const getTileFromScreenPosition = (x: number, y: number): [number, number] => export const getTileFromScreenPosition = (x: number, y: number): [number, number] =>
{ {
const translatedX = x - 1024; // after centering translation const translatedX = x - 1600; // after centering translation
const realX = ((translatedX /(TILE_SIZE / 2)) + (y / (TILE_SIZE / 4))) / 2; const realX = ((translatedX /(TILE_SIZE / 2)) + (y / (TILE_SIZE / 4))) / 2;
const realY = ((y /(TILE_SIZE / 4)) - (translatedX / (TILE_SIZE / 2))) / 2; const realY = ((y /(TILE_SIZE / 4)) - (translatedX / (TILE_SIZE / 2))) / 2;

View File

@ -4,8 +4,8 @@ import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp } from 'react-icons/f
import { SendMessageComposer } from '../../../api'; import { SendMessageComposer } from '../../../api';
import { Base, Button, Column, ColumnProps, Flex, Grid } from '../../../common'; import { Base, Button, Column, ColumnProps, Flex, Grid } from '../../../common';
import { useMessageEvent } from '../../../hooks'; import { useMessageEvent } from '../../../hooks';
import { FloorplanEditor } from '../common/FloorplanEditor';
import { useFloorplanEditorContext } from '../FloorplanEditorContext'; import { useFloorplanEditorContext } from '../FloorplanEditorContext';
import { FloorplanEditor } from '../common/FloorplanEditor';
export const FloorplanCanvasView: FC<ColumnProps> = props => export const FloorplanCanvasView: FC<ColumnProps> = props =>
{ {
@ -32,7 +32,7 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
setOccupiedTilesReceived(true); setOccupiedTilesReceived(true);
elementRef.current.scrollTo((FloorplanEditor.instance.view.width / 3), 0); elementRef.current.scrollTo((FloorplanEditor.instance.renderer.canvas.width / 3), 0);
}); });
useMessageEvent<RoomEntryTileMessageEvent>(RoomEntryTileMessageEvent, event => useMessageEvent<RoomEntryTileMessageEvent>(RoomEntryTileMessageEvent, event =>
@ -86,6 +86,25 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
} }
} }
const onPointerEvent = (event: PointerEvent) =>
{
event.preventDefault();
switch(event.type)
{
case 'pointerout':
case 'pointerup':
FloorplanEditor.instance.onPointerRelease();
break;
case 'pointerdown':
FloorplanEditor.instance.onPointerDown(event);
break;
case 'pointermove':
FloorplanEditor.instance.onPointerMove(event);
break;
}
}
useEffect(() => useEffect(() =>
{ {
return () => return () =>
@ -116,22 +135,46 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
SendMessageComposer(new GetRoomEntryTileMessageComposer()); SendMessageComposer(new GetRoomEntryTileMessageComposer());
SendMessageComposer(new GetOccupiedTilesMessageComposer()); SendMessageComposer(new GetOccupiedTilesMessageComposer());
FloorplanEditor.instance.tilemapRenderer.interactive = true; const currentElement = elementRef.current;
if(!elementRef.current) return; if(!currentElement) return;
currentElement.appendChild(FloorplanEditor.instance.renderer.canvas);
elementRef.current.appendChild(FloorplanEditor.instance.renderer.view); currentElement.addEventListener('pointerup', onPointerEvent);
currentElement.addEventListener('pointerout', onPointerEvent);
currentElement.addEventListener('pointerdown', onPointerEvent);
currentElement.addEventListener('pointermove', onPointerEvent);
return () =>
{
if(currentElement)
{
currentElement.removeEventListener('pointerup', onPointerEvent);
currentElement.removeEventListener('pointerout', onPointerEvent);
currentElement.removeEventListener('pointerdown', onPointerEvent);
currentElement.removeEventListener('pointermove', onPointerEvent);
}
}
}, []); }, []);
const isSmallScreen = () => window.innerWidth < 768;
return ( return (
<Column gap={ gap } { ...rest }> <Column gap={ gap } { ...rest }>
<Grid overflow="hidden" gap={ 1 }> <Grid overflow="hidden" gap={ 1 }>
<Column center size={ 1 }> <Column center size={ 1 } className="d-md-none">
<Button className="d-md-none" onClick={ event => onClickArrowButton('left') }> <Button className="d-md-none" onClick={ event => onClickArrowButton('left') }>
<FaArrowLeft className="fa-icon" /> <FaArrowLeft className="fa-icon" />
</Button> </Button>
</Column> </Column>
<Column overflow="hidden" size={ 10 } gap={ 1 }> <Column overflow="hidden" size={ isSmallScreen() ? 10: 12 } gap={ 1 }>
<Flex justifyContent="center" className="d-md-none"> <Flex justifyContent="center" className="d-md-none">
<Button shrink onClick={ event => onClickArrowButton('up') }> <Button shrink onClick={ event => onClickArrowButton('up') }>
<FaArrowUp className="fa-icon" /> <FaArrowUp className="fa-icon" />
@ -144,7 +187,7 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
</Button> </Button>
</Flex> </Flex>
</Column> </Column>
<Column center size={ 1 }> <Column center size={ 1 } className="d-md-none">
<Button className="d-md-none" onClick={ event => onClickArrowButton('right') }> <Button className="d-md-none" onClick={ event => onClickArrowButton('right') }>
<FaArrowRight className="fa-icon" /> <FaArrowRight className="fa-icon" />
</Button> </Button>
@ -153,4 +196,4 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
{ children } { children }
</Column> </Column>
); );
} }

View File

@ -52,4 +52,4 @@ export const FloorplanImportExportView: FC<FloorplanImportExportViewProps> = pro
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );
} }

View File

@ -1,8 +1,7 @@
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { FaCaretLeft, FaCaretRight } from 'react-icons/fa'; import { FaCaretLeft, FaCaretRight } from 'react-icons/fa';
import ReactSlider from 'react-slider';
import { LocalizeText } from '../../../api'; import { LocalizeText } from '../../../api';
import { Column, Flex, LayoutGridItem, Text } from '../../../common'; import { Column, Flex, LayoutGridItem, Slider, Text } from '../../../common';
import { COLORMAP, FloorAction } from '../common/Constants'; import { COLORMAP, FloorAction } from '../common/Constants';
import { FloorplanEditor } from '../common/FloorplanEditor'; import { FloorplanEditor } from '../common/FloorplanEditor';
import { useFloorplanEditorContext } from '../FloorplanEditorContext'; import { useFloorplanEditorContext } from '../FloorplanEditorContext';
@ -157,8 +156,7 @@ export const FloorplanOptionsView: FC<{}> = props =>
<Flex gap={ 1 }> <Flex gap={ 1 }>
<Column size={ 6 }> <Column size={ 6 }>
<Text bold>{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</Text> <Text bold>{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</Text>
<ReactSlider <Slider
className="nitro-slider"
min={ MIN_FLOOR_HEIGHT } min={ MIN_FLOOR_HEIGHT }
max={ MAX_FLOOR_HEIGHT } max={ MAX_FLOOR_HEIGHT }
step={ 1 } step={ 1 }
@ -186,4 +184,4 @@ export const FloorplanOptionsView: FC<{}> = props =>
</Flex> </Flex>
</Column> </Column>
); );
} }

View File

@ -1,6 +1,6 @@
import { BaseTexture, Resource, Texture } from '@pixi/core'; import { BaseTexture, Resource, Texture } from '@pixi/core';
import { Spritesheet } from '@pixi/spritesheet'; import { Spritesheet } from '@pixi/spritesheet';
import { Dict } from '@pixi/utils'; import { Dict } from '../utils';
import { GetTickerTime } from '../../pixi-proxy'; import { GetTickerTime } from '../../pixi-proxy';
import { GraphicAsset } from './GraphicAsset'; import { GraphicAsset } from './GraphicAsset';
import { GraphicAssetPalette } from './GraphicAssetPalette'; import { GraphicAssetPalette } from './GraphicAssetPalette';

View File

@ -87,6 +87,7 @@ export class SocketConnection extends EventDispatcher implements IConnection
this._dataBuffer = new ArrayBuffer(0); this._dataBuffer = new ArrayBuffer(0);
this._socket = new WebSocket(socketUrl); this._socket = new WebSocket(socketUrl);
this._socket.binaryType = 'arraybuffer';
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_OPENED, this.onOpen); this._socket.addEventListener(WebSocketEventEnum.CONNECTION_OPENED, this.onOpen);
this._socket.addEventListener(WebSocketEventEnum.CONNECTION_CLOSED, this.onClose); this._socket.addEventListener(WebSocketEventEnum.CONNECTION_CLOSED, this.onClose);
@ -104,6 +105,8 @@ export class SocketConnection extends EventDispatcher implements IConnection
this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this.onMessage); this._socket.removeEventListener(WebSocketEventEnum.CONNECTION_MESSAGE, this.onMessage);
if(this._socket.readyState === WebSocket.OPEN) this._socket.close(); if(this._socket.readyState === WebSocket.OPEN) this._socket.close();
NitroLogger.error('Bye Bye connection.');
this._socket = null; this._socket = null;
} }
@ -129,16 +132,9 @@ export class SocketConnection extends EventDispatcher implements IConnection
//this.dispatchConnectionEvent(SocketConnectionEvent.CONNECTION_MESSAGE, event); //this.dispatchConnectionEvent(SocketConnectionEvent.CONNECTION_MESSAGE, event);
const reader = new FileReader(); this._dataBuffer = this.concatArrayBuffers(this._dataBuffer, event.data);
reader.readAsArrayBuffer(event.data); this.processReceivedData();
reader.onloadend = () =>
{
this._dataBuffer = this.concatArrayBuffers(this._dataBuffer, (reader.result as ArrayBuffer));
this.processReceivedData();
};
} }
private dispatchConnectionEvent(type: string, event: Event): void private dispatchConnectionEvent(type: string, event: Event): void

View File

@ -2,7 +2,6 @@ import '@pixi/canvas-display';
import { BatchRenderer, extensions } from '@pixi/core'; import { BatchRenderer, extensions } from '@pixi/core';
import { Extract } from '@pixi/extract'; import { Extract } from '@pixi/extract';
import '@pixi/graphics-extras'; import '@pixi/graphics-extras';
import { InteractionManager } from '@pixi/interaction';
import { AppLoaderPlugin } from '@pixi/loaders'; import { AppLoaderPlugin } from '@pixi/loaders';
import '@pixi/math-extras'; import '@pixi/math-extras';
import '@pixi/mixin-cache-as-bitmap'; import '@pixi/mixin-cache-as-bitmap';
@ -17,7 +16,6 @@ extensions.add(
BatchRenderer, BatchRenderer,
Extract, Extract,
TilingSpriteRenderer, TilingSpriteRenderer,
InteractionManager,
SpritesheetLoader, SpritesheetLoader,
AppLoaderPlugin, AppLoaderPlugin,
TickerPlugin); TickerPlugin);

View File

@ -1,6 +0,0 @@
import { Tilemap } from '@pixi/tilemap';
export class NitroTilemap extends Tilemap
{
}

View File

@ -1,4 +0,0 @@
import { InteractionEvent } from '@pixi/interaction';
export class PixiInteractionEventProxy extends InteractionEvent
{}

View File

@ -1,4 +1,3 @@
export { POINT_STRUCT_SIZE } from '@pixi/tilemap';
export * from './adjustment-filter'; export * from './adjustment-filter';
export * from './CopyChannelFilter'; export * from './CopyChannelFilter';
export * from './GetTicker'; export * from './GetTicker';
@ -16,9 +15,7 @@ export * from './NitroRenderTexture';
export * from './NitroSprite'; export * from './NitroSprite';
export * from './NitroSpritesheet'; export * from './NitroSpritesheet';
export * from './NitroTexture'; export * from './NitroTexture';
export * from './NitroTilemap';
export * from './PaletteMapFilter'; export * from './PaletteMapFilter';
export * from './PixiApplicationProxy'; export * from './PixiApplicationProxy';
export * from './PixiInteractionEventProxy';
export * from './RoomTextureUtils'; export * from './RoomTextureUtils';
export * from './TextureUtils'; export * from './TextureUtils';