Lazarus - animasi sederhana menggunakan komponen TImageFragment

Alih-alih kata pengantar

Dalam artikel Lazarus saya baru-baru ini - menulis komponen untuk animasi sprite, saya menjelaskan proses pembuatan komponen TImageFragment sederhana yang memungkinkan Anda untuk menampilkan fragmen gambar tertentu.

Melanjutkan topik yang dipilih, dalam artikel ini saya ingin menunjukkan betapa mudahnya membuat animasi sprite di lingkungan pengembangan Lazarus ( situs resmi ) menggunakan komponen ini.

Dengan pendekatan ini, masing-masing frame animasi dalam proyeksi yang berbeda ditempatkan pada gambar yang sama, dan komponen untuk menampilkan sprite hanya menunjukkan satu fragmen yang dipilih dari gambar ini menggunakan properti OffsetX dan OffsetY (offset sudut kiri atas fragmen gambar secara horizontal dan vertikal).

Banyak dari gambar yang sudah jadi ini dapat ditemukan di Web - misalnya, di sini di situs ini .

Pilih (dan siapkan) gambar

Sebagai contoh saya, saya memilih gambar ini:

- Sangat ekspresif burung Phoenix ini mengepakkan sayapnya.

Seperti yang Anda lihat, setiap baris berisi 4 bingkai untuk masing-masing dari 4 proyeksi. Dengan mengubah hanya OffsetX , Anda dapat membuat burung mengepakkan sayapnya, dan untuk mengubah proyeksi itu cukup dengan hanya mengganti OffsetY . Pemisahan bingkai demi baris ini sangat menyederhanakan pemrograman animasi.

Ukuran gambar ini adalah 384x384, dan ukuran setiap frame adalah 96x96. Sayangnya, penggunaan langsung gambar ini membuat kami kesal dengan artefak: beberapa bingkai gambar ditempatkan sehingga tepinya jatuh pada bingkai yang berdekatan, dan selama animasi, goresan kuning berkedip di tepi sprite.

Untuk memperbaiki cacat ini, saya menggunakan editor grafis lintas platform gratis GIMP ( situs resmi ). Semua yang harus dilakukan adalah menghapus piksel yang menonjol dari gambar di tempat mereka jatuh pada bingkai yang berdekatan.

File yang diperbaiki terlihat seperti ini:



- Dengan mata telanjang, perbedaannya tidak terlihat, tetapi opsi kedua bekerja tanpa artefak.

Buat proyek baru

1. Buat proyek jenis "Aplikasi" baru.

Secara default, IDE membuat proyek yang disebut "project1", yang segera membuat satu modul program yang disebut "unit1", yang menggambarkan kelas yang disebut "" TForm1 "dan mendeklarasikan instance dengan nama" Form1 ".

Secara umum, saat membuat objek baru, IDE memberinya nama yang mirip, terdiri dari nama tipe objek dan nomor seri. Saya menganggap itu gaya yang baik untuk mengubah nama semua objek seperti itu, memberi mereka nama yang bermakna yang mencerminkan peran atau tujuan objek.

Jadi, proyek kami tidak akan disebut "project1", tetapi "Phoenix" - sesuai dengan nama sprite yang dipilih.

2. Simpan proyek baru kami.

Dianjurkan untuk menyimpan setiap proyek dalam direktori terpisah dengan nama yang cocok dengan nama proyek. Selama proses penyimpanan, kami menentukan direktori yang akan disimpan (jika perlu, kami membuatnya di sana), lalu nama file proyek dan nama file modul program. Saya membuat folder "Phoenix" dan menyimpan file proyek di sana ("Phoenix.lpi" alih-alih yang diusulkan "project1.lpi") dan file modul program ("UnitMain.pas" alih-alih yang diusulkan "unit1.pas").

Nuansa case karakter
Versi Lazarus untuk Windows mengarahkan nama file modul program ke huruf kecil: "unitmain.pas", tetapi nama program modul mempertahankan huruf asli karakter: "unit UnitMain;". Ini tidak terjadi pada file proyek, nama file mempertahankan huruf asli karakter.

3. Ganti nama formulir dan ubah judulnya.

