update: gui & add event listener for mouse and click event
This commit is contained in:
parent
dabd81ecfb
commit
a7d936fff6
@ -1,80 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
||||||
|
|
||||||
export class Drone {
|
|
||||||
constructor() {
|
|
||||||
this.drone = new THREE.Object3D();
|
|
||||||
|
|
||||||
// Создаем основное тело дрона (цилиндрическая форма)
|
|
||||||
const bodyGeometry = new THREE.CylinderGeometry(0.4, 0.6, 1, 32);
|
|
||||||
const bodyMaterial = new THREE.MeshStandardMaterial({ color: 0x0077ff, metalness: 0.6, roughness: 0.4 });
|
|
||||||
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
|
|
||||||
body.rotation.z = Math.PI / 2; // Поворачиваем для более аэродинамической формы
|
|
||||||
this.drone.add(body);
|
|
||||||
|
|
||||||
// Добавляем 4 стойки шасси
|
|
||||||
const legGeometry = new THREE.CylinderGeometry(0.05, 0.05, 0.6, 16);
|
|
||||||
const legMaterial = new THREE.MeshBasicMaterial({ color: 0x444444 });
|
|
||||||
const legPositions = [
|
|
||||||
[-0.4, -0.6, -0.4],
|
|
||||||
[-0.4, -0.6, 0.4],
|
|
||||||
[0.4, -0.6, -0.4],
|
|
||||||
[0.4, -0.6, 0.4],
|
|
||||||
];
|
|
||||||
legPositions.forEach((position) => {
|
|
||||||
const leg = new THREE.Mesh(legGeometry, legMaterial);
|
|
||||||
leg.position.set(...position);
|
|
||||||
leg.rotation.x = Math.PI / 2;
|
|
||||||
this.drone.add(leg);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Создаем пропеллеры
|
|
||||||
const propellerGeometry = new THREE.BoxGeometry(0.2, 0.02, 1.2);
|
|
||||||
const propellerMaterial = new THREE.MeshBasicMaterial({ color: 0x333333 });
|
|
||||||
const propellerPositions = [
|
|
||||||
[-0.6, 0.4, -0.6],
|
|
||||||
[-0.6, 0.4, 0.6],
|
|
||||||
[0.6, 0.4, -0.6],
|
|
||||||
[0.6, 0.4, 0.6],
|
|
||||||
];
|
|
||||||
this.propellers = [];
|
|
||||||
|
|
||||||
propellerPositions.forEach((position) => {
|
|
||||||
const propeller = new THREE.Mesh(propellerGeometry, propellerMaterial);
|
|
||||||
propeller.position.set(...position);
|
|
||||||
propeller.rotation.y = Math.PI / 2;
|
|
||||||
this.propellers.push(propeller);
|
|
||||||
this.drone.add(propeller);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Загрузка более детализированной 3D модели (опционально)
|
|
||||||
// const loader = new GLTFLoader();
|
|
||||||
// loader.load(
|
|
||||||
// './path_to_your_drone_model.glb',
|
|
||||||
// (gltf) => {
|
|
||||||
// this.drone.add(gltf.scene);
|
|
||||||
// },
|
|
||||||
// undefined,
|
|
||||||
// (error) => {
|
|
||||||
// console.error('Ошибка при загрузке модели:', error);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Метод для вращения пропеллеров
|
|
||||||
rotatePropellers(speed) {
|
|
||||||
this.propellers.forEach((propeller) => {
|
|
||||||
propeller.rotation.z += speed;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Метод для установки позиции дрона
|
|
||||||
setPosition(x, y, z) {
|
|
||||||
this.drone.position.set(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Получаем объект дрона для добавления в сцену
|
|
||||||
getObject() {
|
|
||||||
return this.drone;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,40 +3,41 @@ import * as THREE from 'three';
|
|||||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||||
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
|
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
|
||||||
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
|
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
|
||||||
import { Drone } from './Components/Drone';
|
import Drone from './model/Drone';
|
||||||
import HeightPoint from './Model/HeightPoint';
|
import HeightPoint from './model/HeightPoint';
|
||||||
|
import {RandomHeightPoint} from './helpers/generateRandomHeightPoints'
|
||||||
|
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
||||||
const RandomHeightPoint = () => {
|
|
||||||
let result = [];
|
|
||||||
for (let i = 0; i < 20; i++) {
|
|
||||||
for (let j = 0; j < 20; j++) {
|
|
||||||
result.push(new HeightPoint(i, j, Math.random() * 10 + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const mountRef = useRef(null);
|
const mountRef = useRef(null); // Указатель монтирования
|
||||||
const sceneRef = useRef(null);
|
const sceneRef = useRef(null); // Указатель на сцену
|
||||||
const [heightData, setHeightData] = useState(RandomHeightPoint());
|
const [heightData, setHeightData] = useState(RandomHeightPoint()); // Высоты
|
||||||
const [formData, setFormData] = useState({ x: '', y: '', height: '' });
|
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
||||||
const [drones, setDrones] = useState([])
|
const [mouseState, setMouseState] = useState({ x: 0, y: 0, z: 0 }); // Форма для ввода данных карты
|
||||||
|
const mouse = new THREE.Vector2();
|
||||||
|
|
||||||
|
const [drones, setDrones] = useState([]) // Все дроны
|
||||||
|
const [selectedDrone, setSelectedDrone] = useState(null); // Состояние для выбранного дрона
|
||||||
|
|
||||||
|
const [baseStation, setBaseStation] = useState([]) // Все дроны
|
||||||
|
const [selectedBaseStation, setSelectedBaseStation] = useState(null); // Состояние для выбранного дрона
|
||||||
|
|
||||||
const [mapSettings, setMapSettings] = useState({
|
const [mapSettings, setMapSettings] = useState({
|
||||||
maxHeight: 20,
|
maxHeight: 20,
|
||||||
coordX: 0,
|
coordX: 0,
|
||||||
coordY: 0,
|
coordY: 0,
|
||||||
});
|
}); // Настройки карты
|
||||||
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 });
|
|
||||||
|
|
||||||
|
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }); // контекстное меню сцены
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mountRef.current) return;
|
if (!mountRef.current) return;
|
||||||
let width = mountRef.current.clientWidth;
|
let width = mountRef.current.clientWidth;
|
||||||
let height = mountRef.current.clientHeight;
|
let height = mountRef.current.clientHeight;
|
||||||
|
// Создаем объект сцены
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
sceneRef.current = scene; // Сохраняем ссылку на сцену
|
// Сохраняем ссылку на сцену
|
||||||
|
sceneRef.current = scene;
|
||||||
|
// Создаем камеру
|
||||||
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
|
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
|
||||||
camera.position.set(0, 20, 30);
|
camera.position.set(0, 20, 30);
|
||||||
|
|
||||||
@ -90,6 +91,44 @@ const Dashboard = () => {
|
|||||||
light.position.set(0, 50, 50).normalize();
|
light.position.set(0, 50, 50).normalize();
|
||||||
scene.add(light);
|
scene.add(light);
|
||||||
|
|
||||||
|
// Обработка кликов на сцене
|
||||||
|
const handleClick = (event) => {
|
||||||
|
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
|
||||||
|
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
|
||||||
|
console.log('Mouse coordinates:', mouse);
|
||||||
|
const raycaster = new THREE.Raycaster();
|
||||||
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
||||||
|
console.log('Intersections:', intersects)
|
||||||
|
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]))
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
const selected = intersects[0].object;
|
||||||
|
console.log('Clicked on:', selected); // Лог для проверки объекта
|
||||||
|
const drone = drones.find(drone => drone.getObject().children[0] === selected);
|
||||||
|
if (drone) {
|
||||||
|
if (selectedDrone) {
|
||||||
|
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||||
|
}
|
||||||
|
drone.getObject().children[0].material.color.set(0xff1111);
|
||||||
|
setSelectedDrone(drone);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectedDrone) {
|
||||||
|
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||||
|
setSelectedDrone(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
renderer.domElement.addEventListener('click', handleClick);
|
||||||
|
renderer.domElement.addEventListener('mousemove', (event) => {
|
||||||
|
let x = event.x;
|
||||||
|
let y = event.y;
|
||||||
|
setMouseState({x: x, y: y, z: 0});
|
||||||
|
})
|
||||||
const animate = () => {
|
const animate = () => {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
controls.update();
|
controls.update();
|
||||||
@ -103,6 +142,7 @@ const Dashboard = () => {
|
|||||||
// drone.setPosition(droneData.x, droneData.y, droneData.z);
|
// drone.setPosition(droneData.x, droneData.y, droneData.z);
|
||||||
scene.add(droneData.getObject()); //drone.getObject()
|
scene.add(droneData.getObject()); //drone.getObject()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Обработка нажатия ПКМ
|
// Обработка нажатия ПКМ
|
||||||
renderer.domElement.addEventListener('contextmenu', (event) => {
|
renderer.domElement.addEventListener('contextmenu', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -112,23 +152,31 @@ const Dashboard = () => {
|
|||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// const gui = new GUI();
|
||||||
|
// gui.add( effectController, 'focalLength', 1, 135, 0.01 ).onChange( matChanger );
|
||||||
return () => {
|
return () => {
|
||||||
if (mountRef.current) {
|
if (mountRef.current) {
|
||||||
mountRef.current.removeChild(renderer.domElement);
|
mountRef.current.removeChild(renderer.domElement);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [heightData, mapSettings]);
|
}, [drones,heightData, mapSettings]);
|
||||||
|
|
||||||
|
// Добавление дрона в сцену
|
||||||
const handleAddDrone = () => {
|
const handleAddDrone = () => {
|
||||||
if (sceneRef.current) {
|
if (sceneRef.current) {
|
||||||
const drone = new Drone();
|
const current = Date.now();
|
||||||
drone.setPosition(Math.random() * 20 - 10, 0.5, Math.random() * 20 - 10);
|
const drone = new Drone(current/1000);
|
||||||
|
// Создаем новый материал для каждого дрона
|
||||||
|
const droneMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
|
||||||
|
drone.getObject().children[0].material = droneMaterial;
|
||||||
|
drone.setPosition(Math.random() * 20 - 10, 3, Math.random() * 20 - 10);
|
||||||
setDrones((prevDrones) => [...prevDrones, drone]);
|
setDrones((prevDrones) => [...prevDrones, drone]);
|
||||||
|
console.log(drones.map(drone => drone.getObject().children[0]));
|
||||||
sceneRef.current.add(drone.getObject());
|
sceneRef.current.add(drone.getObject());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
const handleInputChange = (event) => {
|
const handleInputChange = (event) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
setFormData({
|
setFormData({
|
||||||
@ -136,7 +184,7 @@ const Dashboard = () => {
|
|||||||
[name]: value,
|
[name]: value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// Добавление элемента карты высот (высоты)
|
||||||
const handleAddHeight = (event) => {
|
const handleAddHeight = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@ -147,7 +195,7 @@ const Dashboard = () => {
|
|||||||
setHeightData((prevData) => [...prevData, newPoint]);
|
setHeightData((prevData) => [...prevData, newPoint]);
|
||||||
setFormData({ x: '', y: '', height: '' });
|
setFormData({ x: '', y: '', height: '' });
|
||||||
};
|
};
|
||||||
|
// Изменение настроек
|
||||||
const handleSettingsChange = (event) => {
|
const handleSettingsChange = (event) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
setMapSettings({
|
setMapSettings({
|
||||||
@ -155,7 +203,7 @@ const Dashboard = () => {
|
|||||||
[name]: value,
|
[name]: value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// Открытие контекстного меню
|
||||||
const handleContextMenuClick = (action) => {
|
const handleContextMenuClick = (action) => {
|
||||||
if (action === 'add') {
|
if (action === 'add') {
|
||||||
handleAddDrone();
|
handleAddDrone();
|
||||||
@ -172,37 +220,23 @@ const Dashboard = () => {
|
|||||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<a class="navbar-item">
|
<a class="navbar-item">Объекты</a>
|
||||||
Объекты
|
<a class="navbar-item">Документация</a>
|
||||||
</a>
|
<a class="navbar">
|
||||||
|
|
||||||
<a class="navbar-item">
|
|
||||||
Документация
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link">
|
<a class="navbar-link">Файл</a>
|
||||||
Файл
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
<div class="navbar-dropdown">
|
||||||
<a class="navbar-item">
|
<a class="navbar-item">Сохранить локально</a>
|
||||||
Сохранить локально
|
<a class="navbar-item is-selected">Сохранить на сервере</a>
|
||||||
</a>
|
<a class="navbar-item">Настройки клиента</a>
|
||||||
<a class="navbar-item is-selected">
|
|
||||||
Сохранить на сервере
|
|
||||||
</a>
|
|
||||||
<a class="navbar-item">
|
|
||||||
Настройки клиента
|
|
||||||
</a>
|
|
||||||
<hr class="navbar-divider"/>
|
<hr class="navbar-divider"/>
|
||||||
<a class="navbar-item">
|
<a class="navbar-item">Debug mode</a>
|
||||||
Debug mode
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
@ -215,9 +249,12 @@ const Dashboard = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p>x: {mouseState.x} y: {mouseState.y} z: {mouseState.z}</p>
|
||||||
|
</div>
|
||||||
<div ref={mountRef} style={{ width: '100%', height: '500px', position: 'relative' }} />
|
<div ref={mountRef} style={{ width: '100%', height: '500px', position: 'relative' }} />
|
||||||
|
</div>
|
||||||
{/* Контекстное меню */}
|
{/* Контекстное меню */}
|
||||||
{contextMenu.visible && (
|
{contextMenu.visible && (
|
||||||
<ul
|
<ul
|
||||||
|
11
src/frontend/src/pages/helpers/generateRandomHeightPoints.js
Normal file
11
src/frontend/src/pages/helpers/generateRandomHeightPoints.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import HeightPoint from '../model/HeightPoint';
|
||||||
|
|
||||||
|
export const RandomHeightPoint = () => {
|
||||||
|
let result = [];
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
for (let j = 0; j < 20; j++) {
|
||||||
|
result.push(new HeightPoint(i, j, Math.random() * 10 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
25
src/frontend/src/pages/model/Drone.js
Normal file
25
src/frontend/src/pages/model/Drone.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
class Drone {
|
||||||
|
constructor(name) {
|
||||||
|
this.object = new THREE.Object3D();
|
||||||
|
this.geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||||
|
this.material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
|
||||||
|
this.name = name;
|
||||||
|
const cube = new THREE.Mesh(this.geometry, this.material);
|
||||||
|
// cube.material.M = new THREE.Color(0x000000); // Инициализируем с базовым эмиссивным цветом
|
||||||
|
this.object.add(cube);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(x, y, z) {
|
||||||
|
this.object.position.set(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
getObject() {
|
||||||
|
return this.object;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Drone;
|
Loading…
Reference in New Issue
Block a user