Godot ، 1000 شيء صغير

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





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



"خارج الصندوق" في المحرك هناك بعض الفيزياء ، بما في ذلك المفاصل والمركبات ذات العجلات. لا يوجد محرر تضاريس مدمج ، ولكن يمكنك استخدام المكون الإضافي أو الاستيراد من البرامج المتخصصة أو تمامًا مثل شبكة من حزمة ثلاثية الأبعاد. في الحالة الأخيرة ، من أجل الأداء ، سيكون عليك قطع المشهد بشكل مستقل إلى أجزاء من القطعة ، وعلى الأرجح جعلها شبكات منفصلة للتصادمات. أما بالنسبة للشبكات لشكل تصادم المشهد - حتى لا تكون هناك تناقضات مرئية ، فأنت بحاجة إلى تثليث النموذج أثناء التصدير من الحزمة ثلاثية الأبعاد. على سبيل المثال ، إحدى أبسط الطرق للقيام بذلك في Blender هي تصدير الشبكة بتنسيق collada (.dae) ، وهناك مربع اختيار ثلاثي بشكل افتراضي.

في بعض الأحيان ، يجب قلب نموذج Blender بزاوية 180 درجة داخل Godot ، لذلك لا تتفاجأ إذا لم تكن التضاريس مرئية - على الأرجح يتم تدويرها بواسطة المعايير في الاتجاه الخاطئ.



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





theEnergy, . Area, , , .



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





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



أما بالنسبة للمتغيرات العامة ، لاستخدامها في كل من GDScript و C # ، فأنت بحاجة إلى إضافة نص برمجي / نصوص عالمية لبدء التشغيل في معلمات المشروع ، والتي يمكن الوصول إلى متغيراتها عالميًا.

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



الإشارات



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

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





النحو التالي : نبدأ الإشارة ونصدرها



في نفس النص البرمجي عند الضغط على زر أو شروط أخرى



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

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





في وقت تجميع المستوى ، نجد سفينة فضائية عليها ونرفق بها مستمع إشارة ، يشير إلى الطريقة التي سنعالج بها رسائل هذه الإشارة.



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





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



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





حدث حدث ونحن نتطلع لمعرفة ما إذا كان الكائن الذي دخل المنطقة لديه الطريقة الصحيحة.





, , . , , .



CSG-





واحدة من الأدوات ثلاثية الأبعاد المفيدة في Godot هي بدائية هندسية صلبة بناءة. ببساطة ، هذه الأشياء تدعم العمليات المنطقية - التقاطع والإقصاء والاتحاد. بالإضافة إلى مجموعة البدائيين ، هناك شبكة CSG عالمية ، يمكن تعيين شبكة عشوائية كشكل.







ستكون دمية CSG Combiner مطلوبة للاستخدام في تسلسل هرمي للتحكم في أولوية العمليات عندما يكون من الضروري تجميع بعض الهياكل المعقدة.





زوج من المجالات التي تم نحت الكرات الطفل منها.



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



التطبيق التالي لـ CSGs الثابتة هو محاكاة التدمير والضرر. للقيام بذلك ، تحتاج إلى ترتيب البدائل CSG في وضع الاستبعاد ، مثل الثقوب ، "بذرة" وخدوش ، ثم اختباء مؤقتًا ، بما في ذلك الرؤية في الوقت المناسب. القيد هنا هو أنه يمكننا فقط "إتلاف" سطح كائن CSG ؛ علاوة على ذلك ، يجب إرفاق "الضرر" في البداية كطفل ، أو إرفاقه من خلال الرمز كطفل. لكن هذا الخيار من حيث مرونة التكوين يفوز بالفعل بشكل ملحوظ مقارنةً بالكائن القابل للتدمير المحضر في الحزمة ثلاثية الأبعاد.





3 أسطوانات مدمجة في الجسر في وضع الاستثناء. بينما كانت مخفية الجسر سليم.



