csp-security-project / vr-controller.js
AbdulElahGwaith's picture
Upload folder using huggingface_hub
d0a2071 verified
/**
* 🎭 VR Controller - تحكم الواقع الافتراضي
* نظام متقدم للتحكم في بيئة الواقع الافتراضي لمركز القيادة الغامر
*
* المميزات:
* - تحكم كامل باليدين
* - تتبع العين (اختياري)
* - تفاعل ثلاثي الأبعاد مع التهديدات
* - واجهة صوتية غامرة
* - حفظ الجلسات
*
* @author MiniMax Agent
* @version 2025.12.10
*/
class VRController {
constructor(scene, camera, renderer) {
this.scene = scene;
this.camera = camera;
this.renderer = renderer;
this.isInitialized = false;
this.isSessionActive = false;
this.session = null;
this.referenceSpace = null;
this.controllers = [];
this.laserPointers = [];
this.currentTarget = null;
// إعدادات VR
this.config = {
sessionType: 'immersive-vr',
requiredFeatures: ['local-floor'],
optionalFeatures: ['hand-tracking', 'eye-tracking'],
maxControllers: 2,
laserPointerLength: 10,
hapticFeedback: true,
saveSessions: true
};
// محاكاة أجهزة التحكم
this.mockControllers = this.createMockControllers();
console.log('🥽 تم تهيئة VR Controller');
}
/**
* تهيئة نظام VR
*/
async initialize() {
try {
console.log('🔧 بدء تهيئة VR...');
// فحص دعم WebXR
if (!navigator.xr) {
throw new Error('WebXR غير مدعوم في هذا المتصفح');
}
// فحص دعم VR
const isVRAvailable = await navigator.xr.isSessionSupported(this.config.sessionType);
if (!isVRAvailable) {
throw new Error('VR غير متاح على هذا الجهاز');
}
// إنشاء أجهزة التحكم الافتراضية
this.createControllers();
// إعداد تتبع العين (إذا كان متاحاً)
if (this.config.optionalFeatures.includes('eye-tracking')) {
await this.initializeEyeTracking();
}
this.isInitialized = true;
console.log('✅ تم تهيئة VR بنجاح');
return true;
} catch (error) {
console.error('❌ خطأ في تهيئة VR:', error);
throw error;
}
}
/**
* إنشاء أجهزة التحكم الافتراضية
*/
createControllers() {
for (let i = 0; i < this.config.maxControllers; i++) {
const controller = {
id: `controller_${i}`,
handedness: i === 0 ? 'left' : 'right',
gamepad: {
axes: [0, 0, 0, 0],
buttons: [
{ pressed: false, value: 0 }, // Trigger
{ pressed: false, value: 0 }, // Grip
{ pressed: false, value: 0 }, // A/Primary
{ pressed: false, value: 0 }, // B/Secondary
{ pressed: false, value: 0 }, // Thumbstick
{ pressed: false, value: 0 } // Touchpad
],
hapticActuators: [
{
pulse: (intensity, duration) => {
console.log(`📳 اهتزاز جهاز التحكم ${i}: ${intensity}% لمدة ${duration}ms`);
return Promise.resolve();
}
}
]
},
connected: true,
pose: {
position: { x: 0, y: 1.5, z: 0 },
orientation: { x: 0, y: 0, z: 0, w: 1 }
}
};
this.controllers.push(controller);
this.createLaserPointer(controller);
}
}
/**
* إنشاء شعاع الليزر لجهاز التحكم
*/
createLaserPointer(controller) {
const geometry = new THREE.CylinderGeometry(0.002, 0.002, this.config.laserPointerLength, 8);
const material = new THREE.MeshBasicMaterial({
color: 0x22d3ee,
transparent: true,
opacity: 0.8,
side: THREE.DoubleSide
});
const laser = new THREE.Mesh(geometry, material);
laser.rotation.x = Math.PI / 2;
laser.visible = false;
// إضافة تأثير الإضاءة
const glowGeometry = new THREE.SphereGeometry(0.01, 8, 8);
const glowMaterial = new THREE.MeshBasicMaterial({
color: 0x22d3ee,
transparent: true,
opacity: 0.9,
blending: THREE.AdditiveBlending
});
const glow = new THREE.Mesh(glowGeometry, glowMaterial);
laser.add(glow);
this.scene.add(laser);
this.laserPointers.push({
mesh: laser,
controller: controller,
visible: false
});
}
/**
* تهيئة تتبع العين
*/
async initializeEyeTracking() {
console.log('👁️ تهيئة تتبع العين...');
try {
// محاكاة تتبع العين
this.eyeTrackingData = {
leftEye: { x: 0, y: 0, z: -1 },
rightEye: { x: 0, y: 0, z: -1 },
combinedGaze: { x: 0, y: 0, z: -1 }
};
// تحديث بيانات العين
this.updateEyeTracking();
console.log('✅ تم تهيئة تتبع العين');
} catch (error) {
console.warn('⚠️ تعذر تهيئة تتبع العين:', error);
}
}
/**
* بدء جلسة VR
*/
async startSession() {
if (!this.isInitialized) {
throw new Error('VR غير مهيأ بعد');
}
try {
console.log('🚀 بدء جلسة VR...');
// طلب جلسة VR
this.session = await navigator.xr.requestSession(this.config.sessionType, {
requiredFeatures: this.config.requiredFeatures,
optionalFeatures: this.config.optionalFeatures
});
// ربط أحداث الجلسة
this.bindSessionEvents();
// بدء تقديم المشهد
this.renderer.xr.enabled = true;
this.renderer.xr.setReferenceSpaceType('local-floor');
await this.renderer.xr.setSession(this.session);
this.isSessionActive = true;
this.startSessionLoop();
console.log('✅ تم بدء جلسة VR بنجاح');
this.emit('session_start');
} catch (error) {
console.error('❌ خطأ في بدء جلسة VR:', error);
throw error;
}
}
/**
* إنهاء جلسة VR
*/
async endSession() {
if (!this.session || !this.isSessionActive) {
return;
}
try {
console.log('🛑 إنهاء جلسة VR...');
this.isSessionActive = false;
if (this.session) {
await this.session.end();
this.session = null;
}
// إيقاف تقديم المشهد
this.renderer.xr.enabled = false;
// إخفاء شعاع الليزر
this.laserPointers.forEach(pointer => {
pointer.visible = false;
pointer.mesh.visible = false;
});
console.log('✅ تم إنهاء جلسة VR');
this.emit('session_end');
} catch (error) {
console.error('❌ خطأ في إنهاء جلسة VR:', error);
}
}
/**
* ربط أحداث الجلسة
*/
bindSessionEvents() {
this.session.addEventListener('end', () => {
this.isSessionActive = false;
this.emit('session_end');
});
this.session.addEventListener('inputsourceschange', (event) => {
this.handleInputSourcesChange(event);
});
this.session.addEventListener('selectstart', (event) => {
this.handleSelectStart(event);
});
this.session.addEventListener('selectend', (event) => {
this.handleSelectEnd(event);
});
this.session.addEventListener('squeezestart', (event) => {
this.handleSqueezeStart(event);
});
this.session.addEventListener('squeezeend', (event) => {
this.handleSqueezeEnd(event);
});
}
/**
* معالجة تغيير مصادر الإدخال
*/
handleInputSourcesChange(event) {
const { added, removed } = event;
added.forEach(inputSource => {
console.log('➕ إضافة مصدر إدخال:', inputSource.handedness);
this.handleInputSourceAdded(inputSource);
});
removed.forEach(inputSource => {
console.log('➖ إزالة مصدر إدخال:', inputSource.handedness);
this.handleInputSourceRemoved(inputSource);
});
}
/**
* معالجة إضافة مصدر إدخال
*/
handleInputSourceAdded(inputSource) {
// العثور على جهاز التحكم المطابق
const controller = this.controllers.find(c => c.handedness === inputSource.handedness);
if (controller) {
controller.inputSource = inputSource;
controller.connected = true;
}
}
/**
* معالجة إزالة مصدر إدخال
*/
handleInputSourceRemoved(inputSource) {
const controller = this.controllers.find(c => c.inputSource === inputSource);
if (controller) {
controller.inputSource = null;
controller.connected = false;
}
}
/**
* معالجة بدء الاختيار
*/
handleSelectStart(event) {
const inputSource = event.inputSource;
const controller = this.controllers.find(c => c.inputSource === inputSource);
if (controller) {
console.log('🎯 بدء الاختيار:', controller.handedness);
// تشغيل اهتزاز
if (this.config.hapticFeedback) {
this.triggerHaptic(controller, 0.5, 100);
}
// معالجة الهدف المحدد
this.handleControllerSelection(controller, event);
}
}
/**
* معالجة نهاية الاختيار
*/
handleSelectEnd(event) {
const inputSource = event.inputSource;
const controller = this.controllers.find(c => c.inputSource === inputSource);
if (controller) {
console.log('🎯 نهاية الاختيار:', controller.handedness);
this.currentTarget = null;
}
}
/**
* معالجة بدء الإمساك
*/
handleSqueezeStart(event) {
const inputSource = event.inputSource;
const controller = this.controllers.find(c => c.inputSource === inputSource);
if (controller) {
console.log('✊ بدء الإمساك:', controller.handedness);
// تشغيل اهتزاز قوي
if (this.config.hapticFeedback) {
this.triggerHaptic(controller, 0.8, 200);
}
this.emit('controller_squeeze', controller);
}
}
/**
* معالجة نهاية الإمساك
*/
handleSqueezeEnd(event) {
const inputSource = event.inputSource;
const controller = this.controllers.find(c => c.inputSource === inputSource);
if (controller) {
console.log('✊ نهاية الإمساك:', controller.handedness);
}
}
/**
* معالجة اختيار جهاز التحكم
*/
handleControllerSelection(controller, event) {
// فحص التفاعل مع الكائنات ثلاثية الأبعاد
const intersections = this.raycast(controller);
if (intersections.length > 0) {
const target = intersections[0].object;
this.currentTarget = target;
console.log('🎯 تم تحديد هدف:', target.userData);
// إرسال حدث التحديد
this.emit('controller_select', {
controller: controller,
target: target,
intersection: intersections[0]
});
// تأثير بصري
this.showSelectionEffect(target);
}
}
/**
* إجراء شعاع للجهاز التحكم
*/
raycast(controller) {
// إنشاء شعاع من جهاز التحكم
const origin = new THREE.Vector3(
controller.pose.position.x,
controller.pose.position.y,
controller.pose.position.z
);
const direction = new THREE.Vector3(0, 0, -1);
direction.applyQuaternion(new THREE.Quaternion(
controller.pose.orientation.x,
controller.pose.orientation.y,
controller.pose.orientation.z,
controller.pose.orientation.w
));
const raycaster = new THREE.Raycaster(origin, direction);
return raycaster.intersectObjects(this.scene.children, true);
}
/**
* تشغيل اهتزاز جهاز التحكم
*/
async triggerHaptic(controller, intensity = 0.5, duration = 100) {
try {
const hapticActuator = controller.gamepad?.hapticActuators?.[0];
if (hapticActuator) {
await hapticActuator.pulse(intensity, duration);
}
} catch (error) {
console.warn('تعذر تشغيل الاهتزاز:', error);
}
}
/**
* عرض تأثير التحديد
*/
showSelectionEffect(target) {
// إنشاء تأثير توهج
const glowGeometry = new THREE.SphereGeometry(0.1, 16, 16);
const glowMaterial = new THREE.MeshBasicMaterial({
color: 0x22d3ee,
transparent: true,
opacity: 0.8,
blending: THREE.AdditiveBlending
});
const glow = new THREE.Mesh(glowGeometry, glowMaterial);
glow.position.copy(target.position);
this.scene.add(glow);
// إزالة التأثير بعد ثانيتين
setTimeout(() => {
this.scene.remove(glow);
}, 2000);
}
/**
* بدء حلقة الجلسة
*/
startSessionLoop() {
const animate = () => {
if (!this.isSessionActive) return;
// تحديث أجهزة التحكم
this.updateControllers();
// تحديث شعاع الليزر
this.updateLaserPointers();
// تحديث تتبع العين
this.updateEyeTracking();
// طلب الإطار التالي
this.session.requestAnimationFrame(animate);
};
this.session.requestAnimationFrame(animate);
}
/**
* تحديث أجهزة التحكم
*/
updateControllers() {
this.controllers.forEach((controller, index) => {
if (!controller.connected) return;
// محاكاة حركة جهاز التحكم
this.simulateControllerMovement(controller);
// تحديث بيانات المحرك
this.updateControllerGamepad(controller);
});
}
/**
* محاكاة حركة جهاز التحكم
*/
simulateControllerMovement(controller) {
const time = Date.now() * 0.001;
// حركة طبيعية لليد
controller.pose.position.x = Math.sin(time * 0.5) * 0.3;
controller.pose.position.y = 1.2 + Math.sin(time * 0.8) * 0.1;
controller.pose.position.z = Math.cos(time * 0.3) * 0.2;
// توجيه الجهاز
controller.pose.orientation.x = Math.sin(time * 0.3) * 0.1;
controller.pose.orientation.y = Math.cos(time * 0.4) * 0.1;
controller.pose.orientation.z = Math.sin(time * 0.6) * 0.1;
}
/**
* تحديث بيانات المحرك
*/
updateControllerGamepad(controller) {
const time = Date.now() * 0.001;
// محاكاة حركة العصا التناظرية
controller.gamepad.axes[0] = Math.sin(time * 0.5) * 0.7; // X
controller.gamepad.axes[1] = Math.cos(time * 0.7) * 0.7; // Y
// أزرار عشوائية
controller.gamepad.buttons.forEach((button, index) => {
if (index < 2) { // Trigger and Grip
button.pressed = Math.random() > 0.95;
button.value = button.pressed ? 1 : 0;
}
});
}
/**
* تحديث شعاع الليزر
*/
updateLaserPointers() {
this.laserPointers.forEach(pointer => {
const controller = pointer.controller;
if (!controller.connected) {
pointer.mesh.visible = false;
return;
}
// تحديد موقع الجهاز
pointer.mesh.position.set(
controller.pose.position.x,
controller.pose.position.y,
controller.pose.position.z
);
// تحديد توجيه الجهاز
const quaternion = new THREE.Quaternion(
controller.pose.orientation.x,
controller.pose.orientation.y,
controller.pose.orientation.z,
controller.pose.orientation.w
);
pointer.mesh.setRotationFromQuaternion(quaternion);
// فحص التفاعل مع الأهداف
const intersections = this.raycast(controller);
if (intersections.length > 0) {
pointer.mesh.visible = true;
// تحديد نهاية الشعاع
const intersection = intersections[0];
const distance = intersection.distance;
// تحديد طول الشعاع
pointer.mesh.scale.z = distance / this.config.laserPointerLength;
// تغيير لون الشعاع عند التفاعل
pointer.mesh.material.color.setHex(0x34d399);
} else {
pointer.mesh.visible = true;
pointer.mesh.scale.z = 1;
pointer.mesh.material.color.setHex(0x22d3ee);
}
});
}
/**
* تحديث تتبع العين
*/
updateEyeTracking() {
if (!this.eyeTrackingData) return;
const time = Date.now() * 0.001;
// محاكاة حركة العين
this.eyeTrackingData.leftEye.x = Math.sin(time * 0.3) * 0.1;
this.eyeTrackingData.leftEye.y = Math.cos(time * 0.4) * 0.1;
this.eyeTrackingData.leftEye.z = -1;
this.eyeTrackingData.rightEye.x = Math.sin(time * 0.3) * 0.1;
this.eyeTrackingData.rightEye.y = Math.cos(time * 0.4) * 0.1;
this.eyeTrackingData.rightEye.z = -1;
// حساب الاتجاه المدمج
this.eyeTrackingData.combinedGaze.x = (this.eyeTrackingData.leftEye.x + this.eyeTrackingData.rightEye.x) / 2;
this.eyeTrackingData.combinedGaze.y = (this.eyeTrackingData.leftEye.y + this.eyeTrackingData.rightEye.y) / 2;
this.eyeTrackingData.combinedGaze.z = -1;
// معالجة نظرة التركيز
this.handleGazeFocus();
}
/**
* معالجة نظرة التركيز
*/
handleGazeFocus() {
// إنشاء شعاع من العين
const origin = new THREE.Vector3(0, 1.6, 0); // موقع الرأس
const direction = new THREE.Vector3(
this.eyeTrackingData.combinedGaze.x,
this.eyeTrackingData.combinedGaze.y,
this.eyeTrackingData.combinedGaze.z
);
const raycaster = new THREE.Raycaster(origin, direction);
const intersections = raycaster.intersectObjects(this.scene.children, true);
if (intersections.length > 0) {
const target = intersections[0].object;
// تأثير نظرة التركيز
if (target !== this.gazeTarget) {
this.showGazeEffect(target);
this.gazeTarget = target;
}
}
}
/**
* عرض تأثير النظر
*/
showGazeEffect(target) {
// إنشاء نقطة توهج
const gazeGeometry = new THREE.SphereGeometry(0.05, 8, 8);
const gazeMaterial = new THREE.MeshBasicMaterial({
color: 0xffd700,
transparent: true,
opacity: 0.6,
blending: THREE.AdditiveBlending
});
const gazePoint = new THREE.Mesh(gazeGeometry, gazeMaterial);
gazePoint.position.copy(target.position);
this.scene.add(gazePoint);
// إزالة التأثير بعد ثانية واحدة
setTimeout(() => {
this.scene.remove(gazePoint);
}, 1000);
}
/**
* إنشاء أجهزة تحكم وهمية للاختبار
*/
createMockControllers() {
return [
{
id: 'mock_left',
handedness: 'left',
connected: true,
buttons: {
trigger: { pressed: false, value: 0 },
grip: { pressed: false, value: 0 },
a: { pressed: false, value: 0 },
b: { pressed: false, value: 0 },
thumbstick: { pressed: false, value: 0 }
},
axes: [0, 0, 0, 0]
},
{
id: 'mock_right',
handedness: 'right',
connected: true,
buttons: {
trigger: { pressed: false, value: 0 },
grip: { pressed: false, value: 0 },
a: { pressed: false, value: 0 },
b: { pressed: false, value: 0 },
thumbstick: { pressed: false, value: 0 }
},
axes: [0, 0, 0, 0]
}
];
}
/**
* الحصول على حالة الأجهزة
*/
getControllersState() {
return this.controllers.map(controller => ({
id: controller.id,
handedness: controller.handedness,
connected: controller.connected,
position: controller.pose.position,
orientation: controller.pose.orientation,
buttons: controller.gamepad.buttons.map(btn => ({
pressed: btn.pressed,
value: btn.value
})),
axes: [...controller.gamepad.axes]
}));
}
/**
* محاكاة إدخال
*/
simulateInput(controllerId, input) {
const controller = this.controllers.find(c => c.id === controllerId);
if (!controller) return;
console.log('🎮 محاكاة إدخال:', controllerId, input);
// معالجة أنواع الإدخال المختلفة
switch (input.type) {
case 'button':
controller.gamepad.buttons[input.button].pressed = input.pressed;
controller.gamepad.buttons[input.button].value = input.value || (input.pressed ? 1 : 0);
break;
case 'axis':
controller.gamepad.axes[input.axis] = input.value;
break;
case 'position':
controller.pose.position = input.position;
break;
case 'orientation':
controller.pose.orientation = input.orientation;
break;
}
}
/**
* حفظ الجلسة
*/
saveSession() {
if (!this.config.saveSessions || !this.isSessionActive) return;
try {
const sessionData = {
timestamp: new Date().toISOString(),
controllers: this.getControllersState(),
gazeTarget: this.gazeTarget?.userData || null,
sceneState: this.captureSceneState()
};
localStorage.setItem('vrSession', JSON.stringify(sessionData));
console.log('💾 تم حفظ جلسة VR');
} catch (error) {
console.warn('تعذر حفظ الجلسة:', error);
}
}
/**
* تحميل الجلسة
*/
loadSession() {
try {
const sessionData = localStorage.getItem('vrSession');
if (!sessionData) return false;
const session = JSON.parse(sessionData);
console.log('📁 تحميل جلسة VR:', session.timestamp);
// استعادة حالة الأجهزة
session.controllers.forEach(savedController => {
const controller = this.controllers.find(c => c.id === savedController.id);
if (controller) {
controller.pose.position = savedController.position;
controller.pose.orientation = savedController.orientation;
}
});
return true;
} catch (error) {
console.warn('تعذر تحميل الجلسة:', error);
return false;
}
}
/**
* التقاط حالة المشهد
*/
captureSceneState() {
const objects = [];
this.scene.traverse((object) => {
if (object.userData.threat) {
objects.push({
id: object.userData.threat.id,
type: object.userData.threat.type,
position: object.position.toArray(),
rotation: object.rotation.toArray(),
scale: object.scale.toArray()
});
}
});
return objects;
}
/**
* نظام الأحداث
*/
emit(eventName, data) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName].forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('خطأ في مستمع الحدث:', error);
}
});
}
}
on(eventName, callback) {
if (!this.eventListeners[eventName]) {
this.eventListeners[eventName] = [];
}
this.eventListeners[eventName].push(callback);
}
off(eventName, callback) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName] = this.eventListeners[eventName].filter(cb => cb !== callback);
}
}
/**
* تدمير النظام
*/
destroy() {
console.log('🗑️ تدمير VR Controller...');
// إنهاء الجلسة النشطة
if (this.isSessionActive) {
this.endSession();
}
// تنظيف الموارد
this.laserPointers.forEach(pointer => {
this.scene.remove(pointer.mesh);
});
this.controllers = [];
this.laserPointers = [];
console.log('✅ تم تدمير VR Controller');
}
}