Aleksmorshen commited on
Commit
b925469
·
verified ·
1 Parent(s): f48879f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +195 -143
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Флагманский Корабль - Babylon.js</title>
7
  <style>
8
  html, body {
9
  overflow: hidden;
@@ -11,190 +11,242 @@
11
  height: 100%;
12
  margin: 0;
13
  padding: 0;
14
- font-family: sans-serif;
15
- background-color: #000; /* Черный фон для космоса */
16
- color: #fff;
17
  }
18
 
19
  #renderCanvas {
20
  width: 100%;
21
  height: 100%;
22
- touch-action: none; /* Важно для сенсорных устройств */
23
- display: block; /* Убирает лишнее пространство под canvas */
24
  }
25
 
26
- #info {
 
27
  position: absolute;
28
- top: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
29
  left: 10px;
 
30
  background-color: rgba(0,0,0,0.5);
31
- padding: 10px;
32
- border-radius: 5px;
33
  font-size: 12px;
34
  }
35
  </style>
36
- <!-- Подключаем Babylon.js -->
37
  <script src="https://cdn.babylonjs.com/babylon.js"></script>
38
- <!-- Дополнительные библиотеки для удобства (не обязательно, но полезно для сложных фигур) -->
39
- <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
40
- <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
41
-
42
  </head>
43
  <body>
44
-
45
  <canvas id="renderCanvas"></canvas>
46
- <div id="info">ЛКМ + Движение: Вращать камеру | Колесико: Зум</div>
 
 
 
 
47
 
48
  <script>
49
- // Получаем canvas элемент
50
  const canvas = document.getElementById('renderCanvas');
51
-
52
- // Создаем движок Babylon.js
53
  const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
54
 
55
- // --- Функция создания сцены ---
56
- const createScene = function () {
57
- // Создаем сцену
 
 
 
 
58
  const scene = new BABYLON.Scene(engine);
59
- scene.clearColor = new BABYLON.Color3(0.02, 0.02, 0.05); // Темно-синий космос
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
- // Создаем камеру - ArcRotateCamera удобна для осмотра объекта
62
- const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 15, BABYLON.Vector3.Zero(), scene);
63
- camera.attachControl(canvas, true);
64
- camera.lowerRadiusLimit = 5; // Минимальное приближение
65
- camera.upperRadiusLimit = 50; // Максимальное отдаление
66
- camera.wheelPrecision = 50; // Чувствительность зума колесиком
67
 
68
- // Создаем свет
69
  const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
70
  light.intensity = 0.8;
