Aracılığıyla paylaş


Ana oyun nesnesini tanımlama

Uyarı

Bu konu, DirectX öğretici serisi ile basit bir Evrensel Windows Platformu (UWP) oluşturma oyunun bir parçasıdır. Bu bağlantıdaki konu başlığı, serinin bağlamını ayarlar.

Örnek oyunun temel çerçevesini ortaya koyduktan ve üst düzey kullanıcı ve sistem davranışlarını işleyen bir durum makinesi uyguladıktan sonra, örnek oyunu bir oyuna dönüştüren kuralları ve mekanikleri incelemek isteyeceksiniz. Şimdi örnek oyunun ana nesnesinin ayrıntılarına ve oyun kurallarını oyun dünyası ile etkileşimlere nasıl çevireceklerine bakalım.

Hedef

  • Bir UWP DirectX oyunu için oyun kuralları ve mekanikleri uygulamak için temel geliştirme tekniklerini uygulamayı öğrenin.

Ana oyun nesnesi

Simple3DGameDX örnek oyunda, simple3DGame ana oyun nesne sınıfıdır. Simple3DGame örneği, App::Load yöntemi aracılığıyla dolaylı olarak oluşturulur.

İşte Simple3DGame sınıfının bazı özellikleri.

  • Oyun mantığının uygulanmasını içerir.
  • Bu ayrıntıları bildiren yöntemleri içerir.
    • Uygulama çerçevesinde tanımlanan durum makinesinde oyun durumundaki değişiklikler.
    • Uygulamadaki oyun durumu değişiklikleri, doğrudan oyun nesnesine aktarılır.
    • Oyunun kullanıcı arabirimini (katman ve uyarı ekranı), animasyonları ve fiziği (dinamikler) güncelleştirme ayrıntıları.

    Uyarı

    Grafiklerin güncelleştirilmesi, oyun tarafından kullanılan grafik cihaz kaynaklarını elde etme ve kullanma yöntemlerini içeren GameRenderer sınıfı tarafından işlenir. Daha fazla bilgi için bkz. İşleme çerçevesi I: İşlemeye giriş.

  • Oyununuzu yüksek düzeyde nasıl tanımladığınıza bağlı olarak oyun oturumunu, düzeyini veya ömrünü tanımlayan veriler için kapsayıcı görevi görür. Bu durumda, oyun durumu verileri oyunun ömrüne yöneliktir ve bir kullanıcı oyunu başlattığında bir kez başlatılır.

Bu sınıf tarafından tanımlanan yöntemleri ve verileri görüntülemek için aşağıdaki Simple3DGame sınıfı bakın.

Oyunu başlatmak ve başlamak

Bir oyuncu oyunu başlattığında, oyun nesnesi durumunu başlatmalı, katman oluşturup eklemeli, oyuncunun performansını izleyen değişkenleri ayarlamalı ve düzeyleri oluşturmak için kullanacağı nesnelerin örneğini oluşturmalıdır. Bu örnek içinde, GameMain örneği App::Loadiçinde oluşturulduğunda yapılmaktadır.

Simple3DGametüründe oyun nesnesi, GameMain::GameMain oluşturucusunda oluşturulur. Ardından, GameMain::ConstructInBackground fire-and-forget coroutine sırasında Simple3DGame::Initialize yöntemi kullanılarak başlatılır. Bu yöntem, GameMain::GameMainöğesinden çağrılır.

Simple3DGame::Initialize yöntemi

Örnek oyun, bu bileşenleri oyun nesnesinde ayarlar.

  • Yeni bir ses oynatma nesnesi oluşturulur.
  • Oyunun grafiksel ilkel öğelerinin dizileri oluşturulur; bunlar arasında seviye ilkelleri, cephane ve engeller için diziler de bulunur.
  • Oyun durumu verilerini kaydetmek için Gameadlı bir konum oluşturulur ve ApplicationData::Currenttarafından belirtilen uygulama veri ayarları depolama konumuna yerleştirilir.
  • Bir oyun zamanlayıcı ve ilk oyun içi katman bit eşlemi oluşturulur.
  • Belirli bir görünüm ve projeksiyon parametreleri kümesiyle yeni bir kamera oluşturulur.
  • Giriş cihazı (denetleyici) kamerayla aynı başlangıç perdesine ve esnemeye ayarlanmıştır, bu nedenle oyuncunun başlangıç kontrol konumu ile kamera konumu arasında 1-1 arası bir yazışması vardır.
  • Player nesnesi oluşturulur ve etkin olarak ayarlanır. Oyuncunun duvarlara ve engellere yakın olduğunu algılamak ve kameranın daldırılmayı engelleyebilecek bir konuma yerleştirilmesini sağlamak için bir küre nesnesi kullanırız.
  • Oyun dünyası ilkel oluşturulur.
  • Silindir engelleri oluşturulur.
  • Hedefler (yüz nesneleri) oluşturulur ve numaralandırılır.
  • Cephane küreleri oluşturulmuştur.
  • Düzeyler oluşturulur.
  • Yüksek puan yüklenir.
  • Önceden kaydedilmiş tüm oyun durumları yüklenir.

