دورة دروس SDL 2.0: الدرس 5 - تقطيع ورقة الرموز المتحركة

صورة

من مترجم:

هذا استمرار لسلسلة من ترجمات دروس Twinklebear ، المتوفرة في الأصل هنا . الترجمة مجانية جزئيًا وقد تحتوي على تعديلات طفيفة أو إضافات من المترجم. ترجمة أول درسين - التأليفInvalidPointerوالثالث والرابع ل k1-801.


قائمة الدروس:



تقطيع ورقة العفريت


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

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

صورة


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

اختيار جزء


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

تغيير مادة التقديم


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

/**
*  SDL_Texture  SDL_Renderer   .
*     
* @param tex  ,   
* @param ren ,    
* @param dst     
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, SDL_Rect dst,
        SDL_Rect *clip = nullptr)
{
        SDL_RenderCopy(ren, tex, clip, &dst);
}

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

/**
*  SDL_Texture  SDL_Renderer   x, y, 
*          
*    ,       
*          
* @param tex  ,   
* @param ren ,    
* @param x  x,    
* @param y  y,    
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y,
        SDL_Rect *clip = nullptr)
{
        SDL_Rect dst;
        dst.x = x;
        dst.y = y;
        if (clip != nullptr){
                dst.w = clip->w;
                dst.h = clip->h;
        }
        else {
                SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
        }
        renderTexture(tex, ren, dst, clip);
}

تحديد مستطيلات القص


في حالتنا ، من السهل جدًا حساب مستطيلات القص باستخدام الطريقة التي تشبه إلى حد كبير طريقة التجانب من الدرس 3 ، ومع ذلك ، بدلاً من الانتقال سطرًا بسطر ، سنذهب عمودًا تلو الآخر. وبالتالي ، ستكون القطعة الأولى خضراء ، والثانية حمراء ، والثالثة زرقاء والرابعة صفراء. فكرة الحوسبة هي نفسها كما في الدرس 3 ، لكننا نمر عبر الأعمدة بدلاً من الصفوف. لذلك يتم حساب إحداثيات ص لدينا من خلال الحصول على الباقي عند قسمة فهرس البلاط على عدد البلاطات (2) ، والإحداثيات س بقسمة الفهرس على عدد البلاطات. إحداثيات x و y هي مؤشرات x و y ، لذا نترجمها إلى إحداثيات بكسل حقيقية عن طريق الضرب في عرض القطع وارتفاعه ، وهو نفسه بالنسبة لجميع المربعات (100x100). أخيرًا ، حدد القطعة للرسم ، في هذه الحالة الأولى.

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

//iW  iH    
//   ,     ,     
int iW = 100, iH = 100;
int x = SCREEN_WIDTH / 2 - iW / 2;
int y = SCREEN_HEIGHT / 2 - iH / 2;

//    
SDL_Rect clips[4];
for (int i = 0; i < 4; ++i){
        clips[i].x = i / 2 * iW;
        clips[i].y = i % 2 * iH;
        clips[i].w = iW;
        clips[i].h = iH;
}
//     
int useClip = 0;

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

تغيير الصور بناءً على الإدخال


للتحقق من جميع أجزاء الصورة التي أنشأناها ، نضيف معالجة إدخال لوحة المفاتيح إلى حلقة معالجة الحدث ونختار الجزء المعروض باستخدام المفاتيح 1-4. لتحديد ما إذا كان قد تم الضغط على أحد المفاتيح ، يمكنك التحقق مما إذا كان الحدث من النوع SDL_KEYDOWN ، وإذا كان الأمر كذلك ، يمكننا معرفة أي مفتاح تم الضغط عليه عن طريق التحقق من رمز المفتاح داخل الحدث باستخدام e.key.keysym.sym. قائمة كاملة بأنواع الأحداث ، ورموز المفاتيح ، ومعلومات أخرى عن SDL_Event متاحة على الويكي.

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

while (SDL_PollEvent(&e)){
        if (e.type == SDL_QUIT)
                quit = true;
        //       
        if (e.type == SDL_KEYDOWN){
                switch (e.key.keysym.sym){
                        case SDLK_1:
                                useClip = 0;
                                *break;
                        case SDLK_2:
                                useClip = 1;
                                *break;
                        case SDLK_3:
                                useClip = 2;
                                *break;
                        case SDLK_4:
                                useClip = 3;
                                *break;
                        case SDLK_ESCAPE:
                                quit = true;
                                *break;
                        default:
                                *break;
                }
        }
}

ارسم صورة مقطوعة


آخر شيء تفعله هو الحصول على الجزء الصحيح من الصورة على الشاشة! سنفعل ذلك من خلال استدعاء نسختنا الأكثر ملاءمة من مادة الرسم لجعل الصورة جزءًا من الصورة دون تحجيم إضافي ونقل الجزء الذي نريد استخدامه (الجزء المستخدم في useClip).

SDL_RenderClear(renderer);
renderTexture(image, renderer, x, y, &clips[useClip]);
SDL_RenderPresent(renderer);

نهاية الدرس 5


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

All Articles