rlcube / src /components /rubiks-cube.tsx
imwithye's picture
add reset feature
52b5f8d
raw
history blame
2.27 kB
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
import { Group } from 'three';
import { RotationStep } from './consts';
import { CubePiece, CubePieceRef } from './cube-piece';
import { rotationController } from './rotation-controller';
import { Rotator, RotatorRef } from './rotator';
const CUBE_POSITIONS: Array<[number, number, number]> = [];
for (let x = -0.5; x <= 0.5; x += 1) {
for (let y = -0.5; y <= 0.5; y += 1) {
for (let z = -0.5; z <= 0.5; z += 1) {
CUBE_POSITIONS.push([x, y, z]);
}
}
}
export type RubiksCubeRef = {
rotate: (steps: Array<RotationStep>) => void;
reset: () => void;
};
type RubiksCubeProps = {
cubeRoughness: number;
cubeSpeed: number;
};
export const RubiksCube = forwardRef<RubiksCubeRef, RubiksCubeProps>(({ cubeRoughness, cubeSpeed }, ref) => {
const cubeGroupRef = useRef<Group | null>(null);
const rotatorRef = useRef<RotatorRef | null>(null);
const cubePieceRefs = useRef<Map<string, CubePieceRef>>(new Map());
useImperativeHandle(ref, () => ({
rotate: (steps: Array<RotationStep>) => rotatorRef.current?.rotate(steps),
reset: () => {
rotationController.stopRotation(() => {
cubePieceRefs.current.forEach((cubePieceRef) => {
cubePieceRef.resetPosition();
});
rotationController.initializeFaces();
});
},
}));
useEffect(() => {
if (!cubeGroupRef.current) return;
rotationController.setCubeGroup(cubeGroupRef.current);
rotationController.initializeFaces();
}, [cubeGroupRef]);
return (
<>
<group ref={cubeGroupRef}>
{CUBE_POSITIONS.map((position) => {
const positionKey = position.join(',');
return (
<CubePiece
key={positionKey}
ref={(ref) => {
if (ref) {
cubePieceRefs.current.set(positionKey, ref);
} else {
cubePieceRefs.current.delete(positionKey);
}
}}
initialPosition={position}
roughness={cubeRoughness}
/>
);
})}
</group>
<Rotator ref={rotatorRef} cubeSpeed={cubeSpeed} />
</>
);
});
RubiksCube.displayName = 'RubiksCube';