最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

如何從零開始用 C++ 開發(fā)一款游戲引擎?

2022-06-02 18:48 作者:C語言編程__Plus  | 我要投稿

原文鏈接:https://hackernoon.com/build-a-game-engine-from-scratch-in-c

游戲開發(fā)一直很能激勵學(xué)生學(xué)習(xí)高級計算機科學(xué)??赡苡行┤苏J(rèn)為游戲是孩子們喜歡的,但對于標(biāo)準(zhǔn)的計算機科學(xué)課程來說,游戲開發(fā)其實是少數(shù)幾個能利用當(dāng)中所有知識的領(lǐng)域。


游戲開發(fā)涉及標(biāo)準(zhǔn)計算機科學(xué)課程中的諸多內(nèi)容

根據(jù)游戲的性質(zhì),你可能還需要深入到更具體的專業(yè),比如分布式系統(tǒng)或人機交互。游戲開發(fā)是一項嚴(yán)肅的工作,是助力計算機科學(xué)理念學(xué)習(xí)的有力工具。

本文將詳細(xì)介紹使用C++創(chuàng)建一款簡單游戲引擎所需的一些基本構(gòu)建模塊,解釋游戲引擎所需的主要組成元素,并就如何從零開始編寫游戲引擎給出一些個人建議。

不過,本文不是一個編程教程,因此也不會深入太多的技術(shù)細(xì)節(jié)或解釋所有這些元素是如何通過代碼粘合在一起的。如果你想找關(guān)于如何編寫C++游戲引擎的綜合性教程,可以先看看《用C++和Lua創(chuàng)建一個2D游戲引擎》。


一、游戲引擎是什么?

概括地講,游戲引擎是一套優(yōu)化視頻游戲開發(fā)的軟件工具。這些引擎可以是小而極簡型的,簡單到只提供一個游戲循環(huán)和幾個渲染功能;當(dāng)然,也可以是大而全面型的,類似于IDE應(yīng)用程序那種,開發(fā)人員可以用于編寫腳本、調(diào)試、自定義關(guān)卡邏輯、人工智能、設(shè)計、發(fā)布、協(xié)作,并最終從頭到尾構(gòu)建游戲,而無需離開引擎。

游戲引擎和游戲框架通常向用戶公開一組API。這些API允許程序員調(diào)用引擎函數(shù),并像執(zhí)行黑匣子一樣執(zhí)行艱難的任務(wù)。

為了真正理解這些API是如何工作的,讓我們更具體地結(jié)合應(yīng)用說明一下。例如,游戲引擎API公開一個名為“IsColliding()”的函數(shù),開發(fā)者可以調(diào)用該函數(shù)來檢查兩個游戲?qū)ο笫欠癜l(fā)生碰撞,這種情況并不罕見。程序員不需要知道該函數(shù)是如何實現(xiàn)的,也不需要知道正確確定兩個形狀是否重疊所需的算法。就我們而言,IsColliding函數(shù)僅是一個黑匣子,根據(jù)這些對象是否相互碰撞,它會正確地返回true或false。下面是大多數(shù)游戲引擎向用戶公開的一個功能示例。


大多數(shù)引擎都會抽象碰撞檢測,并簡單地將其作為真/假函數(shù)公開

除了編程API,游戲引擎的另一個重要職責(zé)是硬件抽象。例如,3D引擎通常構(gòu)建在一個專用的圖形API上,比如OpenGL、Vulkan或Direct3D。這些API為圖形處理單元(GPU)提供了軟件抽象。

說到硬件抽象,還有一些底層庫(如DirectX、OpenAL和SDL),它們提供對許多其他硬件元素的抽象以及多平臺訪問。這些庫幫助我們訪問和處理鍵盤事件、鼠標(biāo)移動、網(wǎng)絡(luò)連接,甚至音頻等各項功能。


二、游戲引擎的崛起

在游戲行業(yè)的早期,游戲是使用定制的渲染引擎構(gòu)建的。開發(fā)代碼是為了從較慢的機器中盡可能多地提升部分系統(tǒng)性能。每個CPU周期都至關(guān)重要,因此代碼重用或適用于多種場景的通用函數(shù)并不是開發(fā)人員能夠負(fù)擔(dān)得起的。

隨著游戲和開發(fā)團(tuán)隊規(guī)模和復(fù)雜性擴(kuò)展,大多數(shù)工作室最終都會在開發(fā)的多款游戲之間重用某些功能和子程序。工作室開發(fā)的內(nèi)部引擎,基本上都是針對處理低級任務(wù)的內(nèi)部文件和庫的集合。這些功能允許開發(fā)團(tuán)隊的其他成員專注于游戲操作、地圖創(chuàng)建和級別定制等高級細(xì)節(jié)。

