Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Topik ini adalah bagian dari Membuat game Universal Windows Platform (UWP) sederhana dengan seri tutorial DirectX. Topik di tautan tersebut mengatur konteks untuk seri.
Setelah Anda meletakkan kerangka kerja dasar permainan sampel, dan mengimplementasikan mesin status yang menangani perilaku pengguna dan sistem tingkat tinggi, Anda harus memeriksa aturan dan mekanika yang mengubah permainan sampel menjadi permainan. Mari kita lihat detail objek utama game sampel, dan cara menerjemahkan aturan game ke dalam interaksi dengan dunia game.
Tujuan
- Pelajari cara menerapkan teknik pengembangan dasar untuk menerapkan aturan dan mekanisme game untuk game UWP DirectX.
Objek permainan utama
Dalam game sampel simple3DGameDX
Berikut adalah beberapa fitur dari kelas Simple3DGame.
- Berisi implementasi logika permainan.
- Berisi metode yang mengomunikasikan detail ini.
- Perubahan pada status permainan ke mesin status yang ditentukan dalam kerangka kerja aplikasi.
- Perubahan status game dari aplikasi ke objek game itu sendiri.
- Detail-detail untuk memperbarui antarmuka pengguna (UI) gim (tampilan overlay dan display heads-up), animasi, dan fisika (dinamika).
Nota
Pembaruan grafis ditangani oleh kelas GameRenderer, yang berisi metode untuk mendapatkan dan menggunakan sumber daya perangkat grafis yang digunakan oleh game. Untuk informasi selengkapnya, lihat Kerangka Kerja Rendering I: Pengantar Render.
- Berfungsi sebagai kontainer untuk data yang mendefinisikan sesi permainan, tingkat, atau masa pakai, tergantung pada bagaimana Anda menentukan permainan Anda pada tingkat tinggi. Dalam hal ini, data status game adalah untuk masa pakai game, dan diinisialisasi satu kali ketika pengguna meluncurkan game.
Untuk melihat metode dan data yang ditentukan oleh kelas ini, lihat kelas Simple3DGame di bawah ini.
Menginisialisasi dan memulai permainan
Ketika pemain memulai permainan, objek game harus menginisialisasi statusnya, membuat dan menambahkan overlay, mengatur variabel yang melacak performa pemain, dan membuat instans objek yang akan digunakan untuk membangun level. Dalam sampel ini, ini dilakukan ketika instance GameMain dibuat di App::Load.
Objek game, dari jenis
Metode Simple3DGame::Initialize
Contoh permainan menyiapkan komponen-komponen ini di objek game.
- Objek pemutaran audio baru dibuat.
- Array untuk primitif grafis game dibuat, termasuk array untuk tingkat primitif, amunisi, dan rintangan.
- Lokasi untuk menyimpan data status game dibuat, bernama Game, dan ditempatkan di lokasi penyimpanan pengaturan data aplikasi yang ditentukan oleh ApplicationData::Current.
- Sebuah timer permainan dan bitmap overlay awal di dalam game dibuat.
- Kamera baru dibuat dengan serangkaian parameter tampilan dan proyeksi tertentu.
- Perangkat input (pengontrol) diatur pada sudut pitch dan yaw awal yang sama dengan kamera, sehingga pemain memiliki korespondensi 1-ke-1 antara posisi kontrol awal dan posisi kamera.
- Objek pemain dibuat dan diaktifkan. Kami menggunakan objek bola untuk mendeteksi kedekatan pemain dengan dinding dan rintangan, serta agar kamera tidak ditempatkan di posisi yang bisa merusak imersi.
- Elemen dasar dunia game telah dibuat.
- Rintangan silinder dibuat.
- Target (Face objek) dibuat dan diberi nomor.
- Bola peluru amunisi dibuat.
- Tingkatan telah dibuat.
- Skor tertinggi telah dimuat.
- Status permainan tersimpan sebelumnya dimuat.
Gim ini sekarang memiliki contoh semua komponen utama—dunia, pemain, rintangan, target, dan bola amunisi. Ini juga memiliki instansi level, yang mewakili konfigurasi semua komponen yang telah disebutkan di atas dan perilakunya untuk setiap level spesifik. Sekarang mari kita lihat bagaimana permainan membangun level.
Membangun dan memuat tingkat permainan
Sebagian besar pekerjaan berat untuk pembangunan level dilakukan dalam file Level[N].h/.cpp
yang ditemukan di folder GameLevels contoh solusi. Karena berfokus pada implementasi yang sangat spesifik, kami tidak akan membahasnya di sini. Yang penting adalah bahwa kode untuk setiap tingkat dijalankan sebagai objek Level[N] terpisah. Jika Anda ingin memperluas permainan, Anda dapat membuat objek Level[N]
Tentukan gameplay
Pada titik ini, kita memiliki semua komponen yang kita butuhkan untuk mengembangkan permainan. Level-level telah dibangun dalam memori dari elemen primitif, dan siap bagi pemain untuk mulai berinteraksi.
Game terbaik bereaksi langsung terhadap input pemain, dan memberikan umpan balik langsung. Ini berlaku untuk semua jenis permainan, mulai dari penembak orang pertama real time yang aksi cepat hingga game strategi berbasis giliran yang memerlukan pemikiran mendalam.
Metode Simple3DGame::RunGame
Saat tingkat permainan sedang berlangsung, game berada pada status Dynamics.
GameMain::Update adalah loop pembaruan utama yang memperbarui status aplikasi satu kali per frame, seperti yang ditunjukkan di bawah ini. Perulangan pembaruan memanggil metode Simple3DGame::RunGame untuk menangani pekerjaan jika game berada dalam status Dynamics.
// Updates the application state once per frame.
void GameMain::Update()
{
// The controller object has its own update loop.
m_controller->Update();
switch (m_updateState)
{
...
case UpdateEngineState::Dynamics:
if (m_controller->IsPauseRequested())
{
...
}
else
{
// When the player is playing, work is done by Simple3DGame::RunGame.
GameState runState = m_game->RunGame();
switch (runState)
{
...
Simple3DGame::RunGame menangani kumpulan data yang menentukan status permainan saat ini untuk iterasi perulangan game saat ini.
Berikut adalah logika alur game di Simple3DGame::RunGame.
- Metode memperbarui timer yang menghitung mundur detik hingga level selesai, dan memeriksa apakah waktu level telah habis. Ini adalah salah satu aturan permainan —ketika waktu habis, jika tidak semua target telah ditembak, maka permainan berakhir.
- Jika waktu telah habis, maka metode menentukan status permainan TimeExpired, dan kembali ke metode Update di kode sebelumnya.
- Jika waktu masih ada, pengontrol gerak-lihat akan dijajaki untuk pembaruan posisi kamera; secara khusus, pembaruan pada sudut pandangan dari proyeksi normal dari bidang kamera (ke arah mana pemain melihat), dan jarak yang telah dipindahkan sudut tersebut sejak terakhir kali pengontrol dijajaki.
- Kamera diperbarui berdasarkan data baru dari pengontrol tampilan gerak.
- Dinamika, atau animasi dan perilaku objek di dunia game yang independen dari kontrol pemain, diperbarui. Dalam permainan sampel ini, metode Simple3DGame::UpdateDynamics dipanggil untuk memperbarui gerakan bola amunisi yang telah ditembakkan, animasi rintangan pilar dan pergerakan target. Untuk informasi selengkapnya, silakan lihat Memperbarui dunia permainan.
- Metode memeriksa apakah kriteria untuk keberhasilan penyelesaian tingkat telah terpenuhi. Jika demikian, sistem menyelesaikan skor untuk level tersebut, dan memeriksa apakah ini adalah level terakhir (dari 6). Jika ini adalah level terakhir, maka metode mengembalikan status game GameState::GameComplete; jika tidak, ia mengembalikan status permainan GameState::LevelComplete.
- Jika level tidak selesai, maka metode mengatur status game ke GameState::Active, dan kembali.
Memperbarui dunia game
Dalam sampel ini, ketika permainan berjalan, metode Simple3DGame::UpdateDynamics dipanggil dari metode Simple3DGame::RunGame (yang dipanggil dari GameMain::Update) untuk memperbarui objek yang dirender dalam adegan game.
Perulangan seperti UpdateDynamics memanggil metode apa pun yang digunakan untuk mengatur dunia game bergerak secara terlepas dari input pemain, menciptakan pengalaman permainan yang imersif dan menghidupkan level. Ini termasuk grafik yang harus dirender, dan menjalankan perulangan animasi untuk menghadirkan dunia dinamis bahkan ketika tidak ada input pemain. Dalam permainan Anda, itu bisa termasuk pohon yang bergoyang di angin, ombak yang menggulung di sepanjang garis pantai, mesin yang mengeluarkan asap, dan monster alien yang membentang dan bergerak. Ini juga mencakup interaksi antara objek, termasuk tabrakan antara bola pemain dan lingkungan, atau antara amunisi dengan rintangan dan target.
Kecuali ketika permainan dijeda secara khusus, perulangan permainan harus terus memperbarui dunia game; apakah itu didasarkan pada logika permainan, algoritma fisik, atau apakah itu hanya acak biasa.
Dalam permainan contoh, prinsip ini disebut dinamika, dan mencakup naik dan jatuhnya rintangan pilar, serta gerakan dan perilaku fisik peluru selama penembakan dan pergerakan.
Metode Simple3DGame::UpdateDynamics
Metode ini berkaitan dengan empat set komputasi ini.
- Lokasi bola peluru amunisi yang ditembakkan di dunia.
- Animasi dari rintangan pilar.
- Titik persilangan pemain dan batas dunia.
- Tabrakan bola amunisi dengan rintangan, target, bola amunisi lainnya, dan lingkungan sekitarnya.
Animasi rintangan terjadi dalam perulangan yang ditentukan dalam file kode sumber Animate.h/.cpp. Perilaku amunisi dan tabrakan didefinisikan oleh algoritma fisika yang disederhanakan, disediakan dalam kode dan diparameterkan oleh serangkaian konstanta global untuk dunia game, termasuk gravitasi dan properti material. Ini semua dihitung dalam ruang koordinat dunia game.
Meninjau alur
Sekarang setelah kita memperbarui semua objek dalam adegan, dan menghitung tabrakan apa pun, kita perlu menggunakan info ini untuk menggambar perubahan visual yang sesuai.
Setelah GameMain::Update telah menyelesaikan iterasi perulangan game saat ini, sampel segera memanggil GameRenderer::Render untuk mengambil data objek yang diperbarui dan menghasilkan adegan baru untuk disajikan kepada pemain, seperti yang ditunjukkan di bawah ini.
void GameMain::Run()
{
while (!m_windowClosed)
{
if (m_visible)
{
switch (m_updateState)
{
case UpdateEngineState::Deactivated:
case UpdateEngineState::TooSmall:
...
// Otherwise, fall through and do normal processing to perform rendering.
default:
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(
CoreProcessEventsOption::ProcessAllIfPresent);
// GameMain::Update calls Simple3DGame::RunGame. If game is in Dynamics
// state, uses Simple3DGame::UpdateDynamics to update game world.
Update();
// Render is called immediately after the Update loop.
m_renderer->Render();
m_deviceResources->Present();
m_renderNeeded = false;
}
}
else
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(
CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
m_game->OnSuspending(); // Exiting due to window close, so save state.
}
Menampilkan grafik dunia game
Kami menyarankan agar grafik dalam sebuah game diperbarui secara sering, idealnya dengan frekuensi yang sama persis dengan perulangan utama game tersebut terjadi. Saat perulangan berulang, status dunia game diperbarui, dengan atau tanpa input pemain. Ini memungkinkan animasi dan perilaku terhitung ditampilkan dengan lancar. Bayangkan jika kita memiliki adegan air sederhana yang bergerak hanya ketika pemain menekan tombol. Itu tidak akan realistis; Permainan yang bagus terlihat halus dan lancar sepanjang waktu.
Ingat siklus permainan sampel sebagaimana yang ditunjukkan di atas dalam GameMain::Run. Jika jendela utama game terlihat, dan tidak di-snap atau dinonaktifkan, maka game terus memperbarui dan merender hasil pembaruan tersebut. Metode GameRenderer::Render yang kita periksa berikutnya merender representasi dari keadaan tersebut. Ini dilakukan segera setelah panggilan ke GameMain::Update, yang mencakup Simple3DGame::RunGame untuk memperbarui status, sebagaimana dibahas di bagian sebelumnya.
GameRenderer::Render menampilkan proyeksi dunia 3D, dan kemudian menampilkan overlay Direct2D di atasnya. Setelah selesai, ini menyajikan rantai pertukaran akhir dengan buffer gabungan untuk ditampilkan.
Nota
Ada dua status untuk overlay Direct2D permainan sampel—satu di mana permainan menampilkan overlay info game yang berisi bitmap untuk menu jeda, dan satu di mana permainan menampilkan crosshair beserta persegi panjang sebagai pengontrol untuk gerak-lihat di layar sentuh. Teks skor ditampilkan di kedua keadaan. Untuk informasi selengkapnya, lihat Rendering framework I: Pengenalan ke rendering.
Metode GameRenderer::Render
void GameRenderer::Render()
{
bool stereoEnabled{ m_deviceResources->GetStereoState() };
auto d3dContext{ m_deviceResources->GetD3DDeviceContext() };
auto d2dContext{ m_deviceResources->GetD2DDeviceContext() };
...
if (m_game != nullptr && m_gameResourcesLoaded && m_levelResourcesLoaded)
{
// This section is only used after the game state has been initialized and all device
// resources needed for the game have been created and associated with the game objects.
...
for (auto&& object : m_game->RenderObjects())
{
object->Render(d3dContext, m_constantBufferChangesEveryPrim.get());
}
}
d3dContext->BeginEventInt(L"D2D BeginDraw", 1);
d2dContext->BeginDraw();
// To handle the swapchain being pre-rotated, set the D2D transformation to include it.
d2dContext->SetTransform(m_deviceResources->GetOrientationTransform2D());
if (m_game != nullptr && m_gameResourcesLoaded)
{
// This is only used after the game state has been initialized.
m_gameHud.Render(m_game);
}
if (m_gameInfoOverlay.Visible())
{
d2dContext->DrawBitmap(
m_gameInfoOverlay.Bitmap(),
m_gameInfoOverlayRect
);
}
...
}
}
Kelas Simple3DGame
Ini adalah metode dan anggota data yang ditentukan oleh kelas Simple3DGame.
Fungsi anggota
Fungsi anggota publik yang ditentukan oleh Simple3DGame mencakup yang di bawah ini.
- Inisialisasi. Mengatur nilai awal variabel global, dan menginisialisasi objek game. Ini tercakup dalam bagian Inisialisasi dan memulai permainan.
- LoadGame. Menginisialisasi level baru dan mulai memuatnya.
- LoadLevelAsync. Koroutine yang menginisialisasi level, lalu memanggil koroutine lain di perender untuk memuat sumber daya level yang khusus untuk perangkat. Metode ini berjalan dalam utas terpisah; akibatnya, hanya metode ID3D11Device (dibandingkan dengan metode ID3D11DeviceContext) yang dapat dipanggil dari utas ini. Metode konteks perangkat apa pun dipanggil dalam metode FinalizeLoadLevel. Jika Anda baru menggunakan pemrograman asinkron, maka lihat Konkurensi dan operasi asinkron dengan C++/WinRT.
- FinalizeLoadLevel. Menyelesaikan pekerjaan apa pun untuk distribusi beban yang harus dilakukan pada utas utama. Ini termasuk segala panggilan ke metode konteks perangkat Direct3D 11 (ID3D11DeviceContext).
- StartLevel. Memulai permainan untuk level baru.
- JedaGame. Menjeda permainan.
- RunGame. Menjalankan iterasi dari siklus permainan. Ini dipanggil sekali dari App::Update setiap iterasi perulangan game jika status game adalah Active.
- OnSuspending dan OnResuming. Tangguhkan/lanjutkan audio permainan.
Berikut adalah fungsi anggota pribadi.
- LoadSavedState dan SaveState. Muat/simpan status permainan saat ini.
- LoadHighScore dan SaveHighScore. Muat/simpan skor tertinggi masing-masing antar beberapa game.
- InitializeAmmo. Mengatur ulang status setiap objek bola yang digunakan sebagai amunisi kembali ke status aslinya untuk awal setiap putaran.
- UpdateDynamics. Ini adalah metode penting karena memperbarui semua objek game berdasarkan rutinitas animasi siap pakai, simulasi fisika, dan input kontrol. Ini adalah inti dari interaktivitas yang mendefinisikan permainan. Ini tercakup di bagian Memperbarui dunia game.
Metode publik lainnya adalah aksesor properti yang mengembalikan informasi khusus gameplay dan overlay ke kerangka kerja aplikasi untuk ditampilkan.
Anggota data
Objek-objek ini diperbarui saat perulangan permainan berjalan.
- MoveLookController objek. Mewakili input pemain. Untuk informasi selengkapnya, lihat Menambahkan kontrol.
- objek GameRenderer. Mewakili renderer Direct3D 11, yang menangani semua objek yang spesifik untuk perangkat dan proses rendering-nya. Untuk informasi selengkapnya, lihat Kerangka Rendering I.
- Objek Audio. Mengontrol pemutaran audio untuk permainan. Untuk informasi selengkapnya, lihat Menambahkan suara.
Variabel permainan lainnya berisi daftar primitif, jumlah masing-masing dalam game, serta data dan batasan spesifik permainan.
Langkah selanjutnya
Kami belum berbicara tentang mesin rendering aktual—bagaimana panggilan ke metode Render pada primitif yang telah diperbarui diubah menjadi piksel di layar Anda. Aspek-aspek tersebut tercakup dalam dua bagian—Rendering framework I: Intro untuk merender dan Rendering framework II: Rendering game. Jika Anda lebih tertarik dengan bagaimana kontrol pemain memperbarui status permainan, lihat Menambahkan kontrol.