
عند تصميم لعبة متعددة اللاعبين ، فإن المكون الأكثر أهمية هو التوازن. يشبه عمل مصمم الألعاب في هذا الصدد عمل محلل استخبارات: إذا كان يعمل بشكل جيد ، فلن يلاحظ أحد. الأمر يستحق التعثر ، ويستغل اللاعبون بلا خجل الخطأ. ولكن الشيء الأكثر إثارة للاهتمام يحدث عندما يكون المبرمج ، بالإضافة إلى مصمم اللعبة ، مخطئًا أيضًا ...
في هذه المقالة ، سننظر في عنصر واحد من استراتيجية القوزاق 3 . تحتوي اللعبة على أنواع مختلفة من الفرسان والرماة الآخرين في القرنين السابع عشر والثامن عشر ، بالإضافة إلى فرصة لاستكشاف التقنيات التي تقلل من وقت إعادة تحميل المسكيت. هناك تحسينان في المجموع ، كل منهما يجلب + 30٪ إلى معدل إطلاق النار - وفقًا لواجهة اللعبة.
ولكن حتى من خلال الرؤية ، من الواضح أن بعض الوحدات القتالية ، بعد البحث في التحسينات ، لا تطلق النار على 60 ٪ فحسب ، بل عدة مرات أكثر. عند قياس معدل إطلاق النار مباشرة باستخدام مؤقت اللعبة المدمج ، تظهر أرقام غريبة تمامًا لا علاقة لها بالنسب المئوية المذكورة.
تحت غطاء "القوزاق"
لحسن الحظ ، تم إنشاء اللعبة بطريقة ودية للغاية للمنسقين ، لذا فإن جميع النصوص البرمجية التي نحتاجها متوفرة كملفات نصية في البيانات / النصوص / المجلد. إذا حكمنا من خلال بناء الجملة ، فإن النصوص مكتوبة بلغة دلفي أو بلغة متشابهة للغاية. دعنا نلقي نظرة على آليات حساب الفواصل الزمنية بين اللقطات.
ملاحظات- تم إجراء التحليل على لعبة "Cossacks 3" الإصدار 2.1.4.
- تحتوي جميع أقسام البرنامج النصي أدناه على كود زائف مبسط.
عندما تبدأ اللعبة ، تتم تهيئة جميع الوحدات القتالية. يشير الإجراء إلى قيم الحيوية والتكلفة والأسلحة لكل نوع. بالنسبة للأسلحة الصغيرة ، يتم تمرير معلمة تشير إلى الفاصل الزمني بين اللقطات في إطارات اللعبة:
//lib/unit.script procedure _unit_InitBase() 'musketeer' : maxhp := 70; SetObjBaseWeapon( x,x,x,x, 150, ... ); SetObjBasePrice( ... ); //lib/unit.script procedure SetObjBaseWeapon( x,x,x,x, pause, ... ) weapon.pause := _misc_FramesToTime( pause );
إذا حكمنا من خلال التعليقات ، فإن وحدة الوقت "إطار اللعبة" هي مبتذلة من "القوزاق" الأول ، والتي تم نسخ عملية اللعبة عند إنشاء الجزء الثالث. ومع ذلك ، يتم إعادة سرد الإطارات على الفور في ثوان اللعبة بنسبة 1:32 ، ولم نعد نواجهها بعد الآن:
//lib/misc.script function _misc_FramesToTime( val ) Result := ( val * gc_frames_to_time ); //dmscript.global gc_frames_to_time := 0.03125; gc_time_to_frames := 32;
أيضًا ، في بداية اللعبة ، تتم تهيئة بيانات دول الألعاب ، بما في ذلك التحسينات المتاحة. لكل واحد منهم ، يتم الإشارة إلى متغير القيمة وتخزينه ، والذي عند دراسة هذا التحسين ، يؤثر على إعادة حساب المعلمات الضرورية للعبة:
//lib/country.script procedure _country_Init() _country_AddUpgrade( x,x,x,x, type_attpauseperc, -30, ... ); procedure _country_AddUpgrade( x,x,x,x, upgrade_type, value, ... );
في حالتنا ، هذا يعني أن فترات الوحدات العسكرية بعد كل تحسن مضروبة بـ 0.7 ثم ... يتم تقريبها؟!
//lib/player.script procedure _player_ApplyUpgrade() type_attpauseperc : weapon.pause := Round( weapon.pause * (1 + value/100) );
بالنظر إلى حقيقة أن فترات الرماة في البداية هي أرقام نقاط عائمة في النطاق من 3.125 إلى 5.0 ، فإن قرار إنهاء نتيجة إعادة الحساب يبدو غريبًا نوعًا ما ، إن لم يكن مهمًا.
بعد كل طلقة ، يشار إلى التأخير قبل اللقطة التالية. يتم تطبيق معدّل id فردي . attackrate على الهياكل البرجية وفي حالتنا دائمًا 1.
لذلك ، بالإضافة إلى الخطأ الرياضي في الحسابات ، والذي يمكن قراءة تفاصيله تحت المفسد أدناه ، هناك تقريب غير مناسب لأرقام الفاصلة العائمة. أتساءل ما هو التأثير على آليات اللعبة لهذا الإشراف البسيط للوهلة الأولى؟
القليل من الرياضياتيتناسب معدل إطلاق النار عكسيا مع حجم الفاصل الزمني بين اللقطات. وإذا كان عدد الجولات في الدقيقة هو ما يهم اللاعب ، فإن محرك اللعبة ، كقاعدة عامة ، يستخدم فترات لحساب الإيقاف المؤقت. الصيد هنا هو أن "تقليل الفاصل الزمني بنسبة 30٪" و "زيادة معدل إطلاق النار بنسبة 30٪" أمران مختلفان تمامًا. يتم وصف النسبة r بين الفواصل الزمنية t وعدد اللقطات n بواسطة صيغة بسيطة:
إذا أخذنا ، على سبيل المثال ، فترة 6 ثوانٍ (10 جولات في الدقيقة) وقمنا بتقليلها بنسبة 30٪ ، فلن نحصل على 13 جولة في الدقيقة:
للحصول على القيمة المطلوبة ، يجب أن تقسم الفاصل الزمني الحالي على النسبة المطلوبة لمعدل الحريق الجديد إلى القديم:
طريقة القياسللحصول على القيم التي يعمل بها محرك اللعبة ، يمكنك استخدام وظائف التسجيل. للقيام بذلك ، تحتاج أولاً إلى تمكين التسجيل:
//cossacks.ini & editor.ini LogFileEnabled = true LogFileRoot = true
ثم أضف في نهاية إجراء _unit_ApplyAttackPause () استدعاء دالة Log () :
//data/scripts/lib/unit.script procedure _unit_ApplyAttackPause(const goHnd, weapind : Integer); begin //... if (attpause<>0) then Log(TObjProp(pobjprop).sid+' '+FloatToStr(attpause)); end;
الآن يمكنك اللعب مع العديد من الأسهم والتحسينات في محرر الخرائط (لتمكين وضع الهجوم ، اضغط على Ctrl + W ). ستتم كتابة البروتوكول إلى ملف نصي في مجلد / log . بعد كل طلقة ، سيتم تسجيل معرف الوحدة القتالية وقيمة فاصلها الحالي.
من هو من
في البداية ، تميز نصوص اللعبة بين 35 نوعًا من الرماة (لا تشمل المرتزقة الذين لم يتأثروا بالتحسينات). إذا قمنا بتجميعها جميعًا حسب حجم الفاصل الزمني ، فيمكننا تمييز عشر فئات. قررت تصنيفها حسب الزيادة النسبية في معدل إطلاق النار من أجل تحديد أولئك الذين يطلقون النار الذين يستفيدون أكثر من التحسينات. لذا ، نتائج التحليل:
| الفاصل الزمني للهجوم | لقطات / دقيقة | معدل النار |
الفئة التحسينات | 0 | +1 | +2 | 0 | +1 | +2 | +1 | +2 |
أنا | 5.00 | 4.0 | 3.0 | 12.0 | 15 | 20 | + 25٪ | + 67٪ |
II | 6.88 | 5،0 | 4.0 | 8.7 | 12 | 15 | + 38٪ | + 72٪ |
ثالثًا | 5.31 | 4.0 | 3.0 | 11.3 | 15 | 20 | + 33٪ | + 77٪ |
IV | 5.63 | 4.0 | 3.0 | 10.7 | 15 | 20 | + 41٪ | + 88٪ |
خامسا | 3.75 | 3.0 | 2.0 | 16.0 | 20 | 30 | + 25٪ | + 88٪ |
سادسا | 5.94 | 4.0 | 3.0 | 10.1 | 15 | 20 | + 48٪ | + 98٪ |
سابعا | 4.06 | 3.0 | 2.0 | 14.8 | 20 | 30 | + 35٪ | + 103٪ |
ثامنا | 4.38 | 3.0 | 2.0 | 13.7 | 20 | 30 | + 46٪ | + 119٪ |
تاسعا | 4.69 | 3.0 | 2.0 | 12.8 | 20 | 30 | + 56٪ | + 134٪ |
X | 3.13 | 2.0 | 1،0 | 19.2 | 30 | 60 | + 56٪ | + 213٪ |
في الرسم البياني أدناه ، تتوافق الأعمدة مع الفئات من الأول إلى العاشر من اليسار إلى اليمين. يتوافق آخر عمود متقطع من الرسم البياني مع معدل الزيادة المعلن عنها في واجهة اللعبة. تظهر مجموعة الأعمدة اليسرى زيادة في معدل إطلاق النار بعد تحسن واحد ، اليمين - بعد كليهما. 
قائمة الفئات والوحداتتحتوي اللعبة على دول مختلفة - 17 أوروبية وأربع فريدة (أوكرانيا وتركيا والجزائر واسكتلندا). الفصائل الأوروبية متشابهة للغاية منذ البداية ولديها الفرسان والفرسان في القرنين السابع عشر والثامن عشر ، وكذلك الغريناديون. لكن في بعض الأحيان تختلف سهام بعض الدول عن النموذج ، أو يتم استبدالها تمامًا بنوع فريد.
الفئة | الوحدات القتالية |
---|
أنا | الفرسان القرن السابع عشر (النمسا) Szekej (هنغاريا) مطلق النار الاسكتلندي (إنجلترا) الكومنولث البولندي الليتواني (بولندا) دراغون القرن الثامن عشر (هولندا وبييمونتي) |
II | هانتسمان (سويسرا) الفارس الملكي (فرنسا) |
ثالثًا | غرينادير (أوروبا باستثناء الدنمارك وبروسيا) دراغون القرن الثامن عشر (أوروبا باستثناء فرنسا وهولندا وبييمونتي) سلاح الفرسان الخفيف (بلدان مختلفة) |
IV | دراغون القرن السابع عشر (أوروبا) |
خامسا | الفرسان القرن السابع عشر (هولندا) |
سادسا | الفرسان القرن السابع عشر (إسبانيا) الفرسان القرن الثامن عشر (بافاريا والدنمارك) غرينادير (الدانمرك) متطوع (البرتغال) هانتسمان (فرنسا) |
سابعا | سيرديوك (أوكرانيا) |
ثامنا | الفرسان القرن الثامن عشر (ساكسونيا) غرينادير (بروسيا) |
تاسعا | الفرسان القرن السابع عشر (أوروبا باستثناء النمسا وبولندا وهولندا وإسبانيا) ميثاق الفرسان (اسكتلندا) القوس (روسيا) جانيسار (تركيا) الفرسان القرن الثامن عشر (أوروبا باستثناء الدنمارك وبافاريا وساكسونيا) باندور (النمسا) دراغون القرن الثامن عشر (فرنسا) |
X | الفرسان القرن السابع عشر (بولندا) حاجدوك (هنغاريا) |
ملاحظات:
- يتم نسخ أسماء الوحدات العسكرية من الواجهة الروسية للعبة.
- السهام المائلة في القرن الثامن عشر مائلة .
- يتم تمييز سهام الحصان بالخط العريض .
اتضح أن الفارس البولندي في القرن السابع عشر والخطف الهنغاري يفوزان بأكبر عدد من التحسينات في معدل إطلاق النار: بدلاً من الموعود + 60 ٪ ، يطلقون النار أكثر من ثلاث مرات في كثير من الأحيان. نظرًا للقيمة الأولية المنخفضة للفاصل الزمني ، فإنهم يطلقون النار في نهاية المطاف بشكل أسرع من جميع الرماة الآخرين مرتين أو ثلاث أو حتى أربع مرات.
من بين سلاح الفرسان ، من الأفضل تسوية الفرسان الفرنسيين في القرن الثامن عشر: يتلقون معدل إطلاق نار أكثر من الضعف. ونتيجة لذلك ، يطلقون طلقات أكثر بنسبة 50٪ في الدقيقة من نظرائهم من الدول الأوروبية الأخرى.
بطبيعة الحال ، لا يؤخذ في الاعتبار تلف الطلقة أو الضرر في الثانية هنا ، ولكن حتى بدون هذه البيانات ، من الواضح أن الوحدات العسكرية لا تتصرف على النحو المنشود.
كيفية الإصلاحالحل الأسرع وغير الجائر للمشكلة هو إعادة كتابة صيغة تطبيق التحسين. بالإضافة إلى رفض التقريب ، بدلاً من ضرب الفاصل في 0.3 ، اقسمه على 1.3. للقيام بذلك ، ما عليك سوى استبدال الصيغة بإجراء تحسين gc_upg_type_attpauseperc بـ
//lib/player.script Round(weapon.pause*(1+value/100));
على
weapon.pause/(1+(-value)/100);
نظرًا لأن التحسينات يتم تطبيقها باستمرار ، في النهاية ، بدلاً من النسبة المعلنة + 60٪ ، نحصل على + 69٪. لكنها لا تزال أفضل من + 213٪.
خاتمة
من أجل تحديد الحسابات الخاطئة بشكل موثوق في التوازن في هذه الحالة ، يجب تحليل جانبين آخرين من آليات اللعبة - تلف الرماة والقيمة الاقتصادية إلى جانب الوقت اللازم لإنشاء وحدة قتالية. ومع ذلك ، يخبرك الفطرة السليمة بانتظار التحديث التالي أولاً ...
لقد استوعبت فكرة الدراسة من الفيديو " لماذا غالبًا ما تكون معدلات الهجوم في AoE2 خاطئة " ، والتي تتناول مشكلة مماثلة في استراتيجية Age of Empires II .
UPD: تم تصحيح الخطأ جزئيًا
لم يمر حتى أسبوع منذ نشر المقال ، حيث قام المطورون في التحديث 2.2.1 بإصلاح الخطأ في التقريب. في نفس الوقت ، بقيت الصيغة نفسها كما هي - معدل النار ينمو بنسبة 43 ٪ لكل ترقية. نظرًا لأن الحساب تزايدي ، فبعد فحص كل من التحسينات ، تعمل جميع الأسهم بشكل أسرع بنسبة 104٪.
طاولةمعدل وحدات النار في اللقطات في الدقيقة بعد البحث في كلا التحسينين ، بترتيب متزايد:
الوحدات القتالية | طلقات |
---|
هانتسمان (سويسرا) الفارس الملكي (فرنسا) | 17.8 |
الفرسان القرن السابع عشر (إسبانيا) الفرسان القرن الثامن عشر (بافاريا والدنمارك) غرينادير (الدانمرك) متطوع (البرتغال) هانتسمان (فرنسا) | 20.6 |
دراغون القرن السابع عشر (أوروبا) | 21.8 |
غرينادير (أوروبا باستثناء الدنمارك وبروسيا) دراغون القرن الثامن عشر (أوروبا باستثناء فرنسا وهولندا وبييمونتي) سلاح الفرسان الخفيف (بلدان مختلفة) | 23.0 |
الفرسان القرن السابع عشر (النمسا) Szekej (هنغاريا) مطلق النار الاسكتلندي (إنجلترا) الكومنولث البولندي الليتواني (بولندا) دراغون القرن الثامن عشر (هولندا وبييمونتي) | 24.5 |
الفرسان القرن السابع عشر (أوروبا باستثناء النمسا وبولندا وهولندا وإسبانيا) ميثاق الفرسان (اسكتلندا) القوس (روسيا) جانيسار (تركيا) الفرسان القرن الثامن عشر (أوروبا باستثناء الدنمارك وبافاريا وساكسونيا) باندور (النمسا) دراغون القرن الثامن عشر (فرنسا) | 26.1 |
الفرسان القرن الثامن عشر (ساكسونيا) غرينادير (بروسيا) | 28.0 |
سيرديوك (أوكرانيا) | 30.1 |
الفرسان القرن السابع عشر (هولندا) | 32،7 |
الفرسان القرن السابع عشر (بولندا) حاجدوك (هنغاريا) | 39،2 |