العمل مع حالات الشخصية. تجارب الوحدة

عند تطوير لعبة على Unity ، صادفت مهمة مثيرة للاهتمام: كيفية جعل وقت طويل من العمل من الآثار السلبية أو الإيجابية على شخصية.

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

احتوت الإصدارات الأولى من هذا الخط على رموز مظلمة من جميع الحالات ، وعندما حدث التأثير ، يضيء الضوء المطلوب.

الصورة

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

  1. خطأ تام: يتم إطلاق كوروتين ثان بالتوازي مع الأول. عندما يكتمل الأول ، فإنه يعود إلى قيمه الأصلية ، أي يتم إزالة التأثير قبل أن ينهي coroutine الثاني العمل.

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

    الصورة

كلتا الطريقتين غير مقبولة لمهمتي ، لأنني بحاجة إلى تمديد مدة التأثير ، حتى أحصل على مجموع مدة كل تأثير ، بغض النظر عن عدد مرات تطبيق التأثير.

إذا خطت الشخصية على المسامير ، فإن ساقه قد تضررت بشكل مشروط ولا يمكنه الاستمرار في التحرك بنفس السرعة. لنفترض أن السرعة تنخفض بمقدار 5 ثوانٍ. إذا خطت الشخصية بعد 3 ثوانٍ على المسامير الأخرى ، فيجب تقليل السرعة بمقدار 5 ثوانٍ أخرى. أي أنه قد مرت 3 ثوانٍ ، و 2 + 5 ثوانٍ متبقية من المسامير الجديدة. يجب أن تستمر مدة التأثير 7 ثوانٍ أخرى من لحظة الهجوم على المسامير الثانية (10 في المجموع).

وبمساعدة coroutine ، لم أجد حلاً للمشكلة ، لأنه من المستحيل معرفة الوقت المتبقي حتى الانتهاء من coroutine لإضافته إلى coroutine الجديد.

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

Dictionary<string, float> statusTime = new Dictionary<string, float>(); 

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

لهذا ، أضفت ثلاث طرق.

Addstatus

أضف الحالة المطلوبة إلى القاموس ، إذا كانت هذه الحالة موجودة بالفعل في القاموس ، فأضف المدة. إذا لم يكن هناك حالة ، فإننا نحسب وقت الانتهاء ونضيفه إلى القاموس.

 private void AddStatus(string status, float duration) { if (statusTime.ContainsKey(status)) { statusTime[status] += duration; } else { float endTime = Time.timeSinceLevelLoad + duration; statusTime.Add(status, endTime); } } 

RemoveStatus

نحذف الحالة من القاموس ، واستعادة القيم الأصلية.

 private void RemoveStatus(string status) { statusTime.Remove(status); RestoreStats(status); } 

Checkstatus

إذا كانت هناك حالات في القاموس ، فإننا نتحقق لمعرفة ما إذا كان وقتهم قد انتهى.

إذا انتهت صلاحيتها ، فاحذف الحالة من القاموس. نظرًا لأن تغيير القاموس في الحلقة يجعل من المستحيل مزامنة قيم القاموس ، فإننا نلقي مفاتيح القاموس هنا في قائمة عادية.

 private void CheckStatuses() { if (statusTime.Count > 0) { float currTime = Time.timeSinceLevelLoad; List<string> statuses = new List<string>(statusTime.Keys);  foreach (string stat in statuses) { if (currTime > statusTime[stat]) { RemoveStatus(stat); } } } } 

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

بالنظر إلى المستقبل (الذي لا يزال ضبابيًا تمامًا لهذه اللعبة) ، أنا واثق أيضًا في هذا القرار في الوضع عبر الإنترنت ، حيث سيحدث التحقق من حالات اللاعب فقط للاعب المحلي الحالي ، وليس لجميع اللاعبين الفوريين.

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


All Articles