一些流行的經(jīng)典引擎包括id-Tech、Build和AGI等。這些引擎是為了幫助特定游戲的開發(fā)而創(chuàng)建的,它們允許團(tuán)隊的其他成員快速開發(fā)新的關(guān)卡,添加自定義資源,并動態(tài)定制地圖。這些定制引擎也被用來為他們的原創(chuàng)游戲修改或創(chuàng)建擴(kuò)展包。

Id Software軟件公司(美國得克薩斯州的一家游戲軟件公司)研發(fā)了id Tech技術(shù)。id Tech技術(shù)其實是一系列不同引擎的集合,其中每一個引擎的迭代時期都關(guān)聯(lián)著一款不同的游戲。于是,開發(fā)人員通常會將id Tech 0描述為“Wolfenstein 3D引擎(Wolfenstein3D engine)”,將id Tech 1描述為“末日引擎(Doom engine)”,將id Tech 2描述為“雷神之錘引擎(Quake engine)”,等等。

Build是上世紀(jì)90年代游戲引擎歷史中的另一個例子。它由肯·西爾弗曼(Ken Silverman)創(chuàng)建,旨在助力第一人稱射擊游戲定制。與id Tech的情況類似,Build隨著時間而發(fā)展,它的不同版本曾經(jīng)先后幫助程序員開發(fā)了《毀滅公爵3D》(Duke Nukem 3D)、《影子武士》(Shadow Warrior)和《血祭》(Blood)等游戲。這三個可以說是使用Build引擎開發(fā)的最受歡迎的游戲作品的代表,通常被稱為“三巨頭(The Big Three)”。


肯·西爾弗曼開發(fā)的Build引擎正在2D模式下編輯關(guān)卡時的情景

上世紀(jì)90年代游戲引擎的另一個例子是“瘋狂大樓專用程序腳本創(chuàng)建開發(fā)工具(Script Creation Utility for Manic Mansion)”(SCUMM)。SCUMM是盧卡斯藝術(shù)公司(LucasArts)開發(fā)的一款引擎,它是許多經(jīng)典點擊式(Point-and-Click)游戲的基礎(chǔ),《猴島小英雄》(Monkey Island)和《全速狂飆》(Full Throttle)這兩款游戲就使用這個引擎。


《全速狂飆》游戲的對話框和運作都使用SCUMM腳本語言進(jìn)行管理

隨著機器的發(fā)展和功能的不斷增強,游戲引擎也隨之發(fā)展?,F(xiàn)代引擎配備了功能豐富的工具,這些工具需要快速的處理器速度、驚人的內(nèi)存量和專用顯卡。

有了備用動力,現(xiàn)代游戲引擎可以用機器循環(huán)來換取更多的抽象性。這種權(quán)衡意味著,我們可以將現(xiàn)代游戲引擎視為通用工具,以較低的成本和較短的開發(fā)時間創(chuàng)建復(fù)雜的游戲。


三、為什么要制作游戲引擎?

這并不是一個陌生的問題,不同的游戲程序員也各有各的看法。其回答取決于開發(fā)的游戲的性質(zhì)、業(yè)務(wù)需求以及其他待考慮因素的影響。

開發(fā)者可以使用現(xiàn)有許多免費、強大、專業(yè)的商業(yè)引擎來創(chuàng)建和部署自己的游戲。那么,既然存在這么多游戲引擎可供選擇,為什么還會有人費心從頭開始制作游戲引擎呢?

我曾經(jīng)寫了一篇博客文章《自己動手編寫游戲引擎還是使用現(xiàn)成的?》(https://pikuma.com/blog/why-make-a-game-engine)來解釋程序員從頭開始制作游戲引擎的一些原因。在我看來,最主要的原因包括:

學(xué)習(xí)機會:對游戲引擎工作原理的深層次理解可以讓你成為一名優(yōu)秀的開發(fā)人員。

工作流控制:你可以更好地控制游戲的特殊方面,并調(diào)整解決方案以滿足工作流需求。

定制:能夠根據(jù)獨特的游戲需求定制解決方案。

極簡主義:較小的代碼庫可以減少較大游戲引擎帶來的開銷。

創(chuàng)新:你可能需要實現(xiàn)一些全新的或針對其他引擎不支持的非正統(tǒng)硬件。


四、如何制作游戲引擎

下文將繼續(xù)討論游戲引擎的一些組件,并指導(dǎo)讀者自己編寫一個游戲引擎。

1.選擇編程語言

開發(fā)核心引擎代碼的編程語言是首要選擇。原始匯編語言、C、C++,甚至C#、Java、Lua,還有JavaScript等高級語言都有用來開發(fā)引擎。

編寫游戲引擎最流行的語言之一是C++。C++編程語言將速度與使用面向?qū)ο缶幊?OOP)和其他編程范式的能力結(jié)合起來,幫助開發(fā)人員組織和設(shè)計大型軟件項目。

