مقدمة
عند تطوير لعبتي ، وصلت إلى نقطة إنشاء أول شخصيات NPC. وثار السؤال حول كيفية جعل المجلس الوطنى لنواب الشعب يرحل حول الجدار وليس "الدخول فيه".
التسلق عبر الإنترنت ، وجدت الخوارزميات التالية:
- بحث واسع (BFS ، البحث الأول)
- خوارزمية ديكسترا (ديكسترا)
- نجمة "A بعلامة النجمة"
- البحث حسب أول تطابق (البحث الأفضل أولاً)
- المؤسسة الدولية للتنمية (A مع تعميق تكراري)
- البحث السريع
وقررت أن أحاول تنفيذ A * على شبكة voxel ثلاثية الأبعاد.

وصف الخوارزمية
تبحث خطوة بخطوة في جميع المسارات المؤدية من القمة الأولية إلى الأخيرة ، حتى تعثر على الحد الأدنى. مثل جميع خوارزميات البحث المستنيرة ، ينظر أولاً إلى تلك المسارات "التي تبدو" التي تؤدي إلى الهدف. من خوارزمية الجشع ، والتي هي أيضًا خوارزمية البحث لأفضل تطابق ، يتميز عن طريق حقيقة أنه عند اختيار قمة ، فإنه يأخذ في الاعتبار ، من بين أمور أخرى ، المسار الكامل الذي سافر إليه.
تصور عمل A * على ويكيبيديا التنفيذ
نظرًا لأن الخوارزمية تحتاج إلى "نقاط" - نقاط لتحديد المسار ، نكتب بنية فئة العقدة:
رمز العقدة:public enum EMoveAction { walk, jump, fall, swim }; public class PathPoint {
صانعي فئة صغيرة: private PathPoint NewPathPoint(Vector3 point, float pathLenghtFromStart, float heuristicEstimatePathLenght, EMoveAction moveAction) { PathPoint a = new PathPoint(); a.point = point; a.pathLenghtFromStart = pathLenghtFromStart; a.heuristicEstimatePathLenght = heuristicEstimatePathLenght; a.moveAction = moveAction; return a; } private PathPoint NewPathPoint(Vector3 point, float pathLenghtFromStart, float heuristicEstimatePathLenght, EMoveAction moveAction, PathPoint ppoint) { PathPoint a = new PathPoint(); a.point = point; a.pathLenghtFromStart = pathLenghtFromStart; a.heuristicEstimatePathLenght = heuristicEstimatePathLenght; a.moveAction = moveAction; a.cameFrom = ppoint; return a; }
بعد ذلك ، سيكون هيكل إعدادات البحث عن المسار مفيدًا:
رمز إعدادات البحث عن المسار: public struct SPathFinderType {
علاوة على ذلك ، يعد "العالم" نوعًا من فئة قاعدة البيانات لتخزين المعلومات حول كتل الخريطة. يمكن تنفيذ دورك بشكل مختلف.
نتيجة وظيفة البحث عن المسار للحصول على المسار: public List<PathPoint> GetPathToTarget(Vector3 beginPoint, Vector3 targetPoint, World worldData, SPathFinderType pfType) { List<PathPoint> path = new List<PathPoint>();
كلوسبوينت
تعتمد وظيفة ClosePoint فقط على تطبيق الفئة العالمية ، فهي تضيف جميع المسارات الممكنة إلى قائمة النقاط المفتوحة منها وتزيل النقطة الحالية من هذه القائمة (تغلقها). سأعطي مثالاً عن "نقطة الختام" في الاتجاهات الأربعة الأولى.
تحذير من كومة كبيرة من التعليمات البرمجية private List<PathPoint> ClosePoint(int index, List<PathPoint> openPoints, List<PathPoint> closedPoints, World worldData, SPathFinderType pfType, Vector3 targetPoint) { List<PathPoint> newOpenPoints = openPoints; PathPoint lastPoint = openPoints[index];
التحسين
ببساطة من خلال تقسيم المسار من البداية إلى النقطة الحالية ، نقوم بتقليل عدد العقد عدة مرات ونجعلها أكثر جشعًا.
return this.heuristicEstimatePathLenght + this.pathLenghtFromStart /2;
الملخص
الإيجابيات:
- بحث سريع في المساحات المفتوحة.
- تنوع الخوارزمية
السلبيات:
- يتطلب الكثير من الذاكرة لحساب الطريق.
يظهر اللون الأخضر قائمة مفتوحة من العقد ، المسار الأحمر إلى الهدف ، العقد المغلقة الزرقاء.
المسارات المستلمة قبل التحسين: المسارات المستلمة بعد التحسين: الأدب
https://tproger.ru/articles/pathfindings/
https://ru.wikipedia.org/wiki/A*