refactor: room
This commit is contained in:
parent
2d5459399c
commit
8ce4e5de8c
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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",
|
||||
|
|
2
packages/topdown/src/components/room/index.js
Normal file
2
packages/topdown/src/components/room/index.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export {default as RoomRenderable} from './renderable';
|
||||
export {default as RoomUi} from './ui';
|
117
packages/topdown/src/components/room/renderable.jsx
Normal file
117
packages/topdown/src/components/room/renderable.jsx
Normal 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;
|
|
@ -0,0 +1,7 @@
|
|||
.stage {
|
||||
display: inline-block;
|
||||
line-height: 0;
|
||||
canvas {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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';
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user