因為在我們開發(fā)游戲時,性能通常是非常重要的,而C++具有編譯語言的優(yōu)勢。使用編譯語言意味著最終的可執(zhí)行文件將在目標(biāo)機器的處理器上以本機方式運行。此外還有許多專用的C++庫和開發(fā)工具包可用于大多數(shù)現(xiàn)代控制臺,如PlayStation或XBox等。


開發(fā)者可以使用微軟提供的C++庫訪問XBox控制器

在性能方面,我個人不推薦使用虛擬機、字節(jié)碼或任何其他中間層的語言。除了C++之外,一些適合編寫核心游戲引擎代碼的替代品還包括Rust、Odin和Zig等語言。

本文將以C++編程語言構(gòu)建一個簡單的游戲引擎。

2?.?硬件訪問

在MS-DOS等較舊的操作系統(tǒng)中,我們通??梢灾苯硬僮鲀?nèi)存地址并訪問映射到不同硬件組件的特殊位置。例如,我要用某種顏色“繪制”一個像素,所要做的就是加載一個特殊的內(nèi)存地址,其中的數(shù)字代表VGA調(diào)色板的正確顏色,而顯示驅(qū)動程序?qū)⒃撟兓D(zhuǎn)換為物理像素,并將其轉(zhuǎn)換到CRT顯示器。

隨著操作系統(tǒng)的發(fā)展,它們開始負(fù)責(zé)保護(hù)硬件免受程序員的攻擊?,F(xiàn)代操作系統(tǒng)將不允許代碼修改操作系統(tǒng)為進(jìn)程提供允許地址之外的內(nèi)存位置。

例如,如果你使用的是Windows、macOS、Linux或BSD,則需要向操作系統(tǒng)請求在屏幕上繪制像素或與任何其他硬件組件對話的正確權(quán)限。即使是在操作系統(tǒng)桌面上打開窗口這樣的簡單任務(wù)也必須通過操作系統(tǒng)API來執(zhí)行。

因此,運行進(jìn)程、打開窗口、在屏幕上渲染圖形、繪制窗口內(nèi)的像素,甚至從鍵盤讀取輸入事件都是特定于操作系統(tǒng)的任務(wù)。

SDL(Simple DirectMedia Layer,即簡易直控媒體層)是一個非常流行的庫,它可以幫助實現(xiàn)多平臺硬件抽象。在游戲開發(fā)課堂上時,通過SDL,我無需為Windows操作系統(tǒng)、macOS和使用Linux系統(tǒng)的學(xué)生創(chuàng)建三個不同版本的代碼。SDL不僅是不同操作系統(tǒng)的橋梁,也是不同CPU體系結(jié)構(gòu)(英特爾、ARM、蘋果M1等)的橋梁。SDL庫對底層硬件訪問進(jìn)行抽象,并“翻譯”我們的代碼以便在這些不同的平臺上都能夠正確工作。

下面是使用SDL在操作系統(tǒng)上打開窗口的一小段代碼。為了簡單起見,代碼中沒有添加處理錯誤的部分,但是下面的代碼對于Windows、macOS、Linux、BSD,甚至RaspberryPi,都是通用的。


SDL只是我們可以用來實現(xiàn)這種多平臺硬件訪問的游戲庫的一個例子。SDL是2D游戲和將現(xiàn)有代碼移植到不同平臺和控制臺的熱門選擇方案之一。多平臺庫的另一個流行選擇方案是GLFW,它主要用于3D游戲和3D引擎。GLFW庫可以很好地與OpenGL和Vulkan等加速3D API進(jìn)行通信。

3?.?游戲主循環(huán)

至此,一旦操作系統(tǒng)方案解決,接下來我們就需要創(chuàng)建一個控制整個游戲的主循環(huán)。

