Animasi masih dapat dengan sempurna dipisah antara logika dan rendering. Keadaan abstrak data animasi akan menjadi informasi yang diperlukan untuk API grafik Anda untuk membuat animasi.
Dalam game 2D misalnya, itu bisa berupa area persegi panjang yang menandai area yang menampilkan bagian sprite sheet Anda saat ini yang perlu digambar (bila Anda memiliki sheet yang terdiri dari katakanlah 30 gambar 80x80 yang berisi berbagai langkah karakter Anda melompat, duduk, bergerak dll.) Ini juga bisa berupa data apa pun yang tidak Anda perlukan untuk render, tetapi mungkin untuk mengelola status animasi itu sendiri, seperti waktu yang tersisa hingga langkah animasi saat ini berakhir atau nama animasi ("berjalan", "berdiri" dll) Semua itu dapat diwakili dengan cara apa pun yang Anda inginkan. Itu bagian logika.
Di bagian rendering, Anda cukup melakukannya seperti biasa, dapatkan persegi panjang itu dari model Anda dan gunakan renderer Anda untuk benar-benar melakukan panggilan ke API grafik.
Dalam kode (menggunakan sintaks C ++ di sini):
class Sprite //Model
{
private:
Rectangle subrect;
Vector2f position;
//etc.
public:
Rectangle GetSubrect()
{
return subrect;
}
//etc.
};
class AnimatedSprite : public Sprite, public Updatable //arbitrary interface for classes that need to change their state on a regular basis
{
AnimationController animation_controller;
//etc.
public:
void Update()
{
animation_controller.Update(); //Good OOP design ;) It will take control of changing animations in time etc. for you
this.SetSubrect(animation_controller.GetCurrentAnimation().GetRect());
}
//etc.
};
Itu datanya. Perender Anda akan mengambil data itu dan menggambarnya. Karena Sprite normal dan animasi digambar dengan cara yang sama, Anda dapat menggunakan polimorf di sini!
class Renderer
{
//etc.
public:
void Draw(const Sprite &spr)
{
graphics_api_pointer->Draw(spr.GetAllTheDataThatINeed());
}
};
TMV:
Saya datang dengan contoh lain. Katakanlah Anda memiliki RPG. Model Anda yang mewakili peta dunia, misalnya, mungkin perlu menyimpan posisi karakter di dunia sebagai koordinat petak di peta. Namun, ketika Anda memindahkan karakter, mereka berjalan beberapa piksel sekaligus ke alun-alun berikutnya. Apakah Anda menyimpan posisi "antar ubin" ini di objek animasi? Bagaimana Anda memperbarui model ketika karakter akhirnya "tiba" di koordinat ubin berikutnya di peta?
Peta dunia tidak tahu tentang posisi pemain secara langsung (tidak memiliki Vector2f atau sesuatu seperti itu yang secara langsung menyimpan posisi pemain =, melainkan memiliki referensi langsung ke objek pemain itu sendiri, yang pada gilirannya berasal dari AnimatedSprite sehingga Anda bisa meneruskannya ke renderer dengan mudah, dan mendapatkan semua data yang diperlukan darinya.
Secara umum, tilemap Anda seharusnya tidak dapat melakukan semuanya - Saya memiliki kelas "TileMap" yang menangani pengelolaan semua ubin, dan mungkin juga melakukan deteksi tabrakan antara objek yang saya serahkan ke sana dan ubin di peta. Kemudian, saya akan memiliki kelas "RPGMap" lainnya, atau bagaimanapun Anda ingin menyebutnya, yang memiliki referensi ke tilemap Anda dan referensi ke pemain dan membuat Pembaruan aktual () panggilan ke pemain Anda dan ke Anda tilemap.
Bagaimana Anda ingin memperbarui model ketika pemain bergerak tergantung pada apa yang ingin Anda lakukan.
Apakah pemain Anda diperbolehkan bergerak di antara ubin secara terpisah (gaya Zelda)? Cukup tangani input dan pindahkan pemain sesuai setiap frame. Atau Anda ingin pemain menekan "kanan" dan karakter Anda secara otomatis memindahkan satu ubin ke kanan? Biarkan kelas RPGMap Anda menginterpolasi posisi pemain sampai tiba di tujuannya dan sementara itu mengunci semua penanganan input gerakan-kunci.
Either way, jika Anda ingin membuatnya lebih mudah pada diri Anda sendiri, semua model Anda akan memiliki metode Pembaruan () jika mereka benar-benar memerlukan beberapa logika untuk memperbarui diri mereka sendiri (bukan hanya mengubah nilai variabel) - Anda tidak memberikan controller dalam pola MVC seperti itu, Anda hanya memindahkan kode dari "satu langkah di atas" (controller) ke model, dan semua controller tidak memanggil metode Update () dari model (Controller dalam kasus kami akan menjadi RPGMap). Anda masih dapat dengan mudah menukar kode logika - Anda bisa langsung mengubah kode kelas atau jika Anda memerlukan perilaku yang sama sekali berbeda, Anda hanya dapat berasal dari kelas model dan hanya mengganti metode Pembaruan ().
Pendekatan itu mengurangi pemanggilan metode dan banyak hal seperti itu - yang dulunya merupakan salah satu kelemahan utama dari pola MVC murni (Anda akhirnya memanggil GetThis () GetThat () sangat sering) - itu membuat kode lebih lama dan lebih sedikit lebih sulit untuk dibaca dan juga lebih lambat - meskipun itu mungkin ditangani oleh kompiler Anda yang mengoptimalkan banyak hal seperti itu.
Saya dapat mengembangkan ini jika Anda mau, tetapi saya memiliki penyaji pusat yang diminta untuk menggambar di loop. Daripada
Saya memiliki sistem yang lebih suka
Kelas renderer hanya menyimpan daftar referensi untuk komponen objek yang dapat digambar. Ini ditugaskan dalam konstruktor untuk kesederhanaan.
Sebagai contoh Anda, saya akan memiliki kelas GameBoard dengan sejumlah Ubin. Setiap ubin jelas tahu posisinya, dan saya menganggap semacam animasi. Faktor yang keluar ke semacam kelas Animasi yang dimiliki ubin, dan minta agar referensi sendiri ke kelas Renderer. Di sana, semuanya terpisah. Ketika Anda memperbarui Tile, itu disebut Perbarui pada animasi .. atau memperbarui itu sendiri. Ketika
Renderer.Draw()
dipanggil, itu menarik animasi.Animasi frame independen tidak perlu terlalu banyak berhubungan dengan loop pengundian.
sumber
Saya telah mempelajari paradigma sendiri belakangan ini, jadi jika jawaban ini tidak lengkap, saya yakin seseorang akan menambahkannya.
Metodologi yang tampaknya paling masuk akal untuk desain game adalah memisahkan logika dari output layar.
Dalam kebanyakan kasus, Anda ingin menggunakan pendekatan multi-utas, jika Anda tidak terbiasa dengan topik itu, itu pertanyaan tersendiri, inilah primer wiki . Pada dasarnya Anda ingin logika permainan Anda dieksekusi dalam satu utas, mengunci variabel yang perlu diakses untuk memastikan integritas data. Jika loop logis Anda sangat cepat (animasi super mega 3d pong?), Anda dapat mencoba untuk memperbaiki frekuensi loop dijalankan dengan tidur utas untuk durasi kecil (120 hz telah disarankan dalam forum ini untuk loop fisika permainan). Bersamaan, utas lainnya menggambar ulang layar (60 hz telah disarankan dalam topik lain) dengan variabel yang diperbarui, lagi-lagi meminta kunci pada variabel sebelum mengaksesnya.
Dalam hal itu, animasi atau transisi, dll., Masuk ke utas menggambar tetapi Anda harus memberi isyarat melalui semacam bendera (variabel keadaan global mungkin) bahwa utas logika permainan tidak boleh melakukan apa-apa (atau melakukan sesuatu yang berbeda ... mengatur parameter peta baru mungkin).
Setelah Anda mendapatkan kepala sekitar konkurensi, sisanya cukup dimengerti. Jika Anda tidak memiliki pengalaman dengan konkurensi, saya sangat menyarankan Anda menulis beberapa program pengujian sederhana sehingga Anda dapat memahami bagaimana aliran terjadi.
Semoga ini membantu :)
[sunting] Pada sistem yang tidak mendukung multithreading, animasinya masih dapat masuk ke draw loop, tetapi Anda ingin mengatur keadaan sedemikian rupa untuk memberi sinyal pada logika bahwa sesuatu yang berbeda sedang terjadi dan tidak terus memproses level saat ini / peta / dll ...
sumber