Oyun artık dünya, oyuncu, engeller, hedefler ve cephane küreleri gibi tüm önemli bileşenlerin örneklerine sahiptir. Ayrıca, yukarıdaki bileşenlerin tümünün yapılandırmalarını ve her belirli düzey için davranışlarını temsil eden düzeylerin örneklerine de sahiptir. Şimdi oyunun seviyeleri nasıl oluşturduğunu görelim.

Oyun düzeylerini oluşturma ve yükleme

Seviye inşasının en önemli kısmı, örnek uygulamanın Level[N].h/.cpp klasöründe bulunan dosyalarında yapılır. Çok belirli bir uygulamaya odaklandığından, bunları burada kapsamayacağız. Önemli olan, her düzeyin kodunun ayrı bir Düzeyi[N] nesnesi olarak çalıştırılmasıdır. Oyunu genişletmek isterseniz, atanmış bir sayıyı parametre olarak alan ve engelleri ve hedefleri rastgele yerleştiren bir Düzeyi[N] nesnesi oluşturabilirsiniz. Alternatif olarak, bir kaynak dosyasından veya hatta İnternet'ten yük düzeyi yapılandırma verilerine de sahip olabilirsiniz.

Oyun oynanışını tanımlama

Bu noktada, oyunu geliştirmek için ihtiyacımız olan tüm bileşenlere sahibiz. Düzeyler ilkel öğelerden bellekte oluşturuldu ve oyuncunun etkileşime başlaması için hazır.

En iyi oyunlar oyuncu girişine anında tepki verir ve anında geri bildirim sağlar. Bu, hızlı aksiyon, gerçek zamanlı birinci şahıs nişancı oyunlarından, düşünceli sıra tabanlı strateji oyunlarına kadar her tür oyun için geçerlidir.

Simple3DGame::RunGame yöntemi

Oyun düzeyi devam ederken, oyun Dynamics durumundadır.

GameMain::Update, aşağıda gösterildiği gibi uygulama durumunu çerçeve başına bir kez güncelleştiren ana güncelleştirme döngüsüdür. Güncelleştirme döngüsü, oyun Dynamics durumundaysa işi işlemek için Simple3DGame::RunGame yöntemini çağırır.

// 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, oyun döngüsünün geçerli yinelemesi için oyunun geçerli durumunu tanımlayan veri kümesini işler.

simple3DGame::RunGameoyun akışı mantığı aşağıda verilmişti.

  • yöntemi, düzey tamamlanana kadar saniyeleri sayan zamanlayıcıyı güncelleştirir ve düzeyin süresinin dolup dolmadığını test eder. Bu, oyunun kurallarından biridir; zaman dolduğunda, tüm hedefler vurulmadıysa oyun biter.
  • Süre dolduysa, yöntem TimeExpired oyun durumunu ayarlar ve önceki kodda yer alan Update yöntemine döner.
  • Süre kalırsa, hareket-görüş denetleyicisi kamera konumunu güncellemek için yoklanır; özellikle, kameradan çıkan normal görünüm açısının güncellenmesi (oyuncunun baktığı yer) ve denetleyicinin son yoklanmasından beri bu açının hareket ettiği mesafe.
  • Kamera, hareket-görünüm denetleyicisinden gelen yeni verilere göre güncellenir.
  • Oyun dünyasındaki nesnelerin dinamikleri veya animasyonları ve davranışları oyuncu denetiminden bağımsız olarak güncelleştirilir. Bu örnek oyunda, Simple3DGame::UpdateDynamics yöntemi, ateşlenen mermi kürelerinin hareketini, sütun engellerinin animasyonunu ve hedeflerin hareketini güncelleştirmek için çağrılır. Daha fazla bilgi için bkz. Oyun dünyasını güncelleştirme.
  • yöntemi, bir düzeyin başarıyla tamamlanması için ölçütlerin karşılanıp karşılanmadığını denetler. Eğer öyleyse, seviyenin puanını tamamlar ve bunun 6 seviyeden sonuncusu olup olmadığını kontrol eder. Eğer son seviyedeyse, yöntem GameState::GameComplete oyun durumunu döndürür; aksi takdirde, GameState::LevelComplete oyun durumunu döndürür.
  • Düzey tamamlanmazsa, yöntem oyun durumunu GameState::Activeolarak ayarlar ve döndürür.

Oyun dünyasını güncelleştirme