簡單地說,我們通常希望我們的游戲以每秒60幀的速度運行。根據(jù)游戲的不同,幀速率可能會有所不同,但為了讓景物變得更加清晰,在膠片上拍攝的電影通常都是以每秒24幀的速度運行(每秒鐘24幅圖像從你眼前閃過)。

在游戲過程中,游戲循環(huán)會持續(xù)運行,在循環(huán)的每一次過程中,我們的引擎都需要運行一些重要的任務(wù)。傳統(tǒng)的游戲循環(huán)必須確保:

在不阻塞的情況下處理輸入事件

更新當(dāng)前幀的所有游戲?qū)ο蠹捌鋵傩?/p>

在屏幕上渲染所有游戲?qū)ο蠛推渌匾畔?/p>


但是,一個原始的C++循環(huán)對我們來說還不夠。游戲循環(huán)必須與現(xiàn)實世界的時間有某種關(guān)系。畢竟,游戲中的敵人應(yīng)該在任何機器上都是以相同的速度移動,而不管這些機器的CPU時鐘速度如何。

控制這個幀速率并將其設(shè)置為固定的FPS數(shù)實際上是一個非常有趣的事情。它通常要求我們跟蹤幀與幀之間的時差,并進(jìn)行一些合理的計算,以確保我們的游戲以至少30 FPS的幀速率順利運行。

4?.?輸入事件處理

很難想象一個游戲不從用戶那里讀取某種輸入事件會是什么情景。所有這些輸入事件可能來自鍵盤、鼠標(biāo)、游戲板或虛擬現(xiàn)實設(shè)備。因此,我們必須在游戲循環(huán)中處理不同的輸入事件。

要處理用戶輸入,我們必須請求訪問硬件事件,這必須通過操作系統(tǒng)API執(zhí)行。我們可以使用一些著名的多平臺硬件抽象庫(SDL、GLFW、SFML等)來處理用戶輸入。

例如,如果我們使用SDL就可以實現(xiàn)輪詢事件,然后僅用幾行代碼就可以處理各種輸入事件。


再強調(diào)一次,如果我們使用像SDL這樣的跨平臺庫來處理輸入,我們不必太擔(dān)心特定于操作系統(tǒng)的實現(xiàn)。無論我們的目標(biāo)平臺是什么,C++代碼都應(yīng)該是相同的。

至此,我們已經(jīng)有了一個可工作的游戲循環(huán)和一種處理用戶輸入的方法。接下來是時候開始考慮在內(nèi)存中組織游戲?qū)ο罅恕?/p>

5?.?在內(nèi)存中表示游戲?qū)ο?/strong>

在設(shè)計游戲引擎時,我們需要設(shè)計數(shù)據(jù)結(jié)構(gòu)來存儲和訪問游戲?qū)ο蟆?/p>

程序員在設(shè)計游戲引擎時會使用多種技術(shù)。一些引擎可能會使用簡單的面向?qū)ο蠓椒▉硖幚眍惡屠^承,而其他引擎可能會將它們的對象組織為實體和組件。


如想學(xué)習(xí)更多關(guān)于算法和數(shù)據(jù)結(jié)構(gòu)的知識,建議嘗試實現(xiàn)這些數(shù)據(jù)結(jié)構(gòu)。如果你使用的是C++,一個選項是使用STL(標(biāo)準(zhǔn)模板庫),并利用它附帶的許多數(shù)據(jù)結(jié)構(gòu)(向量、列表、隊列、堆棧、映射、集合等)。C++STL在很大程度上依賴于模板,因此這是一個練習(xí)使用模板的好機會,同時可以在實際項目中看到它們發(fā)揮的作用。

在閱讀過一些游戲引擎架構(gòu)的內(nèi)容后,你會發(fā)現(xiàn)游戲使用的最流行的設(shè)計模式之一是基于實體和組件。實體組件設(shè)計將游戲場景中的對象組織為實體(Unity引擎中稱之為“游戲?qū)ο蟆?,而Unreal引擎中則稱之為“角色”)和組件(我們可以添加或附加到實體的數(shù)據(jù))。

要了解實體和組件是如何協(xié)同工作的,請考慮一個簡單的游戲場景。此例中,實體將是我們的主要游戲玩家,還包括敵人、地板、投射物等,而組件將是我們“附加”到實體上的重要數(shù)據(jù)塊,如位置、速度、剛體碰撞器等。


一種流行的游戲引擎設(shè)計模式是將游戲元素組織為實體和組件

我們可以選擇附加到實體的一些組件,例如下面這些:

