Skip to content

Commit 40ba375

Browse files
committed
Hexagonal tile factory
1 parent 7e37019 commit 40ba375

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

src/factory/HexagonalTileFactory.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { ExtrudeGeometry, InstancedMesh, Material, MeshStandardMaterial, Object3D, Shape } from "three";
2+
3+
export interface HexagonalTileOptions {
4+
width: number; // Total area width to fill (x-axis)
5+
depth: number; // Total area depth to fill (z-axis)
6+
height: number; // Height of each tile (y-axis)
7+
radius: number; // Radius of each hexagonal tile
8+
gap: number; // Gap spacing between tiles
9+
material?: Material; // Optional custom material
10+
}
11+
12+
/**
13+
* Hexagonal tile pattern factory.
14+
*
15+
* Example usage:
16+
* ```ts
17+
* const hexTile = createHexagonalTile({
18+
* width: 10,
19+
* depth: 10,
20+
* height: 0.01,
21+
* radius: 0.1,
22+
* gap: 0.01,
23+
* material: new THREE.MeshStandardMaterial({ color: ColorPalette.White }),
24+
* });
25+
*
26+
* scene.add(hexTile);
27+
* ```
28+
*/
29+
export function createHexagonalTile(options: HexagonalTileOptions): InstancedMesh {
30+
const { width, depth, height, radius, gap, material } = options;
31+
32+
const tileMaterial = material || new MeshStandardMaterial({ color: 0x8b4513 }); // Default earthy color
33+
34+
// Effective spacing between hexagon centers, including the gap
35+
const spacingX = (radius * 3) / 2 + gap; // Horizontal distance between hex centers
36+
const spacingZ = Math.sqrt(3) * radius + gap; // Vertical distance between hex centers
37+
38+
// Calculate the number of tiles that fit within the area
39+
const hexTileCountX = Math.floor(width / spacingX);
40+
const hexTileCountZ = Math.floor(depth / spacingZ);
41+
42+
const hexTileCount = hexTileCountX * hexTileCountZ;
43+
44+
// Create a hexagonal prism geometry
45+
const hexShape = new Shape();
46+
for (let i = 0; i < 6; i++) {
47+
const angle = (Math.PI / 3) * i; // 60-degree increments
48+
const x = Math.cos(angle) * radius;
49+
const y = Math.sin(angle) * radius;
50+
51+
if (i === 0) hexShape.moveTo(x, y);
52+
else hexShape.lineTo(x, y);
53+
}
54+
hexShape.closePath();
55+
const geometry = new ExtrudeGeometry(hexShape, { depth: height, bevelEnabled: false });
56+
57+
// Rotate geometry so tiles lay flat
58+
geometry.rotateX(-Math.PI / 2);
59+
60+
// Create the instanced mesh
61+
const instancedMesh = new InstancedMesh(geometry, tileMaterial, hexTileCount);
62+
63+
const dummy = new Object3D();
64+
let index = 0;
65+
66+
for (let x = 0; x < hexTileCountX; x++) {
67+
for (let z = 0; z < hexTileCountZ; z++) {
68+
// Calculate the staggered row offset
69+
const offsetX = x * spacingX;
70+
const offsetZ = z * spacingZ + (x % 2) * (spacingZ / 2); // Stagger odd rows by half a tile
71+
72+
// Center the grid
73+
const positionX = offsetX - (hexTileCountX * spacingX) / 2 + spacingX / 2;
74+
const positionZ = offsetZ - (hexTileCountZ * spacingZ) / 2 + spacingZ / 2;
75+
76+
dummy.position.set(positionX, 0, positionZ);
77+
dummy.updateMatrix();
78+
instancedMesh.setMatrixAt(index++, dummy.matrix);
79+
}
80+
}
81+
82+
instancedMesh.instanceMatrix.needsUpdate = true;
83+
84+
return instancedMesh;
85+
}

0 commit comments

Comments
 (0)