refactor: room

This commit is contained in:
cha0s 2022-03-24 08:37:03 -05:00
parent 2d5459399c
commit 8ce4e5de8c
9 changed files with 141 additions and 27 deletions

View File

@ -1,6 +1,7 @@
import Renderer from '@avocado/graphics/renderer';
import {Vector} from '@avocado/math';
import {
classnames,
forwardRef,
memo,
PropTypes,
@ -13,7 +14,7 @@ import {
import K from 'kefir';
import Slider from 'rc-slider';
import './index.css';
import styles from './index.module.scss';
const marks = {
1: '1x',
@ -23,6 +24,7 @@ const marks = {
};
const Stage = forwardRef(({
className,
centered,
renderable,
renderer,
@ -114,9 +116,7 @@ const Stage = forwardRef(({
};
}, [renderable, renderer, ticker]);
return (
<div
className="stage"
>
<div className={classnames(styles.stage, className)}>
{scalable && (
<Slider
min={1}
@ -129,16 +129,14 @@ const Stage = forwardRef(({
value={scale}
/>
)}
<div
className="canvas-host"
ref={hostRef}
/>
<div className={styles.canvas} ref={hostRef} />
</div>
);
});
Stage.defaultProps = {
centered: true,
className: '',
renderer: new Renderer([0, 0]),
scalable: true,
};
@ -147,6 +145,7 @@ Stage.displayName = 'Stage';
Stage.propTypes = {
centered: PropTypes.bool,
className: PropTypes.string,
renderable: PropTypes.shape({
position: PropTypes.arrayOf(PropTypes.number),
scale: PropTypes.arrayOf(PropTypes.number),

View File

@ -9,7 +9,7 @@
min-width: 200px;
}
.stage > .canvas-host {
.stage > .canvas {
align-items: center;
/* border-top: 1px solid rgba(255, 255, 255, 0.1); */
display: flex;
@ -20,15 +20,3 @@
width: 100%;
line-height: 0;
}
.stage > .rc-slider {
margin: 0.5em 0 1.25em;
width: calc(100% - 2em);
}
.rc-slider-handle {
border: 1px solid rgba(0, 0, 0, 0.5);
}
.rc-slider-track {
background-color: #d60000;
}

View File

@ -36,6 +36,7 @@
"@avocado/math": "^3.0.0",
"@avocado/resource": "^3.0.0",
"@avocado/s13n": "^3.0.0",
"@avocado/timing": "^3.0.0",
"@avocado/traits": "^3.0.0",
"@flecks/core": "^1.4.1",
"@flecks/react": "^1.4.1",

View File

@ -0,0 +1,2 @@
export {default as RoomRenderable} from './renderable';
export {default as RoomUi} from './ui';

View File

@ -0,0 +1,117 @@
import {
classnames,
PropTypes,
React,
useCallback,
useEffect,
useFlecks,
useState,
} from '@flecks/react';
import {Container, Renderer, Stage} from '@avocado/graphics';
import {Vector} from '@avocado/math';
import {createLoop, destroyLoop} from '@avocado/timing';
import styles from './renderable.module.scss';
const renderer = new Renderer();
const RoomRenderable = ({camera, className, room}) => {
const flecks = useFlecks();
const [container] = useState(new Container());
const [roomRenderable, setRoomRenderable] = useState();
const [viewSize, setViewSize] = useState(flecks.get('@avocado/topdown.viewSize'));
useEffect(() => {
[container.x, container.y] = Vector.scale(viewSize, 0.5);
}, [container, viewSize]);
useEffect(() => {
if (!room) {
return undefined;
}
const roomRenderable = new (room.constructor.Renderable)(room, renderer);
setRoomRenderable(roomRenderable);
container.addChild(roomRenderable);
return () => {
container.removeChild(roomRenderable);
};
}, [container, room]);
useEffect(() => {
if (!roomRenderable || !camera) {
return undefined;
}
const halfViewport = Vector.scale(viewSize, 0.5);
// eslint-disable-next-line no-param-reassign
camera.realPosition = camera.position;
const onCameraRealOffsetChanged = () => {
roomRenderable.renderChunksForExtent(camera.rectangle);
container.pivot = Vector.sub(halfViewport, Vector.scale(camera.realOffset, -1));
};
const onCameraRotationChanged = () => {
container.rotation = camera.rotation;
};
const onCameraScaleChanged = () => {
[container.scaleX, container.scaleY] = [1, 1] || camera.scale;
};
const onCameraViewSizeChanged = () => {
setViewSize(camera.viewSize);
};
onCameraRealOffsetChanged();
onCameraRotationChanged();
onCameraScaleChanged();
onCameraViewSizeChanged();
camera.on('realOffsetChanged', onCameraRealOffsetChanged);
camera.on('rotationChanged', onCameraRotationChanged);
camera.on('scaleChanged', onCameraScaleChanged);
camera.on('viewSize', onCameraViewSizeChanged);
return () => {
camera.off('realOffsetChanged', onCameraRealOffsetChanged);
camera.off('rotationChanged', onCameraRotationChanged);
camera.off('scaleChanged', onCameraScaleChanged);
camera.off('viewSize', onCameraViewSizeChanged);
};
}, [container, roomRenderable, camera, viewSize]);
const ticker = useCallback(
(elapsed) => {
container.renderTick(elapsed);
},
[container],
);
useEffect(() => {
if (!room) {
return undefined;
}
const handle = createLoop((elapsed) => {
room.tick(elapsed);
});
return () => {
destroyLoop(handle);
};
}, [container, room]);
return (
<Stage
centered={false}
className={classnames(styles.stage, className)}
scalable={false}
renderer={renderer}
renderable={container}
size={viewSize}
ticker={ticker}
/>
);
};
RoomRenderable.defaultProps = {
camera: null,
className: '',
room: null,
};
RoomRenderable.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
camera: PropTypes.any,
className: PropTypes.string,
// eslint-disable-next-line react/forbid-prop-types
room: PropTypes.any,
};
export default RoomRenderable;

View File

@ -0,0 +1,7 @@
.stage {
display: inline-block;
line-height: 0;
canvas {
image-rendering: pixelated;
}
}

View File

@ -6,10 +6,10 @@ import {
useRef,
} from '@flecks/react';
import styles from './room.module.scss';
import styles from './ui.module.scss';
// This is the DOM side of a rendered room. Dialog text, damage numbers, (DOM node entities)...
function Room({
function RoomUi({
domScale,
position,
room,
@ -52,11 +52,11 @@ function Room({
);
}
Room.defaultProps = {
RoomUi.defaultProps = {
room: undefined,
};
Room.propTypes = {
RoomUi.propTypes = {
// @todo Real prop type
domScale: PropTypes.arrayOf(PropTypes.number).isRequired,
position: PropTypes.arrayOf(PropTypes.number).isRequired,
@ -67,4 +67,4 @@ Room.propTypes = {
}),
};
export default Room;
export default RoomUi;

View File

@ -1,6 +1,6 @@
import {Flecks, Hooks} from '@flecks/core';
export {default as Room} from './components/room';
export * from './components/room';
export {default as Camera} from './camera';