Skip to content

Commit e53cb3c

Browse files
committed
♻️ refactor: Organize dictionary structure
1 parent 1e38fea commit e53cb3c

File tree

14 files changed

+184
-6366
lines changed

14 files changed

+184
-6366
lines changed

package-lock.json

Lines changed: 0 additions & 6178 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"three": "^0.157.0"
1818
},
1919
"devDependencies": {
20+
"@types/node": "^20.12.7",
2021
"@types/react": "^18.2.15",
2122
"@types/react-dom": "^18.2.7",
2223
"@typescript-eslint/eslint-plugin": "^6.0.0",

src/App.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import "./assets/scss/global.scss"
2-
31
import Tetris from "./pages/Tetris"
42

53
function App() {
@@ -10,5 +8,4 @@ function App() {
108
)
119
}
1210

13-
14-
export default App
11+
export default App
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ $color-start-btn-shadow: #c0392b;
66
$color-quit-btn: #77c899;
77
$color-quit-btn-shadow: #27ae60;
88

9-
109
* {
1110
margin: 0;
1211
padding: 0;
@@ -20,7 +19,7 @@ $color-quit-btn-shadow: #27ae60;
2019
.game-header {
2120
position: absolute;
2221
width: 100vw;
23-
top: 40px;
22+
top: 20px;
2423
left: 50%;
2524
transform: translateX(-50%);
2625
z-index: 10;
@@ -32,13 +31,9 @@ $color-quit-btn-shadow: #27ae60;
3231
.github-logo {
3332
height: 45px;
3433
margin-right: 10px;
35-
vertical-align: middle;
36-
border: 3px solid #333;
3734
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
3835
border-radius: 50%;
3936
background-color: #fff;
40-
transform: perspective(500px) rotateX(10deg) rotateY(10deg);
41-
transition: transform 0.3s ease;
4237
}
4338

4439
.title-3d {
@@ -51,7 +46,7 @@ $color-quit-btn-shadow: #27ae60;
5146
3px 3px 0 $color-game-title-shadow,
5247
4px 4px 0 $color-game-title-shadow,
5348
5px 5px 0 $color-game-title-shadow;
54-
padding: 5px 10px;
49+
padding:40px 10px;
5550
border-radius: 5px;
5651
letter-spacing: 5px;
5752
}
@@ -61,7 +56,6 @@ $color-quit-btn-shadow: #27ae60;
6156
display: flex;
6257
gap: 10px;
6358
z-index: 10;
64-
gap: 10px;
6559

6660
.hidden {
6761
opacity: 0;
@@ -114,7 +108,6 @@ $color-quit-btn-shadow: #27ae60;
114108
5px 0px 10px rgba($color-quit-btn, 0.3);
115109
}
116110
}
117-
118111
}
119112
}
120113

@@ -155,9 +148,10 @@ $color-quit-btn-shadow: #27ae60;
155148
ul {
156149
list-style-type: none;
157150
padding-left: 0;
158-
151+
margin: 10px 0;
152+
159153
li {
160-
margin-bottom: 10px;
154+
margin: 10px 0;
161155

162156
&>strong {
163157
font-weight: bold;
@@ -176,13 +170,12 @@ $color-quit-btn-shadow: #27ae60;
176170
}
177171

178172
span {
179-
font-size: 1.2em;
173+
font-size: 1.1em;
180174
}
181175
}
182176

183177
.axis-label {
184178
color: white;
185-
font-family: Georgia;
186179
text-align: center;
187180
}
188181
}

src/assets/images/github.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
/* 获取当前 Canvas 的相机角度 */
2-
31
import { useFrame, useThree } from "react-three-fiber";
42
import { Vector3 } from "three";
53

64
interface CameraDirectionUpdaterProps {
75
setDirection: (dir: Vector3) => void;
86
}
97

