核心要點
我正在製作一款名為“變色龍魅力”的遊戲。它使用Three.js、React和WebGL構建。本文介紹了這些技術如何使用react-three-renderer(縮寫為R3R)協同工作。
請查看SitePoint上的《WebGL入門指南》和《React和JSX入門指南》,了解React和WebGL的介紹。本文和隨附的代碼使用ES6語法。
一切的開始
一段時間前,Pete Hunt在#reactjs IRC頻道中開了一個玩笑,說要用React來製作遊戲:
我敢打賭我們可以用React製作一款第一人稱射擊遊戲!敵人有
幾年後,我做的正是這件事。
《變色龍魅力》是一款收集增強道具的遊戲,這些道具會讓你縮小以解決無限分形迷宮。我已經做了幾年的React開發者,我很想知道是否有辦法使用React驅動Three.js。這時,R3R吸引了我的注意。
為什麼選擇React?
我知道你在想什麼:為什麼?請容我解釋一下。以下是一些考慮使用React驅動3D場景的原因:
<player></player>
、<wall></wall>
、<level></level>
等等。 <texture require="" src="%7B"></texture>
讓我們設置一個場景來了解這一切是如何工作的。
React和WebGL
我創建了一個示例GitHub存儲庫來配合本文。克隆存儲庫並按照README中的說明運行代碼並繼續學習。它以SitePointy 3D機器人為主角!
警告:R3R仍在測試階段。其API不穩定,將來可能會發生變化。目前它只處理Three.js的一個子集。我發現它足夠完整,可以構建一個完整的遊戲,但你的結果可能會有所不同。
使用React驅動WebGL的主要好處是我們的視圖代碼與遊戲邏輯解耦。這意味著我們渲染的實體是小而易於理解的組件。
R3R公開了一個封裝Three.js的聲明式API。例如,我們可以編寫:
<code><scene>></scene> <perspectivecamera> position={ new THREE.Vector3( 1, 1, 1 ) /> > </perspectivecamera></code>
現在我們有一個帶有攝像機的空3D場景。向場景添加網格就像包含<mesh></mesh>
組件並賦予它<geometry></geometry>
和<material></material>
一樣簡單。
<code><scene>></scene> … <mesh>></mesh> <boxgeometry></boxgeometry> width={ 1 } height={ 1 } depth={ 1 } /> <meshbasicmaterial></meshbasicmaterial> color={ 0x00ff00 } /> > </code>
在幕後,這將創建一個THREE.Scene並自動添加一個帶有THREE.BoxGeometry的網格。 R3R處理舊場景與任何更改的差異。如果你向場景添加一個新的網格,則不會重新創建原始網格。就像使用普通的React和DOM一樣,3D場景只更新差異。
因為我們在React中工作,所以我們可以將游戲實體分離到組件文件中。示例存儲庫中的Robot.js文件演示瞭如何使用純React視圖代碼表示主要角色。它是一個“無狀態函數”組件,這意味著它不保存任何本地狀態:
<code>const Robot = ({ position, rotation }) => <group></group> position={ position } rotation={ rotation } > <mesh> rotation={ localRotation }></mesh> <geometryresource></geometryresource> resourceId="robotGeometry" /> <materialresource></materialresource> resourceId="robotTexture" /> > >; </code>
現在我們將<robot></robot>
包含在我們的3D場景中!
<code><scene>></scene> … <mesh>></mesh>…> <robot></robot> position={…} rotation={…} /> > </code>
你可以在R3R GitHub存儲庫上查看更多API示例,或者在隨附的項目中查看完整的示例設置。
等式的另一半是處理遊戲邏輯。讓我們給我們的機器人SitePointy添加一些簡單的動畫。
傳統的遊戲循環是如何工作的?它們接受用戶輸入,分析舊的“世界狀態”,並返回新的世界狀態以進行渲染。為方便起見,讓我們將“遊戲狀態”對象存儲在組件狀態中。在一個更成熟的項目中,你可以將游戲狀態移動到Redux或Flux存儲中。
我們將使用瀏覽器的requestAnimationFrame
API回調來驅動我們的遊戲循環,並在GameContainer.js
中運行循環。為了動畫化機器人,讓我們根據傳遞給requestAnimationFrame
的時間戳計算一個新的位置,然後將新的位置存儲在狀態中。
<code><scene>></scene> <perspectivecamera> position={ new THREE.Vector3( 1, 1, 1 ) /> > </perspectivecamera></code>
調用setState()
將觸發子組件的重新渲染,並更新3D場景。我們將狀態從容器組件傳遞到演示性<game></game>
組件:
<code><scene>></scene> … <mesh>></mesh> <boxgeometry></boxgeometry> width={ 1 } height={ 1 } depth={ 1 } /> <meshbasicmaterial></meshbasicmaterial> color={ 0x00ff00 } /> > </code>
我們可以應用一個有用的模式來幫助組織這段代碼。更新機器人位置是一個簡單的基於時間的計算。將來,它還可能考慮來自先前遊戲狀態的先前機器人位置。一個接受一些數據、處理它並返回新數據的函數通常被稱為reducer。我們可以將移動代碼抽象成一個reducer函數!
現在我們可以編寫一個簡潔明了的遊戲循環,其中只包含函數調用:
<code>const Robot = ({ position, rotation }) => <group></group> position={ position } rotation={ rotation } > <mesh> rotation={ localRotation }></mesh> <geometryresource></geometryresource> resourceId="robotGeometry" /> <materialresource></materialresource> resourceId="robotTexture" /> > >; </code>
要向遊戲循環添加更多邏輯,例如處理物理,請創建另一個reducer函數並將其傳遞給先前reducer的結果:
<code><scene>></scene> … <mesh>></mesh>…> <robot></robot> position={…} rotation={…} /> > </code>
隨著遊戲引擎的增長,將游戲邏輯組織成單獨的函數變得至關重要。使用reducer模式,這種組織非常簡單。
這仍然是R3R的一個發展領域。對於紋理,你可以在JSX標籤上指定一個url屬性。使用Webpack,你可以要求本地圖像路徑:
<code>// … gameLoop( time ) { this.setState({ robotPosition: new THREE.Vector3( Math.sin( time * 0.01 ), 0, 0 ) }); } </code>
有了這個設置,如果你更改磁盤上的圖像,你的3D場景將實時更新!這對於快速迭代遊戲設計和內容非常寶貴。
對於其他資源(如3D模型),你仍然必須使用Three.js的內置加載器(如JSONLoader)來處理它們。我嘗試過使用自定義Webpack加載器來加載3D模型文件,但最終工作量太大,沒有好處。將模型視為二進制數據並使用文件加載器加載它們更容易。這仍然可以實現模型數據的實時重載。你可以在示例代碼中看到這一點。
調試
R3R支持Chrome和Firefox的React開發者工具擴展。你可以像檢查普通DOM一樣檢查你的場景!將鼠標懸停在檢查器中的元素上會在場景中顯示它們的邊界框。你還可以將鼠標懸停在紋理定義上以查看場景中哪些對象使用這些紋理。
你還可以加入react-three-renderer Gitter聊天室,以獲得有關調試應用程序的幫助。
性能注意事項
在構建《變色龍魅力》時,我遇到了一些此工作流程特有的性能問題。
setState()
。在分析我的遊戲後,React本身是主要的瓶頸。每幀調用setState()
多次會導致雙重渲染並降低性能。 Chrome DevTools的時間軸功能是調試性能的絕佳工具。你可以輕鬆地直觀地檢查遊戲循環,而且它比DevTools的“配置文件”功能更易於閱讀。
就是這樣!
查看《變色龍魅力》以了解使用此設置可以實現的功能。雖然此工具鏈還很年輕,但我發現使用R3R的React對於清晰地組織我的WebGL遊戲代碼至關重要。你還可以查看小型但不斷增長的R3R示例頁面,以查看一些組織良好的代碼示例。
本文由Mark Brown和Kev Zettler進行同行評審。感謝所有SitePoint的同行評審人員,使SitePoint的內容達到最佳狀態!
使用ReactJS和WebGL構建遊戲的常見問題解答(FAQ)
要開始使用ReactJS和WebGL構建遊戲,你需要對JavaScript、HTML和CSS有基本的了解。還需要了解ReactJS(一個流行的用於構建用戶界面的JavaScript庫)。此外,了解WebGL(Web圖形庫)(一個用於渲染交互式3D和2D圖形的JavaScript API)至關重要。熟悉ES6語法、npm(Node包管理器)和命令行也將大有裨益。
可以使用react-unity-webgl包將Unity與ReactJS集成。此包允許你將Unity WebGL構建嵌入到ReactJS應用程序中。你可以使用npm安裝它並將其導入到你的項目中。然後,你可以使用包提供的Unity組件將你的Unity遊戲嵌入到你的ReactJS應用程序中。
有幾種方法可以使用React創建3D應用程序。最流行的方法之一是使用Three.js,這是一個用於創建和顯示動畫3D計算機圖形的跨瀏覽器JavaScript庫。另一種方法是直接使用WebGL,但這可能更複雜。其他庫(如react-three-fiber和react-unity-webgl)也可以用於使用React創建3D應用程序。
WebGL允許你直接在瀏覽器中創建交互式3D圖形,無需插件。你可以使用WebGL的API創建複雜的3D圖形、動畫和遊戲。但是,WebGL的API是低級的,直接使用可能很複雜。因此,許多開發人員更喜歡使用像Three.js這樣的庫,這些庫為WebGL提供了更高級別的接口。
react-unity-webgl包允許你將Unity WebGL構建嵌入到ReactJS應用程序中。這意味著你可以使用Unity創建複雜的3D遊戲,然後輕鬆地將它們集成到你的ReactJS應用程序中。如果你想創建一個基於Web的遊戲或交互式3D應用程序,這將特別有用。
優化使用ReactJS和WebGL構建的遊戲可能涉及多種策略。這些策略包括最小化React中的重新渲染次數,使用WebGL的內置性能功能(如requestAnimationFrame
)實現流暢的動畫,以及為Web優化3D模型和紋理。
是的,你可以使用ReactJS和WebGL構建在移動設備上的Web瀏覽器中運行的遊戲。但是,對於原生移動遊戲,你可能需要考慮使用Unity或Unreal Engine等遊戲開發平台,這些平台可以直接導出到iOS和Android。
可以使用標準JavaScript事件處理程序在ReactJS和WebGL遊戲中處理用戶輸入。你可以監聽鍵盤、鼠標和触摸事件,然後相應地更新遊戲狀態。 ReactJS還提供合成事件,可以用來以一致的方式跨不同瀏覽器處理用戶輸入。
是的,你可以將其他JavaScript庫與ReactJS和WebGL一起使用。例如,你可能會使用Three.js進行3D圖形處理,使用Howler.js進行音頻處理,或使用Matter.js進行物理處理。關鍵是確保這些庫可以在你的遊戲中無縫協同工作。
可以使用Web瀏覽器中的開發者工具調試使用ReactJS和WebGL構建的遊戲。這些工具允許你檢查HTML、CSS和JavaScript代碼,查看控制台日誌,並逐步調試代碼。此外,React開發者工具是一個瀏覽器擴展,允許你檢查React組件層次結構、道具和狀態。
以上是用三分,react和webGL構建遊戲的詳細內容。更多資訊請關注PHP中文網其他相關文章!