位置組件:跟蹤實體在世界坐標(biāo)系中的x-y位置坐標(biāo)(或3D中的x-y-z)。

速度組件:跟蹤實體在x-y軸(或3D中的x-y-z)上移動的速度。

精靈組件:通常存儲我們應(yīng)該為特定實體渲染的PNG圖像。

動畫組件:跟蹤實體的動畫速度,以及動畫幀如何隨時間變化。

碰撞器組件:這通常與剛體的物理特性有關(guān),并定義實體的碰撞形狀(邊界框、邊界圓、網(wǎng)格碰撞器等)。

健康組件:存儲實體的當(dāng)前健康值。這通常只是一個數(shù)字,或者在某些情況下是一個百分比值(例如,健康進(jìn)度條)。

腳本組件:有時我們可以在實體上附加一個腳本組件,它可能是一個外部腳本文件(Lua、Python等),我們的引擎必須在后臺解釋和執(zhí)行該文件。

上面給出的是一種非常流行的表示游戲?qū)ο蠛椭匾螒驍?shù)據(jù)的方法。如今,我們已經(jīng)有了實體,然后我們就可以將這些不同的組件“插入”到實體中。

目前,市場上已有諸多書籍和文章探討了實現(xiàn)實體組件設(shè)計的方式,以及在這個實現(xiàn)中應(yīng)該使用什么樣的數(shù)據(jù)結(jié)構(gòu)。我們使用的數(shù)據(jù)結(jié)構(gòu)和訪問它們的方式對我們的游戲性能有直接的影響。開發(fā)人員經(jīng)常會提到諸如面向數(shù)據(jù)的設(shè)計、實體組件系統(tǒng)(ECS)、數(shù)據(jù)局部性等想法,這些想法與我們的游戲數(shù)據(jù)在內(nèi)存中的存儲方式以及有效訪問數(shù)據(jù)方式都有密切的關(guān)系。

在內(nèi)存中表示和訪問游戲?qū)ο罂赡苁且粋€復(fù)雜的主題。根據(jù)我的經(jīng)驗,你可以手動編寫一個簡單的實體組件來實現(xiàn),也可以簡單地使用現(xiàn)有的第三方ECS庫(Entity-Component-System,即“實體-組件-系統(tǒng)”的縮寫。此模式遵循組合優(yōu)于繼承原則,游戲內(nèi)的每一個基本單元都是一個實體,每個實體又由一個或多個組件構(gòu)成,每個組件僅僅包含代表其特性的數(shù)據(jù))。

當(dāng)前市場上,有一些流行的現(xiàn)成的ECS庫可供選用,我們可以將它們包含在C++項目中,開始創(chuàng)建實體和附加組件,而不必?fù)?dān)心它們是如何在后臺實現(xiàn)的。C++ ECS庫的一些例子是EnTT和Flecs。

我個人建議那些認(rèn)真對待編程的學(xué)生至少嘗試一次手動實現(xiàn)一個非常簡單的ECS。我的理由是,即使你的實現(xiàn)并不完美,從頭開始編寫ECS系統(tǒng)也會迫使你考慮底層數(shù)據(jù)結(jié)構(gòu)以及相應(yīng)的性能。

一旦完成了定制的臨時ECS實現(xiàn),我建議你只使用一些流行的第三方ECS庫(EnTT、Flecs等),因為這些都是經(jīng)過行業(yè)多年開發(fā)和測試的專業(yè)的游戲開發(fā)庫,它們可能比我們自己從零開始編寫的要好得多。

總之,一個專業(yè)的ECS很難僅憑個人力量從零開始實現(xiàn)。選擇一個經(jīng)過良好測試的第三方ECS庫,并將其添加到游戲引擎代碼中即可完成你的游戲作品。

6?.?渲染

游戲引擎的復(fù)雜性正在慢慢提升。前文已討論了在內(nèi)存中存儲和訪問游戲?qū)ο蟮姆椒?,接下來我們需要討論如何在屏幕上渲染對象的問題。

第一步是考慮用引擎創(chuàng)建的游戲的性質(zhì)。我們創(chuàng)建的游戲引擎是否只用來開發(fā)2D游戲?如果是這樣,我們需要考慮渲染精靈、紋理、管理層,并可能利用圖形卡加速。2D游戲通常比3D游戲簡單,因為2D數(shù)學(xué)比3D數(shù)學(xué)要簡單得多。


如果目標(biāo)是開發(fā)2D引擎,則可以使用SDL幫助進(jìn)行多平臺渲染。SDL抽象了加速的GPU硬件,可以解碼和顯示PNG圖像,繪制精靈,并在我們的游戲窗口中渲染紋理。