Bu örnekte, oyun çalışırken, Simple3DGame::UpdateDynamics yöntemi, bir oyun sahnesinde işlenen nesneleri güncelleştirmek için Simple3DGame::RunGame yönteminden (GameMain::Update) çağrılır.

UpdateDynamics gibi bir döngü, oyuncu girişlerinden bağımsız olarak oyun dünyasını harekete geçirip etkileyici bir oyun deneyimi oluşturmak ve seviyeyi canlandırmak için kullanılan tüm yöntemleri çağırır. Bu, işlenmesi gereken grafikleri ve oyuncu girişi olmadığında bile dinamik bir dünyayı ortaya çıkarmak için animasyon döngüleri çalıştırmayı içerir. Oyununuzda, rüzgarda sallanan ağaçlar, kıyı boyunca kabaran dalgalar, makinelerin dumanı ve uzaylı yaratıkların gerilip hareket ettiği olabilir. Ayrıca, oyuncu küresi ile dünya arasındaki çarpışmalar veya cephane ile engeller ve hedefler arasındaki çarpışmalar dahil olmak üzere nesneler arasındaki etkileşimi de kapsar.

Oyunun özellikle duraklatılması dışında, oyun döngüsü oyun dünyasını güncelleştirmeye devam etmelidir; bunun oyun mantığına, fiziksel algoritmalara veya yalnızca rastgele olmasına bağlı olup olmadığı.

Örnek oyunda, bu ilke dinamikleriolarak adlandırılır ve sütun engellerinin yükselip alçalmasını ile cephane kürelerinin ateşlenmeleri ve hareket etmeleri sırasındaki hareket ve fiziksel davranışlarını kapsar.

Simple3DGame::UpdateDynamics yöntemi

Bu yöntem, bu dört hesaplama kümesiyle ilgilenir.

  • Ateşlenen cephane kürelerinin dünyadaki konumları.
  • Sütun engelleri animasyonu.
  • Oyuncu ile dünya sınırlarının kesişme noktası.
  • Cephane kürelerinin engellerle, hedeflerle, diğer cephane küreleriyle ve dünyayla çarpışmaları.

Engellerin animasyonu, Animate.h/.cpp kaynak kod dosyalarında tanımlanan bir döngüde gerçekleşir. Merminin hareket biçimi ve çarpışmalar sırasında meydana gelen olaylar, kodda sağlanan ve yerçekimi ile malzeme nitelikleri dahil olmak üzere oyun dünyası için bir dizi küresel sabit ile belirlenen basitleştirilmiş fizik algoritmalarıyla tanımlanır. Bunların hepsi oyun dünyası koordinat alanında hesaplanır.

Akışı gözden geçirme

Artık sahnedeki tüm nesneleri güncelleştirdiğimize ve çakışmaları hesapladığımıza göre, ilgili görsel değişiklikleri çizmek için bu bilgileri kullanmamız gerekir.

GameMain::Update oyun döngüsünün geçerli yinelemesini tamamladıktan sonra örnek, güncelleştirilmiş nesne verilerini almak ve aşağıda gösterildiği gibi oyuncuya sunmak üzere yeni bir sahne oluşturmak için GameRenderer::Render hemen çağırır.

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.
}

Oyun dünyasının grafiklerini işleme

Oyundaki grafiklerin, güncellemeler sırasında genellikle, ideal olarak ana oyun döngüsünün geçtiği sıklıkta yenilenmesini öneririz. Döngü yinelendikçe, oyun dünyasının durumu oyuncu girişiyle veya girişi olmadan güncelleştirilir. Bu, hesaplanan animasyonların ve davranışların sorunsuz görüntülenmesini sağlar. Sadece oyuncu bir düğmeye bastığında hareket eden basit bir su sahnesi olduğunu düşünün. Bu gerçekçi olmaz; iyi bir oyun her zaman pürüzsüz ve akıcı görünüyor.

yukarıda GameMain::Runbölümünde gösterildiği gibi örnek oyunun döngüsünü hatırlayın. Oyunun ana penceresi görünür durumda ise, kenetlenmediyse ve devre dışı değilse, oyun güncellenmeye ve bu güncellemenin sonuçlarını görüntülemeye devam eder. GameRenderer::Render yöntemini incelediğimizde, bu durumun bir gösterimini oluşturur. Bu, önceki bölümde açıklandığı gibi, Simple3DGame::RunGame güncelleştirme durumlarını içeren GameMain::Updateçağrısından hemen sonra yapılır.

GameRenderer::Render, 3B dünyanın projeksiyonunu çizer ve ardından üzerine Direct2D katmanını çizer. Tamamlandığında, nihai takas zincirini, birleştirilmiş arabelleklerle gösterim için hazır olarak sunar.

Uyarı

