عند تطوير الألعاب التعليمية، فإن تقديم ملاحظات دقيقة وذات مغزى أمر حاسم لجذب المستخدمين. في هذه المقالة، سأشارك كيف قمنا بتنفيذ نظام حسابات جغرافية للعبة Flagle Explorer، وهي لعبة تخمين الأعلام التي تساعد المستخدمين على تعلم جغرافيا العالم من خلال ملاحظات تفاعلية.
التحدي الفني
كانت متطلباتنا الرئيسية:
- حسابات دقيقة للمسافات بين أي نقطتين على الأرض
- حسابات دقيقة للاتجاهات للإرشاد الاتجاهي
- تسجيل قرب موحد
- أداء في الوقت الحقيقي لتقديم ملاحظات فورية
تفاصيل التنفيذ
1. الهيكل الأساسي للبيانات
أولاً، قمنا بتعريف واجهة نقطة جغرافية أساسية لدينا:
export interface GeoPoint {
lat: number; // Latitude in degrees
lon: number; // Longitude in degrees
}
2. تنفيذ حساب المسافة
قمنا بتنفيذ صيغة هافرساين لحساب المسافات على الدوائر العظمى:
export function calculateDistance(point1: GeoPoint, point2: GeoPoint): number {
// Early return for identical points
if (point1.lat === point2.lat && point1.lon === point2.lon) {
return 0;
}
const R = 6371000; // Earth's radius in meters
// Convert to radians
const dLat = (point2.lat - point1.lat) * Math.PI / 180;
const dLon = (point2.lon - point1.lon) * Math.PI / 180;
const lat1 = point1.lat * Math.PI / 180;
const lat2 = point2.lat * Math.PI / 180;
// Haversine formula
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return (R * c) / 1000; // Convert to kilometers
}
نظام حساب تحمل
لقد قمنا بتطوير حساب تحمل معقد يحول الرياضيات الزاوية المعقدة إلى مؤشرات اتجاهية سهلة الاستخدام:
export function calculateOrientation(point1: GeoPoint, point2: GeoPoint): number {
if (point1.lat === point2.lat && point1.lon === point2.lon) return 0;
// Convert to radians
const lat1 = point1.lat * Math.PI / 180;
const lat2 = point2.lat * Math.PI / 180;
const dLon = (point2.lon - point1.lon) * Math.PI / 180;
// Calculate bearing
const y = Math.sin(dLon) * Math.cos(lat2);
const x = Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
let bearing = Math.atan2(y, x) * 180 / Math.PI;
return (bearing + 360) % 360;
}
4. رسم خرائط الاتجاهات السهلة الاستخدام
لجعل حسابات التحمل أكثر سهولة للمستخدمين، نقوم بتعيينها إلى رموز اتجاهية:
export function calculateOrientationEmoji(point1: GeoPoint, point2: GeoPoint): string {
const orientation = calculateOrientation(point1, point2);
// Map angles to 8-direction compass
if (orientation >= 337.5 || orientation < 22.5) return '⬆️';
if (orientation >= 22.5 && orientation < 67.5) return '↗️';
if (orientation >= 67.5 && orientation < 112.5) return '➡️';
if (orientation >= 112.5 && orientation < 157.5) return '↘️';
if (orientation >= 157.5 && orientation < 202.5) return '⬇️';
if (orientation >= 202.5 && orientation < 247.5) return '↙️';
if (orientation >= 247.5 && orientation < 292.5) return '⬅️';
return '↖️';
}
اعتبارات الأداء
- العودة المبكرة: نقوم بتنفيذ العودة المبكرة للنقاط المتطابقة لتجنب الحسابات غير الضرورية.
- التحسين الثابت: يتم حساب نصف قطر الأرض وتحويل الدرجات إلى راديان مسبقًا.
- التحكم في الدقة: يتم تقريب الأرقام إلى أماكن عشرية مناسبة لتحقيق توازن بين الدقة والأداء.
معالجة الأخطاء وحالات الحافة
تتعامل تنفيذتنا مع عدة حالات حافة:
- النقاط المتطابقة
- النقاط القطبية
- نقاط عند القطبين
- حسابات تقاطع خطوط التاريخ
استراتيجية الاختبار
لقد قمنا بتنفيذ اختبارات شاملة تشمل:
- حسابات المسافات المعروفة بين المدن الكبرى
- الحالات الحدية عند القطبين وخط التاريخ الدولي
- حسابات الاتجاه للنقاط الرئيسية والفرعية
- مؤشرات الأداء لردود الفعل الفورية
التطبيق العملي
تم نشر هذا النظام بنجاح في مستكشف العلم، حيث يُعالج آلاف الحسابات يوميًا مع:
- متوسط وقت استجابة أقل من 5 مللي ثانية
- دقة 99.99% مقارنة بالحسابات المرجعية
- لا توجد شكاوى متعلقة بالحسابات في الإنتاج
التحسينات المستقبلية
نحن نبحث في عدة تحسينات:
- تنفيذ ويب أسمبلي للحسابات المعقدة
- تخزين طرق السفر المحسوبة بشكل متكرر
- معالجة دفعية للحسابات متعددة النقاط
- التكامل مع بيانات ارتفاع التضاريس
الاستنتاج
يتطلب بناء نظام حساب جغرافي اعتبارًا دقيقًا للدقة الرياضية، وتحسين الأداء، وتجربة المستخدم. نجحت تنفيذتنا بـ TypeScript في تحقيق توازن بين هذه العوامل مع الحفاظ على قابلية قراءة الكود وصيانته.
هل ترغب في رؤية هذه الحسابات قيد التنفيذ؟ يمكنك تجربتها في Flagle Explorer ومشاهدة كيف تساعدك مؤشرات المسافة والاتجاه في التنقل عبر الجغرافيا العالمية!
مستودع الكود
التنفيذ الكامل متاح على GitHub. إليك دليل بدء سريع:
import { calculateDistance, calculateOrientationEmoji } from 'the-library/geo';
const london: GeoPoint = { lat: 51.5074, lon: -0.1278 };
const tokyo: GeoPoint = { lat: 35.6762, lon: 139.6503 };
const distance = calculateDistance(london, tokyo);
const direction = calculateOrientationEmoji(london, tokyo);
console.log(`Tokyo is ${distance}km ${direction} from London`);
لقد أثبتت هذه التنفيذة أنها قوية في الإنتاج، حيث تتعامل مع ملايين الحسابات مع الحفاظ على معايير عالية من الأداء والدقة.
Source:
https://dzone.com/articles/geographic-distance-calculator-using-typescript