如果目標(biāo)是開發(fā)一個3D引擎,那么則需要定義將一些額外的3D信息(頂點、紋理、著色器等)發(fā)送到GPU的方式。如果你想使用對圖形硬件軟件抽象,最流行的選擇方案就是OpenGL、Direct3D、Vulkan和Metal。當(dāng)然,使用哪種API的決定可能取決于自身的目標(biāo)平臺。例如,Direct3D會為微軟平臺的應(yīng)用程序提供支持,而Metal則只適合與蘋果的產(chǎn)品配合使用。

3D應(yīng)用程序通過圖形管道處理3D數(shù)據(jù)。該管道將規(guī)定引擎必須如何向GPU發(fā)送圖形信息(頂點、紋理坐標(biāo)、法線等)。圖形API和管道還將規(guī)定我們應(yīng)該如何編寫可編程著色器來變換和修改3D場景的頂點和像素。


可編程著色器規(guī)定GPU應(yīng)如何處理和顯示3D對象

每個頂點和每個像素(片段)可以有不同的腳本,它們分別用于控制反射、平滑度、顏色、透明度等。

至于3D對象和頂點,最好將讀取和解碼不同網(wǎng)格格式的任務(wù)委托給一些第三方庫來實現(xiàn)。大多數(shù)第三方3D引擎都應(yīng)該了解許多流行的3D模型格式,例如OBJ、Collada、FBX和DAE等一些文件格式。我的建議是首選.OBJ文件格式,因為有不少測試和支持力度良好的庫可以用C++處理OBJ加載。這方面,TinyOBJLoader和AssImp就是許多游戲引擎使用的上佳選擇。

7?.?物理引擎

當(dāng)我們向引擎中添加實體時,我們可能還希望它們在場景中移動、旋轉(zhuǎn)和反彈。

游戲引擎的這個子系統(tǒng)稱為物理模擬。這可以手動創(chuàng)建,也可以從現(xiàn)有的現(xiàn)成的物理引擎導(dǎo)入。

在這里,我們還需要考慮想要模擬的物理類型。2D物理通常比3D簡單,但物理模擬的底層部分對2D和3D引擎都非常相似。

如果你只想在項目中包含一個物理庫,那么已有幾個很好的物理引擎可供選擇。對于2D物理引擎,我建議調(diào)研一下Box2D和Chipmunk2D這兩款產(chǎn)品。對于專業(yè)且穩(wěn)定的三維物理模擬引擎,品牌相當(dāng)不錯的包括PhysX和Bullet之類的庫。如果物理穩(wěn)定性和開發(fā)速度對項目至關(guān)重要,那么使用第三方物理引擎總是一個不錯的選擇。


BOX2D是一個非常受歡迎的物理庫選項,可以與游戲引擎一起使用

你不需要編寫一個完美的物理模擬,但要確保物體能夠正確加速,并且不同類型的力可以應(yīng)用到你的游戲物體上。一旦實現(xiàn)基本的物體移動效果,接下來你也可以繼續(xù)考慮實現(xiàn)一些簡單的碰撞檢測和碰撞解析。

對于2D剛體物理可參考Box2D源代碼和來自Erin Catto的介紹。如果想尋找一門關(guān)于游戲物理的綜合課程可參看《從零開始編寫2D游戲物理》)。

如果想學(xué)習(xí)3D物理以及物理模擬實現(xiàn),可參閱大衛(wèi)·埃伯里(David Eberly)編寫的圖書《游戲物理》(Game Physics)。

8?.?用戶界面設(shè)計

一提到Unity或Unreal等現(xiàn)代游戲引擎,我們會想到復(fù)雜的用戶界面,其中包含許多面板、滑塊、拖放選項和其他漂亮的UI元素,可以幫助用戶自定義游戲場景。UI允許開發(fā)者添加和刪除實體,動態(tài)更改組件值,并輕松修改游戲變量。

為了明確起見,我們討論的是用于開發(fā)工具的游戲引擎UI,而不是我們向游戲用戶顯示的用戶界面(如對話框屏幕和菜單)。

游戲引擎不一定需要嵌入編輯器,但由于游戲引擎通常用于提高生產(chǎn)力,友好的用戶界面將幫助你和團(tuán)隊快速自定義游戲場景的關(guān)卡等其他方面。