Örnek oyunun Direct2D katmanı için iki durum vardır: Biri oyunun duraklatma menüsünün bit eşlemini içeren oyun bilgisi katmanını gösterdiği durumdur, diğeri ise oyunun dokunmatik ekran hareket-görünüm denetleyicisinin dikdörtgenleriyle birlikte nişangahı gösterdiği durumu ifade eder. Puan metni her iki durumda da çizilir. Daha fazla bilgi için bkz. İşleme çerçevesi I:işlemeye giriş.

GameRenderer::Render yöntemi

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

Simple3DGame sınıfı

Bunlar, Simple3DGame sınıfı tarafından tanımlanan yöntemler ve veri üyeleridir.

Üye işlevleri

Simple3DGame tarafından tanımlanan genel üye işlevleri aşağıdakileri içerir.

  • başlat. Genel değişkenlerin başlangıç değerlerini ayarlar ve oyun nesnelerini başlatır. Bu, Başlatma ve oyun başlatma bölümünde ele alınmıştır.
  • LoadGame. Yeni bir seviye başlatır ve yüklemeye başlar.
  • LoadLevelAsync. Düzeyi başlatan ve ardından cihaza özgü düzey kaynaklarını yüklemek için rendering işlevinde başka bir eş yordam çağıran bir coroutine. Bu yöntem ayrı bir iş parçacığında çalışır; Sonuç olarak, bu iş parçacığından yalnızca ID3D11Device yöntemleri (ID3D11DeviceContext yöntemleri yerine) çağrılabilir. Tüm cihaz bağlam yöntemleri FinalizeLoadLevel yönteminde çağrılır. Zaman uyumsuz programlama konusunda yeniyseniz, C++/WinRT ile eşzamanlılık ve zaman uyumsuz işlemleröğesine bakın.
  • FinalizeLoadLevel. Ana iş parçacığında yapılması gereken tüm seviye yükleme çalışmalarını tamamlar. Bu, Direct3D 11 cihaz bağlamı (ID3D11DeviceContext) yöntemlerine yapılan çağrıları içerir.
  • StartLevel . Yeni bir düzey için oyun başlatır.
  • PauseGame. Oyunu duraklatır.
  • RunGame. Oyun döngüsünün yinelemesini çalıştırır. App::Update, oyun durumu Activeiken oyun döngüsünün her yinelemesinde bir kez çağrılır.
  • OnSuspending veOnResuming . Sırasıyla oyunun sesini askıya alın/devam ettirin.

Özel üye işlevleri aşağıdadır.

  • LoadSavedState ve SaveState. Sırasıyla oyunun geçerli durumunu yükleyin/kaydedin.
  • LoadHighScore ve SaveHighScore. Oyunlar arasında sırasıyla yüksek puanı yükleyin/kaydedin.
  • InitializeAmmo. Mühimmat olarak kullanılan her küre nesnesinin durumunu, her turun başlangıcı için orijinal durumuna geri sıfırlar.
  • UpdateDynamics. Bu önemli bir yöntemdir çünkü tüm oyun nesnelerini önceden tanımlanmış animasyon rutinleri, fizik ve kontrol girdilerine göre günceller. Bu, oyunu tanımlayan etkileşimin kalbidir. Bu, Oyun dünyasını güncelleştirme bölümünde ele alınmıştır.

Diğer genel yöntemler, oyuna ve katmana özgü bilgileri görüntülemek üzere uygulama çerçevesine döndüren özellik erişimcileridir.

Veri üyeleri

Bu nesneler, oyun döngüsü çalıştırıldığında güncelleştirilir.

  • MoveLookController nesnesi. Oyuncu girişini temsil eder. Daha fazla bilgi için bkz. denetim ekleme.
  • GameRenderer nesnesini . Cihaza özgü tüm nesneleri ve bunların işlenmesini işleyen bir Direct3D 11 işleyicisini temsil eder. Daha fazla bilgi için bkz. Render çerçevesi.
  • Ses nesnesi. Oyunun ses oynatımını kontrol eder. Daha fazla bilgi için bkz. Ek ses ekleme.

Oyun değişkenlerinin geri kalanı, ilkellerin ve bunların ilgili oyun içi miktarlarının listesini ve oyun oynamanın belirli verilerini ve kısıtlamalarını içerir.

Sonraki Adımlar

Gerçek işleme altyapısı hakkında henüz konuşmadık; güncelleştirilmiş temel öğelerdeki render yöntemlerine yapılan çağrıların ekranınızdaki piksellere nasıl dönüştürülmesi. Bu özellikler iki bölümde ele alınmıştır:İşleme çerçevesi I: işlemeye giriş ve İşleme çerçevesi II: Oyun işleme. Oyuncu denetimlerinin oyun durumunu nasıl güncelleştirdiğini daha çok merak ediyorsanız bkz. Denetim ekleme.