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

- بشكل صريح جدا هذا طائر الفينيق يرفرف بجناحيه.
كما ترون ، يحتوي كل صف على 4 إطارات لكل من التوقعات الأربعة. عن طريق تغيير
OffsetX فقط ، يمكنك جعل أجنحة الطيور ترفرف بجناحيها ، ولتغيير الإسقاط يكفي تغيير
OffsetY فقط. هذا الفصل بين الإطارات بخطوط يبسط إلى حد كبير برمجة الرسوم المتحركة.
حجم هذه الصورة هو 384 × 384 ، وحجم كل إطار هو 96 × 96. لسوء الحظ ، أدى الاستخدام المباشر لهذه الصورة إلى إزعاجنا بالقطع الأثرية: يتم وضع بعض إطارات الصورة بحيث تقع حوافها على إطارات مجاورة ، وخلال الرسوم المتحركة ، تومض السكتات الدماغية الصفراء عند حواف العفريت.
لإصلاح هذه العيوب ، استخدمت محرر الرسوم البيانية المجاني
GIMP (
الموقع الرسمي ). كل ما كان يجب القيام به هو إزالة وحدات البكسل البارزة للصور في الأماكن التي سقطت فيها على الإطار المجاور.
الملف المصحح يشبه هذا:

- بالعين المجردة ، تكون الاختلافات غير مرئية ، لكن الخيار الثاني يعمل بدون آثار.
إنشاء مشروع جديد
1. إنشاء مشروع جديد من نوع "التطبيق".
بشكل افتراضي ، يقوم IDE بإنشاء مشروع يسمى "project1" ، والذي ينشئ على الفور وحدة نمطية واحدة للبرنامج تسمى "unit1" ، والتي تصف فئة تسمى "TForm1" وتعلن مثيلًا باسم "Form1".
بشكل عام ، عند إنشاء كائنات جديدة ، يقوم IDE بتعيين أسماء مشابهة لها ، تتكون من اسم نوع الكائن والرقم التسلسلي. أعتبر أنه من الجيد إعادة تسمية كل هذه الكائنات ، مع إعطائها أسماء ذات معنى تعكس دور أو غرض الكائن.
لذلك ، لن يطلق على مشروعنا "project1" ، ولكن "Phoenix" - وفقًا لاسم العفريت المحدد.
2. حفظ مشروعنا الجديد.
يُنصح بحفظ كل مشروع في دليل منفصل باسم يطابق اسم المشروع. في عملية الحفظ ، نشير إلى الدليل المراد حفظه (إذا لزم الأمر ، نقوم بإنشائه هناك) ، ثم اسم ملف المشروع واسم ملف وحدة البرنامج. قمت بإنشاء مجلد "Phoenix" وحفظت ملف المشروع هناك ("Phoenix.lpi" بدلاً من "project1.lpi" المقترح) وملف وحدة البرنامج ("UnitMain.pas" بدلاً من "unit1.pas" المقترح)).
حالة الأحرف فارق بسيطيؤدي إصدار Lazarus لنظام التشغيل Windows إلى تحويل اسم ملف الوحدة النمطية للبرنامج إلى أحرف صغيرة: "unitmain.pas" ، لكن اسم البرنامج الخاص بالوحدة النمطية يحتفظ بالحالة الأصلية للأحرف: "unit UnitMain؛". لا يحدث هذا مع ملف المشروع ؛ يحفظ اسم الملف الحالة الأصلية للأحرف.
3. إعادة تسمية النموذج وتغيير عنوانه.
النموذج المنشأ حديثًا ، المسمى "Form1" (خاصية
الاسم ) ، هو مثيل لفئة "TForm1" ويحتوي على العنوان "Form1" (خاصية
Caption ). قم بتغيير خاصية
اسم النموذج إلى "FormMain" ، وسوف يتغير اسم الفئة إلى "TFormMain".
تغيير خاصية
Caption إلى "Phoenix" بحيث يتم عرض عنوان المشروع في عنوان النافذة.
4. كنتيجة لذلك ، حصلت على النص التالي لوحدة unitmain.pas:
unit UnitMain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs; type TFormMain = class(TForm) private public end; var FormMain: TFormMain; implementation {$R *.lfm} end.
5. ترجمة ، قم بتشغيل المشروع (المفتاح <F9>):