對于初學(xué)者來說,從頭開始開發(fā)UI框架可能是游戲引擎制作中最煩人的任務(wù)之一。你必須創(chuàng)建按鈕、面板、對話框、滑塊、單選按鈕、管理顏色,還需要正確處理UI的事件并始終保持其狀態(tài)。向引擎中添加UI工具會增加應(yīng)用程序的復(fù)雜性,并給源代碼管理帶來大量麻煩。

如果你的目標(biāo)是為引擎創(chuàng)建UI工具,那么我建議使用現(xiàn)有的第三方UI庫,熱門UI備選工具有Dear ImGui、Qt和Nuklear等。


Imgui是一個強大的UI庫,被許多游戲引擎用作編輯工具

Dear ImGui是極佳的選擇之一,它允許我們?yōu)橐婀ぞ呖焖僭O(shè)置用戶界面。ImGui項目使用了一種稱為“即時模式UI”的設(shè)計模式,由于它通過利用加速的GPU渲染與3D應(yīng)用程序進(jìn)行良好的通信從而被廣泛用于游戲引擎。

總之,如果你想在游戲引擎中添加UI工具,建議使用Dear ImGui。

9?.?腳本開發(fā)

隨著我們游戲引擎的不斷發(fā)展,一個常見的選擇是使用簡單的腳本語言實現(xiàn)游戲關(guān)卡定制。

想法很簡單:我們在原生C++應(yīng)用程序中嵌入了一種腳本語言,非專業(yè)程序員可以使用這種更簡單的腳本語言編寫實體行為、AI邏輯、動畫和游戲的其他重要方面的腳本。

一些流行的游戲腳本語言有Lua、Wren、C#、Python和JavaScript等。所有這些語言的運行級別都比我們的原生C++代碼高得多。無論誰使用腳本語言編寫游戲行為腳本,都不需要擔(dān)心內(nèi)存管理或核心引擎如何工作的其他低級細(xì)節(jié)。他們要做的就是編寫游戲中對應(yīng)關(guān)卡的腳本,而我們的引擎知道如何解釋腳本并在幕后執(zhí)行艱難的任務(wù)。


Lua是一種快速、小型的腳本語言,可輕松與C/C++項目集成

我最喜歡的腳本語言是Lua。Lua體積小、速度快,非常容易與C和C++本機代碼集成。此外,如果我使用Lua和“現(xiàn)代”C++,我喜歡使用一個名為Sol的包裝庫(https://github.com/ThePhD/sol2)。Sol庫可幫助人們快速熟悉和使用Lua,并提供了許多輔助函數(shù)來改進(jìn)傳統(tǒng)的Lua C-API。

如果我們開發(fā)的游戲引擎中支持腳本編程的話,那么接下來可以開始在游戲引擎中討論一些更高級的話題。腳本編程能夠幫助定義人工智能邏輯、自定義動畫幀和運動,以及其他不需要通過原生C++代碼控制,而是可以通過外部腳本輕松管理的游戲行為。

10?.?音頻

接下來,還有一個需要為游戲引擎添加的支持元素是音頻。

如果想要讀寫音頻數(shù)據(jù)并發(fā)出聲音,我們需要通過操作系統(tǒng)訪問音頻設(shè)備。再次聲明,由于人們通常不想編寫特定于操作系統(tǒng)的代碼,我建議使用一個多平臺庫來抽象音頻硬件訪問。

SDL等多平臺庫就具有擴(kuò)展功能,可幫助引擎處理音樂和音效等內(nèi)容。

但是,我強烈建議只有在確定引擎的其他部分都已經(jīng)能夠正常協(xié)同工作之后,再考慮處理音頻的問題??刂坡曇粑募l(fā)音可能很容易實現(xiàn),但如果我們過早地開始處理音頻同步問題,即把音頻與動畫、事件和其他游戲元素聯(lián)系起來共同考慮,事情往往會變得一團(tuán)糟。

如果你真正是自己手工編寫代碼,那么由于多線程管理的復(fù)雜性,可能會導(dǎo)致音頻處理起來變得很棘手。不過,如果你的目標(biāo)是編寫一個簡單的游戲引擎,那么我可能更會借助一個專門的庫來處理這一部分功能。

例如,你可以考慮將SDL_Mixer、SoLoud和FMOD等優(yōu)秀的音頻庫和工具集成到自己開發(fā)的游戲引擎中。


《微型戰(zhàn)場》(Tiny Combat Arena)

這款游戲就使用FMOD聲音庫來實現(xiàn)多普勒和壓縮等音頻效果

11?.?人工智能

最后一個子系統(tǒng)是人工智能。我們可以通過腳本來實現(xiàn)人工智能。這意味著,我們可以將人工智能邏輯委托給關(guān)卡設(shè)計師來編寫腳本。另一個選擇是,在我們的游戲引擎內(nèi)核的本機代碼中嵌入適當(dāng)?shù)娜斯ぶ悄芟到y(tǒng)。