71
- const pointLight = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(5, 10, -5), scene);
72
- pointLight.intensity = 0.5;
73
-
74
- // --- Создание модели корабля ---
75
-
76
- // Создаем пустой "родительский" меш для всего корабля
77
- // Это упрощает вращение и перемещение всей модели целиком
78
- const flagship = new BABYLON.Mesh("flagship", scene);
79
-
80
- // 1. Основной корпус (вытянутая сфера)
81
- const body = BABYLON.MeshBuilder.CreateSphere("body", { diameterX: 6, diameterY: 1.5, diameterZ: 2 }, scene);
82
- body.position.y = 0;
83
- body.parent = flagship; // Делаем корпус дочерним к основному мешу
84
-
85
- // 2. Кабина пилота (сфера поменьше спереди)
86
- const cockpit = BABYLON.MeshBuilder.CreateSphere("cockpit", { diameter: 1.2 }, scene);
87
- cockpit.position.x = 2.8; // Смещаем вперед по X
88
- cockpit.position.y = 0.2; // Немного приподнимаем
89
- cockpit.scaling.z = 1.5; // Слегка вытягиваем
90
- cockpit.parent = flagship;
91
-
92
- // 3. Крылья (плоские боксы)
93
- const wingMat = new BABYLON.StandardMaterial("wingMat", scene);
94
- wingMat.diffuseColor = new BABYLON.Color3(0.6, 0.6, 0.7); // Серый цвет
95
- wingMat.specularColor = new BABYLON.Color3(0.3, 0.3, 0.3); // Небольшой блик
96
-
97
- const wingLeft = BABYLON.MeshBuilder.CreateBox("wingLeft", { width: 1.5, height: 0.15, depth: 4 }, scene);
98
- wingLeft.position = new BABYLON.Vector3(0, 0, -2.2); // Смещаем влево (по Z)
99
- wingLeft.rotation.y = BABYLON.Tools.ToRadians(15); // Небольшой угол
100
- wingLeft.parent = flagship;
101
- wingLeft.material = wingMat;
102
-
103
- const wingRight = wingLeft.clone("wingRight"); // Клонируем левое крыло
104
- wingRight.position.z = 2.2; // Смещаем вправо
105
- wingRight.rotation.y = BABYLON.Tools.ToRadians(-15); // Отражаем угол
106
- wingRight.parent = flagship;
107
-
108
- // 4. Двигатели (цилиндры сзади)
109
- const engineMat = new BABYLON.StandardMaterial("engineMat", scene);
110
- engineMat.diffuseColor = new BABYLON.Color3(0.3, 0.3, 0.3);
111
- engineMat.emissiveColor = new BABYLON.Color3(1, 0.5, 0); // Оранжевое свечение!
112
- engineMat.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1);
113
-
114
- const engineLeft = BABYLON.MeshBuilder.CreateCylinder("engineLeft", { height: 1.5, diameter: 0.8 }, scene);
115
- engineLeft.position = new BABYLON.Vector3(-3, 0, -1); // Сзади и слева
116
- engineLeft.rotation.z = BABYLON.Tools.ToRadians(90); // Поворачиваем горизонтально
117
- engineLeft.parent = flagship;
118
- engineLeft.material = engineMat;
119
-
120
- const engineRight = engineLeft.clone("engineRight");
121
- engineRight.position.z = 1; // Сзади и справа
122
- engineRight.parent = flagship;
123
-
124
- // --- Материалы для основных частей ---
125
- const bodyMat = new BABYLON.StandardMaterial("bodyMat", scene);
126
- bodyMat.diffuseColor = new BABYLON.Color3(0.8, 0.85, 0.9); // Светло-серый / Белый
127
- bodyMat.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5); // Сильный блик - металл
128
-
129
- const cockpitMat = new BABYLON.StandardMaterial("cockpitMat", scene);
130
- cockpitMat.diffuseColor = new BABYLON.Color3(0.2, 0.5, 1); // Синий
131
- cockpitMat.alpha = 0.7; // Полупрозрачность
132
- cockpitMat.specularColor = new BABYLON.Color3(0.8, 0.8, 1); // Яркий блик
133
-
134
- body.material = bodyMat;
135
- cockpit.material = cockpitMat;
136
-
137
- // --- Анимация ---
138
- scene.registerBeforeRender(function () {
139
- // Медленное вращение всего корабля вокруг оси Y
140
- flagship.rotation.y += 0.005;
141
-
142
- // Пульсация свечения двигателей (небольшое изменение emissiveColor)
143
- const pulse = Math.abs(Math.sin(performance.now() * 0.002)); // Значение от 0 до 1
144
- engineMat.emissiveColor = new BABYLON.Color3(1 * pulse, 0.5 * pulse, 0);
145
- });
146
 
147
- // --- Добавим немного "космической пыли" или звезд ---
148
- const particleSystem = new BABYLON.ParticleSystem("stars", 5000, scene);
149
- particleSystem.particleTexture = new BABYLON.Texture("https://www.babylonjs-playground.com/textures/flare.png", scene); // Простая текстура для частиц
150
-
151
- // Где создавать частицы (большая сфера вокруг)
152
- particleSystem.emitter = new BABYLON.Vector3(0, 0, 0); // Центр
153
- particleSystem.minEmitBox = new BABYLON.Vector3(-100, -100, -100);
154
- particleSystem.maxEmitBox = new BABYLON.Vector3(100, 100, 100);
155
-
156
- // Цвета частиц
157
- particleSystem.color1 = new BABYLON.Color4(0.8, 0.8, 1.0, 1.0);
158
- particleSystem.color2 = new BABYLON.Color4(0.9, 0.9, 1.0, 1.0);
159
- particleSystem.colorDead = new BABYLON.Color4(0.5, 0.5, 0.5, 0.1);
160
-
161
- // Размер частиц
162
- particleSystem.minSize = 0.1;
163
- particleSystem.maxSize = 0.5;
164
-
165
- // Время жизни
166
- particleSystem.minLifeTime = 100; // Долгоживущие, т.к. они статичны
167
- particleSystem.maxLifeTime = 100;
168
-
169
- // Скорость эмиссии
170
- particleSystem.emitRate = 500; // Создаем 500 сразу
171
-
172
- // Направление не нужно, т.к. они стоят на месте
173
- particleSystem.minEmitPower = 0;
174
- particleSystem.maxEmitPower = 0;
175
- particleSystem.updateSpeed = 0.01; // Очень медленное обновление
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
- particleSystem.start();
178
 
 
 
 
179
 
