اللعبة باستخدام مخططات الرياضيات بدلاً من المخططات



في لقطة الشاشة هذه ، يتم تقديم لعبة تبدو عادية مع رسومات بكسل. ومع ذلك ، ليس كل شيء بهذه البساطة.

يشبه ارتياح الأرض في الأماكن الجيبية ، والرصاص يشبه رسمين بيانيين متماثلين لجذر x.

في الواقع ، كل ما تراه على الشاشة بطريقة أو بأخرى يتعلق بالرياضيات والمنحنيات الرياضية والرسوم البيانية.

الخلفية


ذات مرة ، أثناء مشاهدة فيديو قناة "Numberphile" ، صادفت مادة فيديو مثيرة للاهتمام للغاية تسمى "صيغة كل شيء" .

في هذا الفيديو ، تم تقديم صيغة Tapper المرجعية الذاتية ، والتي ، مع قيمة معينة من k ، أعادت إنشاء صورتها على الرسم البياني. تبدو هذه الصيغة كما يلي:

 frac12< lfloormod( lfloor fracy17 rfloor217 lfloorx rfloormod( lfloory rfloor،17)،2) rfloor


هذه الصيغة تهمني حقًا ، وكان لدي فكرة:

"وماذا إذا قمت بإنشاء لعبة حيث سيتم استخدام الرسوم البيانية الرياضية والمنحنيات بدلاً من الأنسجة العادية المخزنة في ملفات مختلفة بتنسيق .png و .jpg؟"

بدت لي هذه الفكرة مثيرة للاهتمام وصعبة التنفيذ.

المهام


واجهت المهام التالية:

  • تعال مع معنى اللعبة ، اللعب
  • اشتق الصيغ ، والتي ستكون رسوماتها الظلية للشخصيات والرصاص والسطوح التي أحتاجها
  • تنفيذ كل هذا في اللعبة

اللعب ومعنى اللعبة


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

الصيغ وتنفيذها اللاحق في اللعبة


لقد جمعت الفقرتين التاليتين في عنوان فرعي واحد ، لأنه ليس من العملي "التخطي" بين صيغة واحدة وتنفيذها.

لإنشاء اللعبة ، تم اختيار لغة البرمجة c ++ ومكتبة SFML لإنشاء النوافذ ورسم شيء عليها.

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

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

سطح الكوكب


لسطح الكوكب ، اشتقت الصيغة التالية:

f(x)=|sin(x)|

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

int groundC = ceil(abs(sin(((i+1)*groundScale*M_PI)))*groundHeight); 

نسيج الكوكب في الفضاء






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

الرصاص




صورة رصاصة من اللعبة. تم تشغيل الرصاصة.

بالنسبة للرصاص ، تم اختيار صيغة بسيطة للغاية:

 sqrtx

تنعكس مؤامرة هذه الصيغة على الخراج.

بطل الرواية


لذلك وصلنا إلى الصيغ الأكثر تعقيدًا.

استنتجت صيغة بطل الرواية بصعوبة كبيرة. يبدو هذا:

 sqrtx frac12.8+x10.9x9.3x0.3دولا

نعم ، صيغة قبيحة جداً وقبيحة جداً. لكن الشيء الرئيسي ليس الصيغة ، النتيجة الرئيسية.

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



بعد ذلك ، كنا بحاجة إلى نسيج بطل الرواية في الفضاء. يبدو هذا:



كانت قائمة على شكل دائرة. المقصورة الرئيسية مصنوعة باستخدام الصيغة التالية:

(x7x) frac0.8x

يتم عكس الرسم البياني لهذه الصيغة على طول المحور الإحداثي.

هذه هي الطريقة التي تبدو بها هذه الصيغة في c ++:

 int x = round(pow(pow(i, 7 - i), 0.8 / i)); 

الأعداء وبيضهم



على اليمين في الصورة يوجد بيض أزرق ، والأجسام الحمراء هي أعداء.

سبونر هو كوكب عادي بنمط غير عادي. هذا النمط هو رسم بياني للصيغة:

sin(x)x0.8


صيغة نسيج العدو:

(x3x) frac1x



الأشجار


أعترف ، لم أتمكن من اشتقاق أو تحديد صيغة لإنشاء صورة ظلية للأشجار. ولكن ، لكي لا تنتهك المفهوم الأساسي للعبة بأكملها وقواعد عدم استخدام أي ملفات بتنسيق .png و .jpg ، استخدمت خدعة واحدة. استخدمت فركتلات لإنشاء الأشجار.


مثال شجرة كسورية

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

بالطبع ، يمكن للمرء أن يصنع آلة زائفة عادية ، والتي كانت تعتمد على علامات الكمبيوتر ، لكن الفكرة التالية بدت لي أكثر إثارة للاهتمام:

"وماذا لو أعطيت كل شجرة رقمًا محددًا (بذرة) يتم من خلاله حساب الأرقام العشوائية الزائفة التي تؤثر على معلمات الشجرة؟"

لحسن الحظ ، يحتوي c ++ على مكتبة زائفة منفصلة.

ونتيجة لذلك ، تبدو الأشجار المتولدة كما يلي:



على اليسار توجد شجرة بذرة 13 ، وعلى اليمين - 22