在游戲中,人工智能用于對游戲?qū)ο螽a(chǎn)生響應(yīng)性、適應(yīng)性或類似智能的行為。大多數(shù)人工智能邏輯被添加到非玩家角色(NPC、敵人)中,以模擬類似人類的智能。

敵人是AI在游戲中應(yīng)用的一個流行的例子。當(dāng)敵人追逐地圖上的物體時,游戲引擎可以通過路徑搜索算法或有趣的模仿人類的行為來創(chuàng)建抽象效果。

伊恩·米林頓(Ian Millington)的《游戲人工智能》是一本關(guān)于游戲人工智能理論和實現(xiàn)技術(shù)的綜合性書籍,值得參考。


五、不要貪多求快

在游戲引擎開發(fā)工作中,最困難的部分之一是大多數(shù)開發(fā)者都不會設(shè)定明確的界限,即有一種走不到“終點線”的感覺。換句話說,程序員會啟動一個游戲引擎項目,渲染對象,添加實體,添加組件,但到最后突然發(fā)現(xiàn)一切都很糟糕。因此,如果他們不定義某種邊界,就很容易不斷添加越來越多的功能,而忽略了全局。如果這種情況發(fā)生,游戲引擎很有可能永遠(yuǎn)看不到曙光。

除了缺乏邊界,當(dāng)看到代碼以閃電般的速度在眼前增長時,我們自己反倒很容易被淹沒。游戲引擎項目的復(fù)雜性可能會迅速擴(kuò)大,幾周內(nèi)你的C++項目可能會有幾個依賴項,需要復(fù)雜的構(gòu)建系統(tǒng),而隨著更多功能添加到引擎中,代碼的整體可讀性會不斷下降。


因此,我的首要建議是,在編寫實際游戲時,要始終堅持編寫自己的游戲引擎。開始并完成游戲的第一次迭代時,腦海中要有一個真實的游戲。這將幫助你設(shè)定限制,并為你需要完成的工作指出一條清晰的路徑。盡最大的努力堅持下去,而不是反復(fù)改變需求。


六、穩(wěn)扎穩(wěn)打,專注基礎(chǔ)

大多數(shù)學(xué)生在項目開始時都感到興奮,但是隨著時間的推移就開始出現(xiàn)焦慮情緒。如果我們從頭開始創(chuàng)建一個游戲引擎,尤其是在使用像C++這樣的復(fù)雜語言時,很容易不知所措失去動力。

因此,要學(xué)會及時享受某些階段性的小勝利。例如,學(xué)會如何成功地在屏幕上顯示PNG紋理,成功地發(fā)現(xiàn)了兩個物體之間的碰撞等等。專注并理解基礎(chǔ)知識一直都是非常重要的事情。

對于熱愛編程的朋友來說,路再難走也要堅持走下去!如果你想更好的提升你的編程核心能力(內(nèi)功)不妨從現(xiàn)在開始!

微信公眾號:C語言編程學(xué)習(xí)基地

C語言零基礎(chǔ)入門教程(83集全)

整理分享(多年學(xué)習(xí)的源碼、項目實戰(zhàn)視頻、項目筆記,基礎(chǔ)入門教程)

歡迎轉(zhuǎn)行和學(xué)習(xí)編程的伙伴,利用更多的資料學(xué)習(xí)成長比自己琢磨更快哦!

編程學(xué)習(xí)書籍分享:

粉絲編程交流:




如何從零開始用 C++ 開發(fā)一款游戲引擎?的評論 (共 條)

分享到微博請遵守國家法律
准格尔旗| 资源县| 温泉县| 迁西县| 辰溪县| 久治县| 长海县| 兴化市| 汨罗市| 安宁市| 望都县| 赣榆县| 九江县| 孝昌县| 龙川县| 新丰县| 蓝山县| 尼玛县| 瓮安县| 莎车县| 黄陵县| 泸水县| 广南县| 靖西县| 佛山市| 万源市| 三亚市| 遂平县| 垦利县| 阜宁县| 南京市| 巴林右旗| 吉林省| 鞍山市| 邳州市| 桂平市| 当涂县| 武安市| 大新县| 宜阳县| 隆林|