180
  return scene;
181
  };
182
- // --- Конец функции создания сцены ---
183
 
184
- // Создаем сцену
185
  const scene = createScene();
186
 
187
- // Запускаем цикл рендеринга
188
- engine.runRenderLoop(function () {
189
  scene.render();
190
  });
191
 
192
- // Обрабатываем изменение размера окна
193
- window.addEventListener('resize', function () {
194
  engine.resize();
195
  });
196
 
197
  </script>
198
-
199
  </body>
200
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Простой Minecraft-клон на Babylon.js</title>
7
  <style>
8
  html, body {
9
  overflow: hidden;
 
11
  height: 100%;
12
  margin: 0;
13
  padding: 0;
14
+ font-family: sans-serif; /* Добавим шрифт для UI */
 
 
15
  }
16
 
17
  #renderCanvas {
18
  width: 100%;
19
  height: 100%;
20
+ touch-action: none; /* Для мобильных устройств */
 
21
  }
22
 
23
+ /* Простой интерфейс для прицела */
24
+ #crosshair {
25
  position: absolute;
26
+ top: 50%;
27
+ left: 50%;
28
+ width: 10px;
29
+ height: 10px;
30
+ border: 1px solid white;
31
+ background-color: rgba(0, 0, 0, 0.5);
32
+ transform: translate(-50%, -50%);
33
+ pointer-events: none; /* Чтобы не мешал кликам */
34
+ }
35
+ /* Инструкция */
36
+ #instructions {
37
+ position: absolute;
38
+ bottom: 10px;
39
  left: 10px;
40
+ color: white;
41
  background-color: rgba(0,0,0,0.5);
42
+ padding: 5px;
43
+ border-radius: 3px;
44
  font-size: 12px;
45
  }
46
  </style>
47
+ <!-- Подключение Babylon.js -->
48
  <script src="https://cdn.babylonjs.com/babylon.js"></script>
49
+ <!-- Опционально: загрузчики моделей/текстур, если понадобятся -->
50
+ <!-- <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> -->
 
 
51
  </head>
52
  <body>
 
53
  <canvas id="renderCanvas"></canvas>
54
+ <div id="crosshair"></div>
55
+ <div id="instructions">
56
+ WASD/Стрелки: Движение | Пробел: Вверх | Shift: Вниз <br>
57
+ Левый клик: Удалить блок | Правый клик: Поставить блок
58
+ </div>
59
 
60
  <script>
 
61
  const canvas = document.getElementById('renderCanvas');
 
 
62
  const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
63
 