إذا تم تضمينها ، يتم قطع المنطقة المستبعدة من قبلهم.



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

ومع ذلك ، من الصعب بالفعل استبدال تأثيرات CSGs المتحركة بحلول حزمة ثلاثية الأبعاد ، لذلك قد تكون مهتمًا باستخدامها (على الأقل إذا كنت لن ترسم الأبعاد الثلاثية المتقدمة من خلال التعليمات البرمجية). الشيء الرئيسي هو العثور على الاستخدام المناسب لهم ، فمن الأفضل استخدامها بشكل نقطي ، في أماكن معينة ، بما في ذلك الرسوم المتحركة على الزناد. نتيجة لفتح ممر أو تأثير خاص آخر لمرة واحدة. بطبيعة الحال ، كلما كان شكل كائنات CSG أبسط - كلما كان ذلك أفضل. وهي تمارس الحمل الحسابي الرئيسي على وجه التحديد في عملية الاتصال أثناء الحركة ، علاوة على ذلك ، لا يوجد فرق معين في أي جسم يتم تحريكه بالنسبة إلى آخر.





هناك لحظة في الفيديو حيث تسقط السيارة من خلال فتحة في الجسر ، عندما تمر كبسولة CSG متحركة عبر شبكة CSG مع نموذج للجسر.



Multimesh





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

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





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





لدينا هنا كائنين تمت إضافتهما إلى المشهد كعقد MeshInstance. بعد ذلك ، تركنا الكائن الأيسر على اليمين.





نحصل على multimesh. في هذه الحالة ، تم تعيين 10000 نسخة في الإعدادات. بالمناسبة ، إذا كان هناك 3-4 آلاف منهم ، فلن تكون النتيجة بصريًا مختلفة تمامًا.



يمكن نقل multimesh "المخبوز" في أي مكان ، بالإضافة إلى أنه يحتوي على معلمة Visible Instance التي تعرض في البداية عدد النسخ المستنسخة المحددة أثناء الإنشاء. من خلال تغيير هذه القيمة ، يمكنك التحكم في عدد النسخ المستنسخة التي تظهر في الوقت الحالي. بشكل افتراضي ، تكون -1 ، ولكن هذه قيمة خاصة لعرض الحد الأقصى من النسخ المستنسخة. إذا وضعت 10 ، فسيكون هناك 10 استنساخ. إذا كان 100 ، ثم 100. إذا كان الحد الأقصى 50 ، فعند 100 ، و 1000 ، و -1 سيكون 50 منهم.

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





قمنا بتعيين المثيل المرئي إلى 500 وتنخفض كثافة التعبئة بشكل كبير.



متنوع





يمكن تكوين الإدارة في Godot من خلال فتح عنصر المشروع في جزء المحرر العلوي. بعد ذلك ، إعدادات المشروع ، علامة التبويب قائمة الإجراءات .





يمكنك معرفة ما تسمى الأزرار الافتراضية لمعرفة الأسماء التي يتم الوصول إليها من خلال التعليمات البرمجية. وإضافة أيضًا الخاصة بك.



على سبيل المثال ، الاسم الافتراضي لزر PgUP هو "ui_page_up" ، ويمكنك التعامل مع الضغط عليه في التعليمات البرمجية عن طريق كتابة السطر التالي في GDScript - إذا كان Input.is_action_pressed ("ui_page_up"):

إذا كان الإجراء مطلوبًا بضغطة واحدة ، فيجب استبدال is_action_pressed بـ is_action_Just_pressed. نهاية الضغط - التغييرات الضغط على صدر.



#



إذا كنت بحاجة إلى تحريك وميض مادة ، يمكنك القيام بذلك من خلال تظليل مكتوب ذاتيًا. للقيام بذلك ، حدد New ShaderMaterial كمادة للكائن.









بعد ذلك ، حدد VisualShader في الحقل الفارغ.





انقر فوقه ، يفتح المحرر المرئي أسفل المحرر.