Formulir yang baru dibuat, disebut "Form1" (properti Name ), adalah turunan dari kelas "TForm1" dan berisi judul "Form1" (properti Caption ). Ubah properti Name dari form menjadi "FormMain", dan nama kelas akan berubah menjadi "TFormMain".

Ubah properti Caption menjadi "Phoenix" sehingga judul proyek ditampilkan dalam judul jendela.

4. Sebagai hasilnya, saya mendapatkan teks berikut dari modul 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. Kompilasi, jalankan proyek (kunci <F9>):



Letakkan sprite di formulir

Dengan asumsi bahwa Anda telah menginstal komponen TImageFragment yang dijelaskan dalam artikel Lazarus saya sebelumnya - kami menulis komponen untuk animasi sprite , pilih tab "Game" pada palet komponen dan tambahkan komponen "TImageFragment" ke formulir.

Menggunakan properti Picture , memuat gambar (versi tetap burung Phoenix) ke dalam komponen. Selain itu, kami juga mengubah properti objek baru berikut:

  • atur properti Tinggi dan Lebar ke 96
  • atur properti Kiri dan Atas ke 0 (nyaman untuk mencocokkan dengan tangkapan layar saya)
  • Properti nama diubah dari "ImageFragment1" yang tidak nyaman menjadi "Sprite" yang sederhana dan dapat dimengerti.

Jika semuanya dilakukan dengan benar, komponen akan menampilkan bingkai pertama dari gambar:


Teks modul UnitMain akan mengalami perubahan kecil:
- modul ImageFragment ditambahkan ke bagian penggunaan

 uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ImageFragment; 

- objek baru akan muncul di deklarasi kelas

  TFormMain = class(TForm) Sprite: TImageFragment; private public end; 


Tambahkan animasi - sayap sayap

1. Tambahkan komponen baru dari kelas TTimer ke formulir .

Komponen ini terletak pada tab "Sistem" pada palet komponen. Anda dapat menempatkannya di tempat yang nyaman di formulir, karena tidak ditampilkan di aplikasi yang sedang berjalan.

2. Ganti nama objek yang ditambahkan.

Objek baru secara otomatis mendapatkan nama "Timer1", tetapi kami menamainya menjadi "TimerLive". Sering kali lebih mudah untuk memberi nama benda seperti itu, terdiri dari dua bagian: yang pertama mencerminkan kelas objek, dan yang kedua mencerminkan tujuannya.

3. Ubah properti Interval dari 1000 menjadi 100.

Biarkan bingkai animasi ini saling menggantikan setiap 100 milidetik, yaitu 10 kali per detik. Di masa depan, properti ini dapat diubah untuk memperlambat atau mempercepat rentang sayap - sesuai kebijakan programmer.

4. Tambahkan pengendali acara OnTimer.

Cara termudah untuk melakukan ini adalah klik dua kali pada ikon objek TimerLive baru. Sebagai hasil dari tindakan ini, IDE itu sendiri akan menambahkan prosedur baru ke deklarasi kelas bentuk, tautan ke prosedur ini ke properti objek, dan badan prosedur baru akan ditambahkan ke bagian implementasi (dan kursor akan ditempatkan di dalam prosedur baru ini, antara kata kunci mulai dan akhir ).

5. Tambahkan satu baris kode ke prosedur baru.

  Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; 

Sebagai hasil dari tindakan ini, deklarasi kelas akan terlihat seperti ini:

  TFormMain = class(TForm) Sprite: TImageFragment; TimerLive: TTimer; procedure TimerLiveTimer(Sender: TObject); private public end; 

Dan prosedur baru - event handler OnTimer akan terlihat seperti ini:

 procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end; 

Setelah menyusun dan menjalankan aplikasi, Anda dapat menyaksikan burung Phoenix mengepakkan sayapnya.

Ini terjadi karena pengendali peristiwa waktu setiap 100 milidetik mengubah siklus offset fragmen yang ditampilkan, dan frame yang dipilih digeser secara horizontal, secara berurutan menampilkan 4 frame dari garis atas gambar yang dimuat. Operasi mod - mendapatkan sisa divisi - mencegah offset melampaui ukuran gambar, dan sebagai hasilnya, frame ke-4 kembali diikuti oleh frame ke-1.

Tambahkan gerakan sprite di sekitar jendela

