|
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8"> |
5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
6 | | - <title>Event City</title> |
| 6 | + <title>Event City: Living Monolith</title> |
7 | 7 | <link rel="manifest" href="manifest.json"> |
8 | 8 | <style> |
9 | 9 | body { margin: 0; overflow: hidden; background: #0f0f0f; } |
|
17 | 17 | display: flex; |
18 | 18 | flex-direction: column; |
19 | 19 | align-items: center; |
20 | | -transition: opacity 0.7s; |
| 20 | + transition: opacity 0.7s; |
21 | 21 | } |
22 | | - #header-link:hover { opacity: 0.3; } |
| 22 | + #header-link:hover { opacity: 0.5; } |
23 | 23 | #header-logo { |
24 | | -opacity: 0.7; |
| 24 | + opacity: 0.7; |
25 | 25 | max-height: 60px; |
26 | 26 | display: block; |
27 | 27 | } |
|
87 | 87 | color: 0xCCCCCC, metalness: 0.9, roughness: 0.18, emissive: 0x050505 |
88 | 88 | }); |
89 | 89 | const geom = new THREE.BoxGeometry(0.95, 1, 0.95); |
| 90 | + const cubes = []; // Массив для хранения ссылок на кубы |
90 | 91 | for (let x = 0; x < 8; x++) { |
| 92 | + cubes[x] = []; |
91 | 93 | for (let z = 0; z < 8; z++) { |
92 | 94 | let sx = x < 4 ? x : 7 - x; |
93 | 95 | let sz = z < 4 ? z : 7 - z; |
|
98 | 100 | cube.position.set(x - 3.5, height / 2, z - 3.5); |
99 | 101 | cube.castShadow = true; |
100 | 102 | cube.receiveShadow = true; |
| 103 | + cube.userData.height = height; // Сохраняем высоту |
101 | 104 | scene.add(cube); |
| 105 | + cubes[x][z] = cube; // Сохраняем куб |
102 | 106 | } |
103 | 107 | } |
104 | 108 | const infinitePlane = new THREE.Mesh( |
|
110 | 114 | infinitePlane.receiveShadow = true; |
111 | 115 | scene.add(infinitePlane); |
112 | 116 | renderer.setClearColor(scene.fog.color); |
| 117 | + |
| 118 | + // --- ЛОГИКА ШАХМАТ --- |
| 119 | + const pieces = []; |
| 120 | + const conflictPointLight = new THREE.PointLight(0xff3300, 0, 5); // Свет конфликта |
| 121 | + scene.add(conflictPointLight); |
| 122 | + |
| 123 | + function createPiece(type, mat, x, z) { |
| 124 | + let piece; |
| 125 | + const scale = 0.4; |
| 126 | + switch(type) { |
| 127 | + case 'p': piece = new THREE.Mesh(new THREE.ConeGeometry(scale, scale*2, 8), mat); break; // Пешка |
| 128 | + case 'r': piece = new THREE.Mesh(new THREE.CylinderGeometry(scale, scale, scale*2, 8), mat); break; // Ладья |
| 129 | + case 'n': piece = new THREE.Mesh(new THREE.BoxGeometry(scale, scale*2, scale*1.5), mat); break; // Конь (стилизованный) |
| 130 | + case 'b': piece = new THREE.Mesh(new THREE.ConeGeometry(scale, scale*3, 4), mat); break; // Слон |
| 131 | + case 'q': piece = new THREE.Mesh(new THREE.SphereGeometry(scale*1.2, 8, 8), mat); break; // Ферзь |
| 132 | + case 'k': piece = new THREE.Mesh(new THREE.BoxGeometry(scale*1.5, scale*1.5, scale*1.5), mat); break; // Король |
| 133 | + } |
| 134 | + piece.castShadow = true; |
| 135 | + piece.userData.gridX = x; |
| 136 | + piece.userData.gridZ = z; |
| 137 | + scene.add(piece); |
| 138 | + pieces.push(piece); |
| 139 | + } |
| 140 | + |
| 141 | + const initialBoard = [ |
| 142 | + ['r','n','b','q','k','b','n','r'], |
| 143 | + ['p','p','p','p','p','p','p','p'], |
| 144 | + [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], |
| 145 | + ['P','P','P','P','P','P','P','P'], |
| 146 | + ['R','N','B','Q','K','B','N','R'] |
| 147 | + ]; |
| 148 | + |
| 149 | + for (let z = 0; z < 8; z++) { |
| 150 | + for (let x = 0; x < 8; x++) { |
| 151 | + const p = initialBoard[z][x]; |
| 152 | + if (p) { |
| 153 | + const mat = p === p.toUpperCase() ? goldMat : platMat; |
| 154 | + createPiece(p.toLowerCase(), mat, x, z); |
| 155 | + } |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + let lastMoveTime = 0; |
| 160 | + let conflictCube = null; |
| 161 | + |
113 | 162 | function animate(time) { |
114 | 163 | requestAnimationFrame(animate); |
115 | 164 | const t = time * 0.0008; |
|
118 | 167 | movingLight.position.z = Math.sin(t * 2) * (radius / 2); |
119 | 168 | movingLight.position.y = 8 + Math.cos(t * 1.5) * 2; |
120 | 169 | lightSphere.position.copy(movingLight.position); |
| 170 | + |
| 171 | + // Обновление позиции фигур над кубами |
| 172 | + pieces.forEach(p => { |
| 173 | + const x = p.userData.gridX; |
| 174 | + const z = p.userData.gridZ; |
| 175 | + const cube = cubes[x][z]; |
| 176 | + p.position.set(cube.position.x, cube.userData.height + 0.5, cube.position.z); |
| 177 | + }); |
| 178 | + |
| 179 | + // Эффект конфликта |
| 180 | + if (conflictCube) { |
| 181 | + conflictCube.material.emissiveIntensity = 0.5 + Math.sin(time * 0.01) * 0.4; |
| 182 | + conflictPointLight.position.copy(conflictCube.position); |
| 183 | + conflictPointLight.position.y += conflictCube.userData.height + 1; |
| 184 | + conflictPointLight.intensity = 1 + Math.sin(time * 0.01) * 0.5; |
| 185 | + } |
| 186 | + |
| 187 | + // Логика движения (каждую секунду) |
| 188 | + if (time - lastMoveTime > 1000) { |
| 189 | + const piece = pieces[Math.floor(Math.random() * pieces.length)]; |
| 190 | + let newX = Math.floor(Math.random() * 8); |
| 191 | + let newZ = Math.floor(Math.random() * 8); |
| 192 | + |
| 193 | + // Очистка старого конфликта |
| 194 | + if (conflictCube) { |
| 195 | + conflictCube.material.emissiveIntensity = 0.1; |
| 196 | + conflictCube = null; |
| 197 | + conflictPointLight.intensity = 0; |
| 198 | + } |
| 199 | + |
| 200 | + // Проверка на конфликт |
| 201 | + const targetPiece = pieces.find(p => p.userData.gridX === newX && p.userData.gridZ === newZ && p !== piece); |
| 202 | + if (targetPiece) { |
| 203 | + conflictCube = cubes[newX][newZ]; // Запускаем свечение |
| 204 | + } |
| 205 | + |
| 206 | + piece.userData.gridX = newX; |
| 207 | + piece.userData.gridZ = newZ; |
| 208 | + lastMoveTime = time; |
| 209 | + } |
| 210 | + |
121 | 211 | controls.update(); |
122 | 212 | renderer.render(scene, camera); |
123 | 213 | } |
|
0 commit comments