player attribute
This commit is contained in:
parent
fb55999d47
commit
d249b1cf62
@ -1,4 +1,12 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
"use client";
|
||||||
|
import { Canvas } from '@react-three/fiber';
|
||||||
|
import { OrbitControls, useGLTF, Line, Text } from '@react-three/drei';
|
||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import { Drone, BaseStation } from '../Threejs/Models';
|
||||||
|
import { PlayCircleIcon } from '@heroicons/react/24/outline';
|
||||||
|
import FormComponent from '../ObjectProps/FormComponent';
|
||||||
|
import Modal from '../Modal/Modal';
|
||||||
|
|
||||||
|
|
||||||
interface Player {
|
interface Player {
|
||||||
Click: () => void; // клик по кнопке
|
Click: () => void; // клик по кнопке
|
||||||
@ -59,7 +67,8 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate }
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-slate-600 p-4 rounded-md w-full max-w-md mx-auto">
|
<div className="bg-slate-600 p-4 rounded-md w-full max-w-5xl mx-auto">
|
||||||
|
<PlayerTsInstance/>
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<a href='/pages/simulations'
|
<a href='/pages/simulations'
|
||||||
className={`text-white p-2 rounded-md bg-green-600`}
|
className={`text-white p-2 rounded-md bg-green-600`}
|
||||||
@ -119,5 +128,198 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate }
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
interface IPlayerTsInstance {
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlayerTsInstance : React.FC<IPlayerTsInstance> = () => {
|
||||||
|
const [drones, setDrones] = useState<Drone[]>([]);
|
||||||
|
const [baseStations, setBaseStations] = useState<BaseStation[]>([]);
|
||||||
|
const [selectedObject, setSelectedObject] = useState<{ type: 'drone' | 'baseStation'; id: number } | null>(null);
|
||||||
|
const orbitControlsRef = useRef<any>(null); // Reference to OrbitControls
|
||||||
|
|
||||||
|
const addDrone = (drone?: Drone) => {
|
||||||
|
setDrones((prev) => [
|
||||||
|
...prev,
|
||||||
|
drone || {
|
||||||
|
id: prev.length,
|
||||||
|
name: `Drone ${prev.length + 1}`,
|
||||||
|
position: [Math.random() * 10, 5, Math.random() * 10],
|
||||||
|
frequency: Math.random() * 100 + 400, // Example frequency range between 400-500
|
||||||
|
signalRadius: Math.random() * 5 + 5, // Example signal radius between 5-10
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addBaseStation = (baseStation?: BaseStation) => {
|
||||||
|
setBaseStations((prev) => [
|
||||||
|
...prev,
|
||||||
|
baseStation || {
|
||||||
|
id: prev.length,
|
||||||
|
name: `Base Station ${prev.length + 1}`,
|
||||||
|
position: [Math.random() * 10, -1, Math.random() * 10],
|
||||||
|
frequency: Math.random() * 100 + 400, // Example frequency range between 400-500
|
||||||
|
signalRadius: Math.random() * 5 + 5, // Example signal radius between 5-10
|
||||||
|
antennaDirection: [0, 1, 0],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleObjectClick = (type: 'drone' | 'baseStation', id: number) => {
|
||||||
|
setSelectedObject({ type, id });
|
||||||
|
focusOnObject(type, id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusOnObject = (type: 'drone' | 'baseStation', id: number) => {
|
||||||
|
const object = type === 'drone' ? drones.find((d) => d.id === id) : baseStations.find((b) => b.id === id);
|
||||||
|
if (object && orbitControlsRef.current) {
|
||||||
|
orbitControlsRef.current.target.set(...object.position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectNextObject = (direction: 'next' | 'prev') => {
|
||||||
|
if (!selectedObject) return;
|
||||||
|
|
||||||
|
const currentList = selectedObject.type === 'drone' ? drones : baseStations;
|
||||||
|
const currentIndex = currentList.findIndex((obj) => obj.id === selectedObject.id);
|
||||||
|
const newIndex = direction === 'next'
|
||||||
|
? (currentIndex + 1) % currentList.length
|
||||||
|
: (currentIndex - 1 + currentList.length) % currentList.length;
|
||||||
|
setSelectedObject({ type: selectedObject.type, id: currentList[newIndex].id });
|
||||||
|
focusOnObject(selectedObject.type, currentList[newIndex].id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-20'>
|
||||||
|
<div style={{ height: '550px' }} />
|
||||||
|
<div className='border border-blue-500 bg-blue-500 flex justify-center items-start'>
|
||||||
|
<Canvas
|
||||||
|
style={{ height: '550px', width: '1100px' }}
|
||||||
|
shadows
|
||||||
|
>
|
||||||
|
<ambientLight intensity={0.5} />
|
||||||
|
<directionalLight position={[5, 10, 5]} intensity={1} castShadow />
|
||||||
|
<pointLight position={[10, 10, 10]} intensity={0.8} />
|
||||||
|
<spotLight position={[-10, 15, 10]} angle={0.3} intensity={0.7} castShadow />
|
||||||
|
<OrbitControls ref={orbitControlsRef} />
|
||||||
|
<MapModel />
|
||||||
|
{baseStations.map((baseStation) => (
|
||||||
|
<BaseStationModel
|
||||||
|
key={baseStation.id}
|
||||||
|
onClick={() => handleObjectClick('baseStation', baseStation.id)}
|
||||||
|
isSelected={selectedObject?.type === 'baseStation' && selectedObject.id === baseStation.id}
|
||||||
|
position={baseStation.position}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{drones.map((drone) => (
|
||||||
|
<DroneModel
|
||||||
|
key={drone.id}
|
||||||
|
position={drone.position}
|
||||||
|
droneName={drone.name}
|
||||||
|
onClick={() => handleObjectClick('drone', drone.id)}
|
||||||
|
isSelected={selectedObject?.type === 'drone' && selectedObject.id === drone.id}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{drones.flatMap((drone) => (
|
||||||
|
baseStations.map((baseStation) => {
|
||||||
|
const distance = Math.sqrt(
|
||||||
|
Math.pow(drone.position[0] - baseStation.position[0], 2) +
|
||||||
|
Math.pow(drone.position[1] - baseStation.position[1], 2) +
|
||||||
|
Math.pow(drone.position[2] - baseStation.position[2], 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance <= drone.signalRadius && distance <= baseStation.signalRadius) {
|
||||||
|
return (
|
||||||
|
<Line
|
||||||
|
key={`link-${drone.id}-${baseStation.id}`}
|
||||||
|
points={[drone.position, baseStation.position]}
|
||||||
|
color="yellow"
|
||||||
|
lineWidth={Math.min(drone.frequency, baseStation.frequency) / 200} // Adjust line width based on frequency
|
||||||
|
dashed={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
))}
|
||||||
|
{baseStations.map((baseStation) => (
|
||||||
|
baseStation.signalRadius > 0 && (
|
||||||
|
<mesh key={`signal-${baseStation.id}`} position={baseStation.position}>
|
||||||
|
<sphereGeometry args={[baseStation.signalRadius, 32, 32]} />
|
||||||
|
<meshBasicMaterial color="red" opacity={0.3} transparent />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
{drones.map((drone) => (
|
||||||
|
drone.signalRadius > 0 && (
|
||||||
|
<mesh key={`signal-${drone.id}`} position={drone.position}>
|
||||||
|
<sphereGeometry args={[drone.signalRadius, 32, 32]} />
|
||||||
|
<meshBasicMaterial color="green" opacity={0.3} transparent />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='col-auto row-auto m-auto items-center'>
|
||||||
|
<button onClick={() => selectNextObject('prev')} className="p-2 m-2 bg-yellow-500 text-white rounded transition duration-300 ease-in-out transform hover:scale-105 focus:scale-95"><</button>
|
||||||
|
<button onClick={() => selectNextObject('next')} className="p-2 m-2 bg-yellow-500 text-white rounded transition duration-300 ease-in-out transform hover:scale-105 focus:scale-95">></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Модель карты
|
||||||
|
const MapModel = () => {
|
||||||
|
const { scene } = useGLTF('/map/map.glb');
|
||||||
|
return <primitive object={scene} scale={[2, 2, 2]} />;
|
||||||
|
};
|
||||||
|
// Модель дрона
|
||||||
|
const DroneModel = ({ position, droneName, onClick, isSelected }: { position: [number, number, number]; droneName?: string; onClick: () => void; isSelected: boolean }) => {
|
||||||
|
const { scene } = useGLTF('/objects/drone.glb');
|
||||||
|
return (
|
||||||
|
<group onClick={onClick}>
|
||||||
|
<primitive object={scene} position={[position[0] + 0.8, position[1], position[2] - 0.5]} scale={[0.1, 0.1, 0.1]} />
|
||||||
|
{/* Добавляем текстовую подпись над дроном */}
|
||||||
|
<Text
|
||||||
|
position={[position[0], position[1] + 10, position[2]]} // Позиционируем текст над дроном
|
||||||
|
fontSize={1}
|
||||||
|
color="white" // Цвет текста
|
||||||
|
anchorX="center" // Центровка текста по X
|
||||||
|
anchorY="middle" // Центровка текста по Y
|
||||||
|
>
|
||||||
|
{droneName}
|
||||||
|
</Text>
|
||||||
|
{isSelected && (
|
||||||
|
<mesh position={position}>
|
||||||
|
<sphereGeometry args={[1, 16, 16]} />
|
||||||
|
<meshBasicMaterial color="red" wireframe />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
// Модель базовой станции
|
||||||
|
const BaseStationModel = ({ position, onClick, isSelected }: { position: [number, number, number]; onClick: () => void; isSelected: boolean }) => {
|
||||||
|
const { scene } = useGLTF('/objects/bs.glb');
|
||||||
|
return (
|
||||||
|
<group onClick={onClick}>
|
||||||
|
<primitive object={scene} position={position} scale={[0.7, 0.7, 0.7]} />
|
||||||
|
{isSelected && (
|
||||||
|
<mesh position={position}>
|
||||||
|
<sphereGeometry args={[0.5, 10, 10]} />
|
||||||
|
<meshBasicMaterial color="red" wireframe />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export default InitPlayer;
|
export default InitPlayer;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user