1. Tambahkan modul Matematika ke bagian penggunaan

 uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math; 

2. Tambahkan variabel baru dan konstan ke deklarasi kelas.

Untuk menyimpan vektor memindahkan sprite di sekitar jendela, tambahkan variabel tipe TPoint

  private FVector: TPoint; 

Di tempat yang sama, kami mendeklarasikan konstanta untuk mendefinisikan modul kecepatan

  const Speed = 10; 

3. Tambahkan komponen lain dari kelas TTimer ke formulir .

Saya mengingatkan Anda: komponen ini terletak di tab "Sistem" pada palet komponen.

Objek baru lagi secara otomatis mendapatkan nama "Timer1", dan kami menamainya - kali ini menjadi "TimerMove". Tujuan dari pengatur waktu kedua adalah untuk mengontrol pergerakan sprite. Saya tidak mengikat kedua proses (animasi dan gerakan) ke timer yang sama sehingga masing-masing timer dapat diatur secara terpisah - misalnya, untuk memperlambat frekuensi ayunan sayap tanpa memperlambat gerakan, dan sebagainya.

4. Ubah properti Interval dari 1000 menjadi 100.

Biarkan timer ini juga menyala setiap 100 milidetik, yaitu 10 kali per detik. Di masa depan, properti ini juga dapat diubah untuk memperlambat atau mempercepat frekuensi rendering fakta sprite move.

5. Tambahkan pengendali acara OnTimer .

Untuk perubahan, kali ini saya mengusulkan untuk melakukan ini dengan mengklik dua kali berlawanan dengan peristiwa OnTimer pada tab "Acara" pada objek TimerMove yang baru. Seperti terakhir kali, sebagai hasil dari tindakan ini, IDE itu sendiri akan menambahkan prosedur baru ke deklarasi kelas bentuk, tautan ke prosedur ini ke properti objek, dan badan prosedur baru akan ditambahkan ke bagian implementasi (dan kursor akan ditempatkan di dalam prosedur baru ini, di antara kunci kata - kata mulai dan berakhir ).

6. Tambahkan dua baris kode ke prosedur baru.

  Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); 

Menggunakan fungsi Max () dan Min () mencegah sprite keluar dari form (jendela aplikasi utama).
Untuk menggunakan fungsi-fungsi ini kami menghubungkan modul Matematika ke bagian penggunaan .

7. Tambahkan pengendali event OnKeyPress .

Pilih formulir (klik pada persegi panjang abu-abu dari tata letak jendela di luar semua komponen yang ditambahkan) dan pada tab Acara kita menemukan acara OnKeyPress . Dengan mengklik dua kali pada nilai kosong event handler, kami membuat dan menetapkan prosedur baru - event handler.

8. Tambahkan beberapa baris kode ke prosedur baru.

  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); 

Sebagai hasil dari tindakan ini, deklarasi kelas akan terlihat seperti ini:

  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; 

Dan prosedur baru - Penangan event OnTimer dan OnKeyPress akan terlihat seperti ini:

 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; 

Setelah mengkompilasi dan memulai aplikasi, Anda dapat memindahkan burung Phoenix di layar menggunakan tombol "a", "w", "s", "d" dan hentikan dengan spasi.

Kami menggunakan proyeksi sprite yang berbeda

Tambahkan kode berikut ke akhir prosedur 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; 

Mengubah properti OffsetY tergantung pada vektor perpindahan menyebabkan gambar berputar ke arah gerakan.

Semua Teks Modul UnitMain
 unit UnitMain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math; type { TFormMain } 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} { TFormMain } 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. 

Alih-alih kata penutup

Contoh sederhana ini tidak mengklaim peringkat tinggi untuk kecepatan atau kegunaan. Jika seseorang, seperti dalam artikel sebelumnya , ingin memberi tahu dalam komentar bahwa animasi perlu dilakukan salah - selamat datang, tulis artikel Anda. Dan topik artikel ini adalah bagaimana membuat animasi dalam beberapa baris kode, tanpa menggunakan perpustakaan khusus, praktis β€œon the knee”. Metode ini telah diuji dalam praktiknya, itu benar-benar berhasil, jadi sebelum mengkritik dan "minus", baca kembali artikel ini tentang apa dan mengapa.

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


All Articles