File size: 4,365 Bytes
ec43676
aa1b508
 
f68ade5
42ffd2e
e9d3f6f
aa1b508
42ffd2e
 
 
 
aa1b508
 
aa74807
 
 
 
 
e9d3f6f
f68ade5
42ffd2e
 
 
 
 
f68ade5
 
42ffd2e
 
e9d3f6f
 
f68ade5
 
42ffd2e
f68ade5
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
42ffd2e
aa74807
42ffd2e
 
f68ade5
 
 
 
 
42ffd2e
 
e9d3f6f
 
f68ade5
ec43676
42ffd2e
 
 
 
e9d3f6f
ec43676
f68ade5
42ffd2e
 
 
e9d3f6f
42ffd2e
 
f68ade5
ec43676
 
aa1b508
 
42ffd2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa1b508
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { useCubesContext } from "@/contexts/cubes-context";
import { FacingDirection } from "./consts";
import { RotationPanel } from "./rotation-panel";
import { Group } from "three";
import { Fragment, useRef } from "react";
import { useFrame } from "@react-three/fiber";

type RotateArgs = {
  rotatingFaceDirection: FacingDirection;
  rotatingDirection: "clockwise" | "counter-clockwise";
  rotatingGroup: Group;
};

type RotatorProps = {
  cubeSpeed: number;
};

export const Rotator = ({ cubeSpeed }: RotatorProps) => {
  const { getCubes, cubeGroupRef } = useCubesContext();
  const isRotating = useRef(false);
  const rotateArgs = useRef<RotateArgs>({
    rotatingFaceDirection: "front",
    rotatingDirection: "clockwise",
    rotatingGroup: new Group(),
  });

  useFrame((state, delta) => {
    const { rotatingFaceDirection, rotatingDirection, rotatingGroup } =
      rotateArgs.current;
    const cubeGroup = cubeGroupRef.current;
    if (!isRotating.current || !cubeGroup) return;

    let sign = 0;
    switch (rotatingFaceDirection) {
      case "front":
        sign = rotatingDirection === "clockwise" ? -1 : 1;
        rotatingGroup.rotation.z += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.z) > Math.PI / 2) {
          rotatingGroup.rotation.z = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
      case "back":
        sign = rotatingDirection === "clockwise" ? 1 : -1;
        rotatingGroup.rotation.z += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.z) > Math.PI / 2) {
          rotatingGroup.rotation.z = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
      case "left":
        sign = rotatingDirection === "clockwise" ? 1 : -1;
        rotatingGroup.rotation.x += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.x) > Math.PI / 2) {
          rotatingGroup.rotation.x = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
      case "right":
        sign = rotatingDirection === "clockwise" ? -1 : 1;
        rotatingGroup.rotation.x += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.x) > Math.PI / 2) {
          rotatingGroup.rotation.x = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
      case "top":
        sign = rotatingDirection === "clockwise" ? -1 : 1;
        rotatingGroup.rotation.y += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.y) > Math.PI / 2) {
          rotatingGroup.rotation.y = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
      case "bottom":
        sign = rotatingDirection === "clockwise" ? 1 : -1;
        rotatingGroup.rotation.y += sign * delta * cubeSpeed;
        if (Math.abs(rotatingGroup.rotation.y) > Math.PI / 2) {
          rotatingGroup.rotation.y = (Math.PI / 2) * sign;
          isRotating.current = false;
        }
        break;
    }

    if (isRotating.current) return;
    const children = [...rotatingGroup.children];
    children.forEach((child) => cubeGroup.attach(child));
    cubeGroup.remove(rotatingGroup);
  });

  const handleClick = (
    facingDirection: FacingDirection,
    direction: "clockwise" | "counter-clockwise",
  ) => {
    if (isRotating.current || !cubeGroupRef.current) return;
    const cubes = getCubes(facingDirection);

    rotateArgs.current.rotatingFaceDirection = facingDirection;
    rotateArgs.current.rotatingDirection = direction;
    rotateArgs.current.rotatingGroup = new Group();
    cubeGroupRef.current.add(rotateArgs.current.rotatingGroup);
    cubes.forEach((cube) => rotateArgs.current.rotatingGroup.attach(cube));

    isRotating.current = true;
  };

  return (
    <>
      {["front", "back", "left", "right", "top", "bottom"].map(
        (facingDirection) => (
          <Fragment key={facingDirection}>
            <RotationPanel
              direction="clockwise"
              facingDirection={facingDirection as FacingDirection}
              onClick={handleClick}
            />
            <RotationPanel
              direction="counter-clockwise"
              facingDirection={facingDirection as FacingDirection}
              onClick={handleClick}
            />
          </Fragment>
        ),
      )}
    </>
  );
};