والرمز الذي يولد هذه الأشجار هو:

 Branch Branch::createNewBranch(Branch cur, Tree* parent, float angleMultiplier, int level) { Vector2f sp(cur.startPoint.x, cur.startPoint.y); float randomAngle = ((*parent).getRand() * 15) - 5; float t = cur.thickness * 0.75; float l = cur.length * 0.67; float a = cur.angle + 30*angleMultiplier + randomAngle; sp.y -= (cos((cur.angle-180)*3.1415926 / 180) * cur.length); sp.x += (sin((cur.angle-180)*3.1415926 / 180) * cur.length); Branch gen(sp, t, l, a, level); if (level > 0) { int count = 100 * (*parent).getRand(); if (count >= 25 && count < 80) { //     ,      && count < 80,        ,  . , -          20%  10%,  ,    count<90 (*parent).addBranch(gen.createNewBranch(gen, parent, 1, level - 1)); (*parent).addBranch(gen.createNewBranch(gen, parent, -1, level - 1)); } if (count >= 80) { //    ,    count >= 90 if (count % 2 == 0) { (*parent).addBranch(gen.createNewBranch(gen, parent, -1, level - 1)); } else { (*parent).addBranch(gen.createNewBranch(gen, parent, 1, level - 1)); } } } return gen; } 

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

المزيد من التعليمات البرمجية


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

لاعب


يحتوي المشغل على طريقتين مختلفتين للتحديث - spaceUpdate و planetUpdate. وفقًا لذلك ، يحدِّث spaceUpdate المشغل عندما يكون في الفضاء ، ويحدث في planetUpdate - عندما يكون على الكوكب. يتم حساب تسارع اللاعب وسرعته على هذا الكوكب. اعتمادًا على التسارع الأفقي ، تتغير زاوية ميل اللوحة من 30 درجة إلى -30. عند الاقتراب من الحواجز ، تقل سرعة اللاعب. توجد مثل هذه الحواجز للمحور x (0؛ mapSize.x) والمحور y. بالنسبة للمحور y ، تكون الأمور أكثر تعقيدًا. هناك حد أدنى للارتفاع يتم حسابه على النحو التالي: يؤخذ الحد الأدنى لارتفاع الأرض ، ويضاف إلى ارتفاع الموجة الجيبية ويضاف ارتفاع الأشجار. يتم حساب ارتفاع الأشجار بطريقة بسيطة جدًا - الطول الأولي للفرع مضروبًا في عدد الدورات التي يتم إجراؤها أثناء تكوين الشجرة. لا توجد حدود عليا - تحلق خارج الخريطة من الأعلى ، يتحول اللاعب إلى spaceUpdate ويتم رسم الفضاء.

يعمل SpaceUpdate على النحو التالي: يتم حساب تسريع اللاعب وسرعته. بعد ذلك ، يتم حساب زاوية دوران اللاعب. يتم احتساب الزاوية على النحو التالي: إذا كان التسارع صفرًا ، فسيتم حساب الزاوية بالنسبة لسرعة اللاعب ، إن لم يكن ، بالنسبة إلى التسارع. أيضا ، في الفضاء ، اللاعب لديه إمكانية إطلاق النار. يحدث التصوير على النحو التالي - يتم إنشاء رصاصة بدورة مثل لاعب وإضافتها إلى القائمة. عند تحديث لاعب في الفضاء ، يتم أيضًا تحديث كل رمز نقطي في هذه القائمة. عند تقديم لاعب ، يتم رسم الرصاص أيضًا. أيضا ، في الفضاء ، الأمور أكثر تعقيدا مع الحواجز. المساحة مقسمة إلى قطاعات ، في كل قطاع 4 كواكب ، في المجموع - 1 000 000 كوكب و 25000 قطاع. لكل قطاع معرف فريد. إذا كان الباقي عند القسمة على 500 يساوي 0 - هناك حاجز أيسر ، إذا كان الباقي من 499 صحيحًا ، إذا كانت النتيجة عند القسمة على 0 - يكون الحاجز العلوي موجودًا ، إذا كان 499 هو الحاجز العلوي. إذا لم تكن هناك حواجز ، فعندما يتحرك اللاعب خارج الإطار ، ينتقل اللاعب إلى القطاع المقابل.

الفضاء


لقد أوجزت معظمها بالفعل ، ولكن لا تزال هناك بعض الأشياء المتبقية. في كل من قطاعات الفضاء هناك 4 كواكب. عندما يضغط اللاعب على المفتاح E ، إذا كان بعيدًا عن هذا الكوكب ، ينتقل اللاعب إلى هذا الكوكب.

الأعداء


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

مبيض


يوجد في كل قطاع من الفضاء مبايض واحد. يمكن أن يكون سباونرز بأحجام مختلفة. يؤثر الحجم على رؤية اللاعب. إذا كان اللاعب في منطقة الرؤية الخاصة به ، يقوم المُفرز بإنشاء أعداء كل 5 ثوانٍ ، لكن عدد الأعداء لا يمكن أن يتجاوز 10.

الخلاصة


بعد قضاء حوالي أسبوع ، أنشأت لعبة لا تستخدم أي ملفات .png أو .jpg.

رابط للمشروع على جيثب

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

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


All Articles