أضف زوجًا من العقد ، أولاً الإدخال - كل الوقت ، ثم Scalar - Common - ScalarFunc ، وقم بتعيينها في القائمة المنسدلة ، على سبيل المثال ، خطيئة. من حيث المبدأ ، سيعطي مثل هذا البناء بالفعل شيئًا مثل الخفقان بين الأسود والأبيض ، ولكن لجعله أفضل ، أضف عقدة أخرى Scalar - Common - ScalarFuncواختر عبس هناك. نقوم بتوصيل العقد معًا (لاحظ أنه من خلال النقر على العين المغلقة لكل عقدة ، يمكنك فتحها ومعرفة كيفية تغير الصورة في كل مرحلة) والاتصال بقناة Alpha أو Emission أو Albedo. هذا كل شيء ، فإن هدفنا يتلألأ الآن.







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



#



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

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



#



لاستخدام المتغيرات العالمية ، تحتاج إلى إنشاء برنامج نصي وإفلاته في التحميل التلقائي: المشروع -إعدادات المشروع - بدء التشغيل . يجب تحديد مربع الاختيار "singleton".





محتويات البرنامج النصي SaveTheWorld الذي نريد استخدامه في المتغيرات العالمية. في الوقت الحالي ، يتم الإعلان عن مؤشر صحي معين ومجموعة من الدول المعادية هنا ، ويتم ملؤها في خطوة التهيئة.



للإشارة إلى هذه المتغيرات العالمية من الشفرة ، تحتاج أولاً إلى الحصول على مرجع إلى المفرد ، ثم استخدام متغيراته:





ابحث عن SaveTheWorld ، ثم تحقق مما إذا كانت حالة هذا العدو المحدد صفر. إذا كان الأمر كذلك ، تتم إزالة العدو.



UPD. يمكنك الوصول إلى متغيرات المفرد مباشرة من خلال اسمه ، أي في المثال أعلاه ، لن نضطر إلى أخذ رابط ، وبدلاً من main.enemy_arr [myID] سنشير إلى SaveTheWorld.enemy_arr [myID]. ولكن يجب أن تتأكد من أن هذه العقدة لها علامة اختيار في عمود "singleton" في بدء التشغيل.



#



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

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







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

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



#



للعقد المختلفة ، على سبيل المثال MeshInstance أو CollisionShape ، في حقل Mesh (Shape) يمكنك الاختيار من قائمة معدة من البدائيين (بما في ذلك تحميل النموذج المخصص الخاص بك ، في حالة MeshInstance).







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

يمكن أن يقوم Godot أيضًا بعمل شكل تصادم لـ MeshInstance تلقائيًا عن طريق النقر فوق زر Array الذي يظهر في أعلى اليمين في المحرر عند تحديد MeshInstance. بعد ذلك ، اختر من الخيارات المقترحة ، ولكن كقاعدة عامة ، لنفس التضاريس ، سيكون هذا العنصر الأول - "إنشاء جسم ثابت مقعر" (وبعد ذلك سيتم إرفاق عقدة StaticBody بالكائن مع التصادم الدقيق المتداخل فيه). في جميع الحالات الأخرى ، عندما لا تكون هناك حاجة إلى تصادمات دقيقة بشكل خاص ، يمكنك الحصول عليها باستخدام بدائل CollisionShape المكشوفة بشكل مستقل ، أو جمع الشبكات المثالية للتصادمات في حزمة ثلاثية الأبعاد ، ثم إضافتها من خلال MeshInstance وإنشاء تصادم بناءً على شكلها عبر زر "Array".



#



إذا كان مطلوبًا في أي من الحقول الرقمية في المفتش ، على سبيل المثال ، إضافة رقم معين إلى المعلمة ، وضرب القيمة ، وما إلى ذلك ، يمكنك ضرب هذه الطريقة: "315-180" ، "20 + 40" ، "64 * 5" ... سيحرر المحرر نفسه ويستبدل النتيجة النهائية للعملية في الميدان.



All Articles