10-
export const CameraDirectionUpdater: React.FC<CameraDirectionUpdaterProps> = ({ setDirection }) => {
8+
/**
9+
* 获取当前 Canvas 的相机角度
10+
*/
11+
const CameraDirectionUpdater: React.FC<CameraDirectionUpdaterProps> = ({ setDirection }) => {
1112
const { camera } = useThree();
1213

1314
useFrame(() => {
@@ -18,3 +19,5 @@ export const CameraDirectionUpdater: React.FC<CameraDirectionUpdaterProps> = ({
1819

1920
return null;
2021
};
22+
23+
export default CameraDirectionUpdater;

src/components/MiniAxes.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
/* 迷你坐标轴 */
2-
31
import { Html } from '@react-three/drei';
42
import { useFrame, useThree } from '@react-three/fiber';
53
import React, { useEffect, useRef } from 'react';
64
import { ArrowHelper, Color, Group, Vector3 } from 'three';
75

6+
/**
7+
* 迷你坐标轴
8+
*/
89
interface MiniAxesProps {
910
position?: [number, number, number];
1011
cameraDirection: Vector3;
@@ -45,16 +46,16 @@ const MiniAxes: React.FC<MiniAxesProps> = ({ position = [0, 0, 0], cameraDirecti
4546
scene.remove(groupRef.current);
4647
};
4748

48-
4949
useEffect(() => {
5050
setupArrows();
5151
scene.add(groupRef.current);
5252

5353
return () => {
5454
cleanupArrows();
5555
};
56-
}, [scene]);
5756

57+
// eslint-disable-next-line react-hooks/exhaustive-deps
58+
}, [scene]);
5859

5960
// 每一帧渲染时随着传入的方向一起旋转
6061
useFrame(() => {
@@ -80,4 +81,4 @@ const MiniAxes: React.FC<MiniAxesProps> = ({ position = [0, 0, 0], cameraDirecti
8081
);
8182
};
8283

83-
export default MiniAxes;
84+
export default MiniAxes;

src/components/Tetrimino.tsx

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
/* 七种小方块组件 */
2-
31
import { Box } from '@react-three/drei';
42
import React from 'react';
53
import { BoxGeometry } from 'three';
64

5+
export type Block = { x: number; y: number; z: number };
6+
77
interface TetriminoProps {
88
type: TetriminoType;
99
position: [number, number, number];
1010
blocks: Block[];
11-
scale?: number; // 缩放可选
11+
scale?: number;
1212
}
13-
1413
interface TetriminoDefinition {
1514
blocks: Block[];
1615
color: string;
1716
}
1817

19-
export type Block = { x: number; y: number; z: number };
20-
2118
export type TetriminoType = keyof typeof Tetriminos;
2219

23-
// 七种俄罗斯方块种类
20+
/**
21+
* 七种俄罗斯方块
22+
*/
2423
export const Tetriminos: { [key: string]: TetriminoDefinition } = {
2524
OrangeRicky: {
2625
blocks: [
@@ -87,7 +86,9 @@ export const Tetriminos: { [key: string]: TetriminoDefinition } = {
8786
}
8887
};
8988

90-
// 单独一个方块
89+
/**
90+
* 单独一个方块
91+
*/
9192
export const Cube: React.FC<{ position: Block; color: string }> = ({ position, color }) => {
9293
return (
9394
<group position={[position.x, position.y, position.z]}>
@@ -102,8 +103,10 @@ export const Cube: React.FC<{ position: Block; color: string }> = ({ position, c
102103
);
103104
};
104105

105-
// 所有方块构成的整体
106-
export const Tetrimino: React.FC<TetriminoProps> = ({ type, position, blocks, scale = 1 }) => {
106+
/**
107+
* 所有方块构成的整体
108+
*/
109+
export const TetriminoSet: React.FC<TetriminoProps> = ({ type, position, blocks, scale = 1 }) => {
107110
const tetriminoColor = Tetriminos[type].color;
108111

109112
return (
@@ -117,26 +120,28 @@ export const Tetrimino: React.FC<TetriminoProps> = ({ type, position, blocks, sc
117120
);
118121
};
119122

120-
// 已经下落的方块集合
123+
/**
124+
* 已经下落的方块集合
125+
*/
121126
export const FallenCubes: React.FC<{ gridState: (string | null)[][][] }> = ({ gridState }) => {
122127
const cubes = [];
123128

124129
for (let x = 0; x < gridState.length; x++) {
125-
for (let z = 0; z < gridState[x].length; z++) {
126-
for (let y = 0; y < gridState[x][z].length; y++) {
127-
const color = gridState[x][z][y];
128-
if (color) {
129-
cubes.push(
130-
<Cube
131-
key={`${x},${y},${z}`}
132-
position={{ x: x + 0.5, y: y + 0.5, z: z + 0.5 }}
133-
color={color}
134-
/>
135-
);
136-
}
137-
}
130+
for (let z = 0; z < gridState[x].length; z++) {
131+
for (let y = 0; y < gridState[x][z].length; y++) {
132+
const color = gridState[x][z][y];
133+
if (color) {
134+
cubes.push(
135+
<Cube
136+
key={`${x},${y},${z}`}
137+
position={{ x: x + 0.5, y: y + 0.5, z: z + 0.5 }}
138+
color={color}
139+
/>
140+
);
141+
}
138142
}
143+
}
139144
}
140145

141146
return <>{cubes}</>;
142-
};
147+
};

src/components/ThreeSidedGrid.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/* 6×6×12的空间网格组件 */
2-
1+
/**
2+
* 6×6×12的空间网格组件
3+
*/
34
const ThreeSidedGrid: React.FC = () => {
4-
55
const size = 6;
66
const divisions = 6;
77
const color = "gray"

src/libs/initUtils.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Block, TetriminoType, Tetriminos } from "@/components/Tetrimino";
2+
3+
// eslint-disable-next-line prefer-const
4+
let bag: TetriminoType[] = [];
5+
6+
/**
7+
* 随机选择方块类型
8+
* (Multi-bag Random Generator)
9+
*/
10+
export function getRandomTetrimino(): TetriminoType {
11+
const shuffleArray = (array: TetriminoType[]): TetriminoType[] => {
12+
for (let i = array.length - 1; i > 0; i--) {
13+
const j = Math.floor(Math.random() * (i + 1));
14+
[array[i], array[j]] = [array[j], array[i]];
15+
}
16+
return array;
17+
}
18+
const fillBag = () => {
19+
const tetriminos = Object.keys(Tetriminos) as TetriminoType[];
20+
for (let i = 0; i < 3; i++) { // 每种方块三个
21+
bag.push(...tetriminos);
22+
}
23+
shuffleArray(bag);
24+
}
25+
26+
if (bag.length === 0) {
27+
fillBag();
28+
}
29+
30+
return bag.pop()!;
31+
}
32+
33+
/**
34+
* 随机旋转方块
35+
*/
36+
export function rotateRandomly(blocks: Block[]): Block[] {
37+
for (let i = 0; i < 5; i++) {
38+
const rotateTypes = Math.floor(Math.random() * 3);
39+
switch (rotateTypes) {
40+
case 0:
41+
blocks = blocks.map(block => ({ x: block.y, y: -block.x, z: block.z }));
42+
break;
43+
case 1:
44+
blocks = blocks.map(block => ({ x: -block.z, y: block.y, z: block.x }));
45+
break;
46+
default:
47+
break;
48+
}
49+
}
50+
return blocks;
51+
}
52+
53+
/**
54+
* 随机获取下落位置
55+
*/
56+
export function getRandomPosition(rotatedBlocks: Block[]): [number, number, number] {
57+
const getBounds = (blocks: Block[]) => {
58+
let minX = Infinity, maxX = -Infinity;
59+
let minY = Infinity, maxY = -Infinity;
60+
let minZ = Infinity, maxZ = -Infinity;
61+
62+
blocks.forEach(block => {
63+
minX = Math.min(minX, block.x);
64+
maxX = Math.max(maxX, block.x);
65+
minY = Math.min(minY, block.y);
66+
maxY = Math.max(maxY, block.y);
67+
minZ = Math.min(minZ, block.z);
68+
maxZ = Math.max(maxZ, block.z);
69+
});
70+
71+
return { minX, maxX, minY, maxY, minZ, maxZ };
72+
}
73+
74+
const bounds = getBounds(rotatedBlocks);
75+
76+
const xRange = 5 - (bounds.maxX - bounds.minX);
77+
const zRange = 5 - (bounds.maxZ - bounds.minZ);
78+
79+
const x = Math.floor(Math.random() * xRange) - bounds.minX + 0.5;
80+
const y = 11.5 - bounds.maxY;
81+
const z = Math.floor(Math.random() * zRange) - bounds.minZ + 0.5;
82+
83+
return [x, y, z];
84+
}

0 commit comments

Comments
 (0)