64
+ const BLOCK_SIZE = 1; // Размер одного блока
65
+ const WORLD_WIDTH = 16; // Ширина мира в блоках
66
+ const WORLD_DEPTH = 16; // Глубина мира в блоках
67
+ const WORLD_HEIGHT = 8; // Максимальная высота мира (для генерации)
68
+
69
+ // --- Создание сцены ---
70
+ const createScene = () => {
71
  const scene = new BABYLON.Scene(engine);
72
+ scene.clearColor = new BABYLON.Color3(0.5, 0.8, 1.0); // Цвет неба
73
+ scene.gravity = new BABYLON.Vector3(0, -0.9, 0); // Гравитация
74
+ scene.collisionsEnabled = true; // Включаем обработку столкновений
75
+
76
+ // --- Камера ---
77
+ const camera = new BABYLON.UniversalCamera("playerCamera", new BABYLON.Vector3(WORLD_WIDTH / 2, WORLD_HEIGHT + 2, WORLD_DEPTH / 2), scene);
78
+ camera.setTarget(BABYLON.Vector3.Zero()); // Смотрим в центр
79
+ camera.attachControl(canvas, true); // Подключаем управление
80
+ camera.speed = 0.2; // Скорость движения
81
+ camera.angularSensibility = 4000; // Чувствительность мыши
82
+
83
+ // Включаем столкновения для камеры
84
+ camera.checkCollisions = true;
85
+ camera.applyGravity = true;
86
+ // Задаем "эллипсоид" - физическую модель игрока для столкновений
87
+ camera.ellipsoid = new BABYLON.Vector3(0.5, 0.9, 0.5); // Ширина, Высота, Глубина
88
+
89
+ // Управление с клавиатуры (WASD + пробел/shift)
90
+ camera.keysUp.push(87); // W
91
+ camera.keysDown.push(83); // S
92
+ camera.keysLeft.push(65); // A
93
+ camera.keysRight.push(68); // D
94
+ // Добавляем управление вверх/вниз (не стандартное для UniversalCamera)
95
+ scene.onBeforeRenderObservable.add(() => {
96
+ if (camera.inputs.attached.keyboard) {
97
+ const keyboard = camera.inputs.attached.keyboard;
98
+ if (keyboard.directInput[' ']) { // Пробел
99
+ camera.cameraDirection.y += camera.speed / 10; // Двигаемся вверх
100
+ }
101
+ if (keyboard.directInput[16]) { // Shift
102
+ camera.cameraDirection.y -= camera.speed / 10; // Двигаемся вниз
103
+ }
104
+ }
105
+ });
106
 
 
 
 
 
 
 
107
 
108
+ // --- Освещение ---
109
  const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
110
  light.intensity = 0.8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
+ // --- Материалы блоков ---
113
+ const grassMaterial = new BABYLON.StandardMaterial("grassMat", scene);
114
+ grassMaterial.diffuseColor = new BABYLON.Color3(0.4, 0.8, 0.4); // Зеленый
115
+ grassMaterial.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1); // Меньше бликов
116
+
117
+ const dirtMaterial = new BABYLON.StandardMaterial("dirtMat", scene);
118
+ dirtMaterial.diffuseColor = new BABYLON.Color3(0.6, 0.4, 0.2); // Коричневый
119
+ dirtMaterial.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1);
120
+
121
+ const stoneMaterial = new BABYLON.StandardMaterial("stoneMat", scene);
122
+ stoneMaterial.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.5); // Серый
123
+ stoneMaterial.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1);
124
+
125
+ // --- Мир блоков ---
126
+ // Используем Map для хранения блоков { "x,y,z": mesh }
127
+ const blocks = new Map();
128
+
129
+ // Прототип блока (для клонирования)
130
+ const blockPrototype = BABYLON.MeshBuilder.CreateBox("blockProto", { size: BLOCK_SIZE }, scene);
131
+ blockPrototype.isVisible = false; // Сам прототип не видим
132
+ blockPrototype.checkCollisions = true; // Блоки должны иметь коллизию
133
+
134
+ // Генерация простого ландшафта
135
+ for (let x = 0; x < WORLD_WIDTH; x++) {
136
+ for (let z = 0; z < WORLD_DEPTH; z++) {
137
+ // Простая высота на основе шума (очень примитивно)
138
+ const height = Math.floor(WORLD_HEIGHT / 2 + Math.sin(x * 0.3) * 2 + Math.cos(z * 0.2) * 2);
139
+ for (let y = 0; y < height; y++) {
140
+ const block = blockPrototype.clone(`block_${x}_${y}_${z}`);
141
+ block.position = new BABYLON.Vector3(
142
+ x * BLOCK_SIZE + BLOCK_SIZE / 2,
143
+ y * BLOCK_SIZE + BLOCK_SIZE / 2,
144
+ z * BLOCK_SIZE + BLOCK_SIZE / 2
145
+ );
146
+ block.isVisible = true;
147
+
148
+ // Назначаем материал в зависимости от высоты
149
+ if (y === height - 1) {
150
+ block.material = grassMaterial; // Верхний слой - трава
151
+ } else if (y > height - 4) {
152
+ block.material = dirtMaterial; // Под травой - земля
153
+ } else {
154
+ block.material = stoneMaterial; // Глубже - камень
155
+ }
156
+
157
+ const blockKey = `${block.position.x - BLOCK_SIZE/2},${block.position.y - BLOCK_SIZE/2},${block.position.z - BLOCK_SIZE/2}`; // Ключ по нижнему углу
158
+ blocks.set(blockKey, block);
159
+ block.isBlock = true; // Флаг, что это наш блок
160
+ }
161
+ }
162
+ }
163
+
164
+ // --- Взаимодействие с блоками ---
165
+ scene.onPointerDown = (evt, pickResult) => {
166
+ // evt.button: 0 = левый клик, 1 = средний, 2 = правый клик
167
+
168
+ // --- Удаление блока (левый клик) ---
169
+ if (evt.button === 0) {
170
+ if (pickResult.hit && pickResult.pickedMesh && pickResult.pickedMesh.isBlock) {
171
+ const blockToRemove = pickResult.pickedMesh;
172
+ const blockKey = `${blockToRemove.position.x - BLOCK_SIZE/2},${blockToRemove.position.y - BLOCK_SIZE/2},${blockToRemove.position.z - BLOCK_SIZE/2}`;
173
+ blocks.delete(blockKey);
174
+ blockToRemove.dispose();
175
+ }
176
+ }
177
+
178
+ // --- Размещение блока (правый клик) ---
179
+ if (evt.button === 2) {
180
+ if (pickResult.hit && pickResult.pickedMesh) { // Проверяем, что попали во что-то
181
+ // Определяем позицию для нового блока
182
+ // Она должна быть смещена от точки попадания по нормали к поверхности
183
+ const normal = pickResult.getNormal(true); // Получаем нормаль к грани
184
+ const hitPoint = pickResult.pickedPoint;
185
+
186
+ // Вычисляем центр потенциального нового блока
187
+ const potentialPos = hitPoint.add(normal.scale(BLOCK_SIZE / 2));
188
+
189
+ // Округляем (снапим) к сетке блоков
190
+ // Важно: Вычитаем/добавляем половину размера блока для центрирования
191
+ const newBlockX = Math.floor(potentialPos.x / BLOCK_SIZE) * BLOCK_SIZE + BLOCK_SIZE / 2;
192
+ const newBlockY = Math.floor(potentialPos.y / BLOCK_SIZE) * BLOCK_SIZE + BLOCK_SIZE / 2;
193
+ const newBlockZ = Math.floor(potentialPos.z / BLOCK_SIZE) * BLOCK_SIZE + BLOCK_SIZE / 2;
194
+
195
+ const newBlockKey = `${newBlockX - BLOCK_SIZE/2},${newBlockY - BLOCK_SIZE/2},${newBlockZ - BLOCK_SIZE/2}`;
196
+
197
+ // Проверяем, не занято ли это место
198
+ if (!blocks.has(newBlockKey)) {
199
+ // Проверяем, не ставим ли блок "внутрь" игрока
200
+ const playerBox = new BABYLON.BoundingBox(
201
+ camera.position.subtract(camera.ellipsoid),
202
+ camera.position.add(camera.ellipsoid)
203
+ );
204
+ const newBlockBox = new BABYLON.BoundingBox(
205
+ new BABYLON.Vector3(newBlockX - BLOCK_SIZE/2, newBlockY - BLOCK_SIZE/2, newBlockZ - BLOCK_SIZE/2),
206
+ new BABYLON.Vector3(newBlockX + BLOCK_SIZE/2, newBlockY + BLOCK_SIZE/2, newBlockZ + BLOCK_SIZE/2)
207
+ );
208
+
209
+ if (!playerBox.intersects(newBlockBox)) {
210
+ const newBlock = blockPrototype.clone(`block_${newBlockKey.replace(/,/g, '_')}`);
211
+ newBlock.position = new BABYLON.Vector3(newBlockX, newBlockY, newBlockZ);
212
+ newBlock.material = dirtMaterial; // По умолчанию ставим землю
213
+ newBlock.isVisible = true;
214
+ newBlock.isBlock = true;
215
+ blocks.set(newBlockKey, newBlock);
216
+ } else {
217
+ console.log("Нельзя ставить блок внутри себя!");
218
+ }
219
+ } else {
220
+ console.log("Место занято!");
221
+ }
222
+ }
223
+ }
224
+ };
225
+
226
+ // Отключаем контекстное меню по правому клику на канвасе
227
+ canvas.addEventListener("contextmenu", (evt) => {
228
+ evt.preventDefault();
229
+ });
230
 
 
231
 
232
+ // --- Оптимизация (очень базовая) ---
233
+ // Можно добавить Octree для ускорения рендеринга и коллизий
234
+ // scene.createOrUpdateSelectionOctree();
235
 
236
  return scene;
237
  };
 
238
 
239
+ // --- Запуск ---
240
  const scene = createScene();
241
 
242
+ engine.runRenderLoop(() => {
 
243
  scene.render();
244
  });
245
 
246
+ window.addEventListener('resize', () => {
 
247
  engine.resize();
248
  });
249
 
250
  </script>
 
251
  </body>
252
  </html>