ضع العفريت على النموذج
على افتراض أنك قمت بالفعل بتثبيت مكون
TImageFragment الموضح في مقالتي
Lazarus السابقة
- نكتب مكونًا للرسوم المتحركة العفوية ، وحدد علامة التبويب "Game" في لوحة المكون وقم بإضافة مكون "TImageFragment" إلى النموذج.
باستخدام خاصية
الصورة ، قم بتحميل صورة (إصدار ثابت من طائر الفينيق) في المكون. بالإضافة إلى ذلك ، نقوم أيضًا بتغيير الخصائص التالية للكائن الجديد:
- قم بتعيين خصائص الارتفاع والعرض إلى 96
- اضبط الخصائص لليسار والأعلى على 0 (ملائمة للمطابقة مع لقطات الشاشة الخاصة بي)
- يتم تغيير خاصية الاسم من "ImageFragment1" غير المناسب إلى "Sprite" بسيطة ومفهومة
إذا تم كل شيء بشكل صحيح ، فسوف يعرض المكون الإطار الأول للصورة:
سيخضع نص وحدة
UnitMain لتغييرات بسيطة:
- يتم إضافة وحدة
ImageFragment إلى قسم
الاستخدامات uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ImageFragment;
- سيظهر كائن جديد في إعلان الفصل
TFormMain = class(TForm) Sprite: TImageFragment; private public end;
إضافة الرسوم المتحركة - اللوحات الجناح
1. أضف مكونًا جديدًا من فئة
TTimer إلى
النموذج .
يوجد هذا المكون في علامة التبويب "النظام" في لوحة المكون. يمكنك وضعه في أي مكان مناسب في النموذج ، لأنه لا يتم عرضه في تطبيق قيد التشغيل.
2. إعادة تسمية الكائن المضافة.
يحصل الكائن الجديد تلقائيًا على الاسم "Timer1" ، لكننا نسميه باسم "TimerLive". غالبًا ما يكون من المناسب إعطاء كائنات مثل هذه الأسماء ، التي تتكون من جزأين: الأول يعكس فئة الكائن ، والثاني يعكس الغرض منه.
3. قم بتغيير خاصية
الفاصل الزمني من 1000 إلى 100.
دع إطارات هذه الرسوم المتحركة تحل محل بعضها البعض كل 100 ميلي ثانية ، أي 10 مرات في الثانية. في المستقبل ، يمكن تغيير هذه الخاصية لإبطاء أو تسريع جناحيها - حسب تقدير المبرمج.
4. أضف معالج أحداث OnTimer.
أسهل طريقة للقيام بذلك هي النقر المزدوج على أيقونة كائن
TimerLive جديد. نتيجة لهذا الإجراء ، سيضيف IDE نفسه إجراءً جديدًا إلى إعلان فئة النموذج ، وسيتم إضافة رابط لهذا الإجراء إلى خصائص الكائن ، وسيتم إضافة نص الإجراء الجديد إلى قسم
التنفيذ (وسيتم وضع المؤشر داخل هذا الإجراء الجديد ، بين
الكلمات الرئيسية للبداية والنهاية ).
5. أضف سطرًا واحدًا من التعليمات البرمجية إلى الإجراء الجديد.
Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384;
نتيجة لهذه الإجراءات ، يجب أن يبدو إعلان الفصل كما يلي:
TFormMain = class(TForm) Sprite: TImageFragment; TimerLive: TTimer; procedure TimerLiveTimer(Sender: TObject); private public end;
والإجراء الجديد - يجب أن يبدو
معالج أحداث
OnTimer بشيء من هذا القبيل:
procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end;
بعد تجميع التطبيق وتشغيله ، يمكنك مشاهدة طائر العنقاء الذي يرفرف بجناحيه.
يحدث هذا لأن معالج الأحداث المؤقت كل 100 مللي ثانية يغير دوريًا إزاحة الجزء المعروض ، ويتم تغيير الإطار المحدد أفقيًا ، ويعرض بالتتابع 4 إطارات من السطر العلوي للصورة المحملة. تمنع عملية
التعديل - الحصول على باقي القسم - الإزاحة من تجاوز حجم الصورة ، ونتيجة لذلك ، فإن الإطار الرابع يتبعه الإطار الأول مرة أخرى.
إضافة حركة العفريت حول النافذة
1. أضف وحدة
الرياضيات إلى قسم
الاستخدامات uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math;
2. أضف متغيرًا جديدًا وثابتًا إلى إعلان الفصل.
لحفظ متجه تحريك العفريت حول النافذة ، أضف متغيرًا من النوع
TPoint private FVector: TPoint;
في نفس المكان ، نعلن عن ثابت لضبط وحدة سرعة الحركة
const Speed = 10;
3. أضف مكونًا آخر من فئة
TTimer إلى
النموذج .
أذكرك: يوجد هذا المكون في علامة التبويب "النظام" في لوحة المكونات.
الكائن الجديد مرة أخرى يحصل تلقائيًا على اسم "Timer1" ، ونعيد تسميته - هذه المرة إلى "TimerMove". الغرض من الموقت الثاني هو التحكم في حركة العفريت. لم أربط كلتا العمليتين (الرسوم المتحركة والحركة) مع الموقت نفسه بحيث يمكن ضبط كل من الموقتات بشكل منفصل - على سبيل المثال ، لإبطاء وتيرة تقلبات الجناح دون إبطاء الحركة ، وما إلى ذلك.
4. قم بتغيير خاصية
الفاصل الزمني من 1000 إلى 100.
اسمح لهذا الموقت أيضًا إطلاق كل 100 ميلي ثانية ، أي 10 مرات في الثانية. في المستقبل ، يمكن أيضًا تغيير هذه الخاصية لإبطاء أو تسريع وتيرة تقديم حقيقة حركة العفريت.
5. أضف
معالج أحداث
OnTimer .
للتغيير ، هذه المرة أقترح القيام بذلك عن طريق النقر المزدوج مقابل حدث
OnTimer في علامة التبويب "الأحداث" الخاصة بكائن
TimerMove الجديد. في المرة الأخيرة ، ونتيجة لهذا الإجراء ، سيضيف IDE نفسه إجراءً جديدًا إلى إعلان فئة النموذج ، ورابطًا لهذا الإجراء إلى خصائص الكائن ، وستتم إضافة نص الإجراء الجديد إلى قسم
التنفيذ (وسيتم وضع المؤشر داخل هذا الإجراء الجديد ، بين المفتاح الكلمات
تبدأ وتنتهي ).
6. أضف سطرين من التعليمات البرمجية إلى الإجراء الجديد.
Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y));
باستخدام دالات Max () و Min () يمنع sprite من إنهاء النموذج (إطار التطبيق الرئيسي).
من أجل استخدام هذه الوظائف ، قمنا بتوصيل وحدة
الرياضيات بقسم
الاستخدامات .
7. أضف
معالج أحداث
OnKeyPress .
حدد النموذج (انقر على المستطيل الرمادي لتخطيط النافذة خارج جميع المكونات المضافة) وفي علامة تبويب الأحداث ،
وجدنا حدث
OnKeyPress . بالنقر المزدوج على القيمة الفارغة لمعالج الأحداث ، نقوم بإنشاء وتعيين إجراء جديد - معالج الحدث.
8. أضف بضعة أسطر من التعليمات البرمجية إلى الإجراء الجديد.
if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0);
نتيجة لهذه الإجراءات ، يجب أن يبدو إعلان الفصل كما يلي:
TFormMain = class(TForm) Sprite: TImageFragment; TimerMove: TTimer; TimerLive: TTimer; procedure FormKeyPress(Sender: TObject; var Key: char); procedure TimerLiveTimer(Sender: TObject); procedure TimerMoveTimer(Sender: TObject); private FVector: TPoint; const Speed = 10; public end;
والإجراءات الجديدة - يجب أن تبدو معالجات الأحداث
OnTimer و
OnKeyPress بالشكل التالي:
procedure TFormMain.TimerMoveTimer(Sender: TObject); begin Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); end; procedure TFormMain.FormKeyPress(Sender: TObject; var Key: char); begin if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0); end;
بعد تجميع التطبيق وتشغيله ، يمكنك نقل طائر العنقاء عبر الشاشة باستخدام مفاتيح "a" و "w" و "s" و "d" وإيقافه باستخدام شريط المسافة.
نحن نستخدم توقعات مختلفة من العفريت
أضف التعليمات البرمجية التالية إلى نهاية الإجراء
TFormMain.FormKeyPress if FVector.x < 0 then Sprite.OffsetY := 96 else if FVector.x > 0 then Sprite.OffsetY := 192 else if FVector.y < 0 then Sprite.OffsetY := 288 else Sprite.OffsetY := 0;
يؤدي تغيير خاصية
OffsetY وفقًا لمتجه الإزاحة إلى تدوير الصورة في اتجاه الحركة.
كل وحدة UnitMain النص unit UnitMain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math; type TFormMain = class(TForm) Sprite: TImageFragment; TimerMove: TTimer; TimerLive: TTimer; procedure FormKeyPress(Sender: TObject; var Key: char); procedure TimerLiveTimer(Sender: TObject); procedure TimerMoveTimer(Sender: TObject); private FVector: TPoint; const Speed = 10; public end; var FormMain: TFormMain; implementation {$R *.lfm} procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end; procedure TFormMain.TimerMoveTimer(Sender: TObject); begin Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); end; procedure TFormMain.FormKeyPress(Sender: TObject; var Key: char); begin if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0); if FVector.x < 0 then Sprite.OffsetY := 96 else if FVector.x > 0 then Sprite.OffsetY := 192 else if FVector.y < 0 then Sprite.OffsetY := 288 else Sprite.OffsetY := 0; end; end.
بدلا من الكلمة الأخيرة
هذا المثال البسيط لا يطالب بتصنيفات عالية للسرعة أو قابلية الاستخدام. إذا أراد شخص ما ، كما في
المقالة السابقة ، أن يقول في التعليقات أن الرسوم المتحركة يجب أن تتم بشكل خاطئ - مرحبًا ، اكتب مقالك. وموضوع هذه المقالة هو كيفية جعل الرسوم المتحركة في عدة أسطر من التعليمات البرمجية ، دون استخدام أي مكتبات خاصة ، عملياً "على الركبة". تم اختبار هذه الطريقة في الممارسة العملية ، وهي تعمل حقًا ، لذا قبل أن تنتقد و "ناقص" ، يرجى إعادة قراءة ما تدور حوله هذه المقالة ولماذا.