لعب ، ولكن تحقق: كيف يدير المحرك المصمم



عند تصميم لعبة متعددة اللاعبين ، فإن المكون الأكثر أهمية هو التوازن. يشبه عمل مصمم الألعاب في هذا الصدد عمل محلل استخبارات: إذا كان يعمل بشكل جيد ، فلن يلاحظ أحد. الأمر يستحق التعثر ، ويستغل اللاعبون بلا خجل الخطأ. ولكن الشيء الأكثر إثارة للاهتمام يحدث عندما يكون المبرمج ، بالإضافة إلى مصمم اللعبة ، مخطئًا أيضًا ...


في هذه المقالة ، سننظر في عنصر واحد من استراتيجية القوزاق 3 . تحتوي اللعبة على أنواع مختلفة من الفرسان والرماة الآخرين في القرنين السابع عشر والثامن عشر ، بالإضافة إلى فرصة لاستكشاف التقنيات التي تقلل من وقت إعادة تحميل المسكيت. هناك تحسينان في المجموع ، كل منهما يجلب + 30٪ إلى معدل إطلاق النار - وفقًا لواجهة اللعبة.


ولكن حتى من خلال الرؤية ، من الواضح أن بعض الوحدات القتالية ، بعد البحث في التحسينات ، لا تطلق النار على 60 ٪ فحسب ، بل عدة مرات أكثر. عند قياس معدل إطلاق النار مباشرة باستخدام مؤقت اللعبة المدمج ، تظهر أرقام غريبة تمامًا لا علاقة لها بالنسب المئوية المذكورة.


تحت غطاء "القوزاق"


لحسن الحظ ، تم إنشاء اللعبة بطريقة ودية للغاية للمنسقين ، لذا فإن جميع النصوص البرمجية التي نحتاجها متوفرة كملفات نصية في البيانات / النصوص / المجلد. إذا حكمنا من خلال بناء الجملة ، فإن النصوص مكتوبة بلغة دلفي أو بلغة متشابهة للغاية. دعنا نلقي نظرة على آليات حساب الفواصل الزمنية بين اللقطات.


ملاحظات
  • تم إجراء التحليل على لعبة "Cossacks 3" الإصدار 2.1.4.
  • تحتوي جميع أقسام البرنامج النصي أدناه على كود زائف مبسط.

  1. عندما تبدأ اللعبة ، تتم تهيئة جميع الوحدات القتالية. يشير الإجراء إلى قيم الحيوية والتكلفة والأسلحة لكل نوع. بالنسبة للأسلحة الصغيرة ، يتم تمرير معلمة تشير إلى الفاصل الزمني بين اللقطات في إطارات اللعبة:


    //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; 

  2. أيضًا ، في بداية اللعبة ، تتم تهيئة بيانات دول الألعاب ، بما في ذلك التحسينات المتاحة. لكل واحد منهم ، يتم الإشارة إلى متغير القيمة وتخزينه ، والذي عند دراسة هذا التحسين ، يؤثر على إعادة حساب المعلمات الضرورية للعبة:


     //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 ، فإن قرار إنهاء نتيجة إعادة الحساب يبدو غريبًا نوعًا ما ، إن لم يكن مهمًا.


  3. بعد كل طلقة ، يشار إلى التأخير قبل اللقطة التالية. يتم تطبيق معدّل id فردي . attackrate على الهياكل البرجية وفي حالتنا دائمًا 1.


     //lib/unit.script procedure _unit_ApplyAttackPause() attackdelay := weapon.pause * idividual.attackrate; 


لذلك ، بالإضافة إلى الخطأ الرياضي في الحسابات ، والذي يمكن قراءة تفاصيله تحت المفسد أدناه ، هناك تقريب غير مناسب لأرقام الفاصلة العائمة. أتساءل ما هو التأثير على آليات اللعبة لهذا الإشراف البسيط للوهلة الأولى؟


القليل من الرياضيات

يتناسب معدل إطلاق النار عكسيا مع حجم الفاصل الزمني بين اللقطات. وإذا كان عدد الجولات في الدقيقة هو ما يهم اللاعب ، فإن محرك اللعبة ، كقاعدة عامة ، يستخدم فترات لحساب الإيقاف المؤقت. الصيد هنا هو أن "تقليل الفاصل الزمني بنسبة 30٪" و "زيادة معدل إطلاق النار بنسبة 30٪" أمران مختلفان تمامًا. يتم وصف النسبة r بين الفواصل الزمنية t وعدد اللقطات n بواسطة صيغة بسيطة:

 fract1t2=r= fracn2n1


إذا أخذنا ، على سبيل المثال ، فترة 6 ثوانٍ (10 جولات في الدقيقة) وقمنا بتقليلها بنسبة 30٪ ، فلن نحصل على 13 جولة في الدقيقة:

6 space mathrms cdot0.7=4.2 space mathrms؛ quad frac6 space mathrms4.2 space mathrms حوالي1.43 neq frac1310


للحصول على القيمة المطلوبة ، يجب أن تقسم الفاصل الزمني الحالي على النسبة المطلوبة لمعدل الحريق الجديد إلى القديم:

t2= fract1r= frac6 space mathrms1.3 almost4.62 space mathrms



طريقة القياس

للحصول على القيم التي يعمل بها محرك اللعبة ، يمكنك استخدام وظائف التسجيل. للقيام بذلك ، تحتاج أولاً إلى تمكين التسجيل:


  //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+20+1+2+1+2
أنا5.004.03.012.01520+ 25٪+ 67٪
II6.885،04.08.71215+ 38٪+ 72٪
ثالثًا5.314.03.011.31520+ 33٪+ 77٪
IV5.634.03.010.71520+ 41٪+ 88٪
خامسا3.753.02.016.02030+ 25٪+ 88٪
سادسا5.944.03.010.11520+ 48٪+ 98٪
سابعا4.063.02.014.82030+ 35٪+ 103٪
ثامنا4.383.02.013.72030+ 46٪+ 119٪
تاسعا4.693.02.012.82030+ 56٪+ 134٪
X3.132.01،019.23060+ 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

Source: https://habr.com/ru/post/ar414853/


All Articles