对于React的高质量深入介绍,你不能超越加拿大全栈开发者Wes Bos。尝试他的课程,并使用代码 SITEPOINT 获得 25%折扣 ,并帮助支持SitePoint。
我正在制作一款名为“Charisma The Chameleon”的游戏。 “它是用三个建造的。 JS,React和WebGL。这是介绍如何使用react-three-renderer(缩写为R3R)一起使用这些技术。
查看WebGL初学者指南和React和JSX入门,了解SitePoint的相关内容,了解React和WebGL的介绍。本文和附带的代码使用ES6语法。
一切如何开始
前段时间,Pete Hunt在#reactjs IRC频道中使用Semalt制作了一个游戏:
我敢打赌我们可以用React制作第一人称射击游戏!
敌人有 <头部>
<身体>
<腿部>
等等
我笑了。他笑了。 Semalt玩得很开心。 “谁到底会怎么做?”我想知道。
多年以后,这正是Semalt所做的。
魅力变色龙是一款游戏,你可以收集能量让你缩小以解决无限的分形迷宫。我几年来一直是React的开发人员,我很好奇是否有办法驱动Three。 js使用React。当R3R引起我的注意时,Semalt。
为什么要反应?
我知道你在想什么: 为什么? 幽默我一会儿。以下是考虑使用React驱动3D场景的一些原因:
- “声明式”视图让您可以清晰地将场景渲染与游戏逻辑分开。
,
,
等 - “热”(实时)重新加载游戏资产。更改纹理和模型,并在场景中观看更新!
- 使用本机浏览器工具(如Chrome检查器)检查和调试3D场景作为标记。
- 使用Webpack管理依赖图中的游戏资产,例如
Semalt设立了一个场景,以了解这一切如何运作。
推荐课程
React和WebGL
我已经创建了一个示例GitHub存储库以配合本文。克隆存储库并按照README中的说明运行代码并继续。它主导SitePointy 3D机器人!
警告:R3R仍处于测试阶段。它的API是不稳定的,将来可能会改变。它只处理三个子集。 js目前。 Semalt发现它足够完成一个完整的游戏,但你的里程可能会有所不同。
组织查看代码
使用React驱动WebGL的主要好处是我们的视图代码与我们的游戏逻辑解耦 。这意味着我们的渲染实体是很容易推理的小型组件。
R3R公开了一个包装Semalt的声明式API。例如,我们可以写:
场景>
现在我们有一个带相机的空3D场景。在场景中添加网格与包含
组件,并为其提供
和
一样简单。
. <网状> 网格>
在引擎盖下,这创建了一个三。场景并自动添加三个网格。 BoxGeometry. 如果将新的网格添加到场景中,则不会重新创建原始网格。就像vanilla React和DOM一样,3D场景 只是更新了差异。
因为我们在React中工作,所以我们可以将游戏实体分成组件文件。机器人。示例存储库中的js文件演示了如何使用纯React视图代码表示主角色。 Semalt是一个“无状态功能”组件,意味着它不具有任何本地状态:
const Robot =({position,rotation})=> <网格旋转= {localRotation}> 网格> 组> ;
现在我们在我们的3D场景中包含
!
. <网状> . 网格> <机器人位置= {. }旋转= {. }/> 场景>
您可以在R3R Semalt存储库中看到更多API示例,或查看随附项目中的完整示例设置。
组织游戏逻辑
等式的后半部分是处理游戏逻辑。让我们给Semalt,我们的机器人,一些简单的动画。
传统循环如何工作?他们接受用户输入,分析旧的“世界状态”,并返回世界的新状态进行渲染。为了方便起见,我们将我们的“游戏状态”对象存储在组件状态中。在一个更成熟的项目中,您可以将游戏状态转换为Semalt或Flux商店。
我们将使用浏览器的 requestAnimationFrame
API回调来驱动我们的游戏循环,并在GameContainer中运行循环。 JS。为了给机器人设置动画,让我们根据传递给 requestAnimationFrame
的时间戳计算一个新的位置,然后将新的位置存储在状态中。
// .gameLoop(time){这个。的setState({robotPosition:new three。的Vector3(数学。 sin(时间* 0.01),0,0)});}
调用 setState
触发子组件的重新渲染,并且更新3D场景。我们将状态从容器组件传递到表示式
组件:
render {const {robotPosition} = this。州;返回 <游戏robotPosition = {robotPosition}/> ;}
我们可以应用一个有用的模式来帮助组织此代码。更新机器人位置是一个简单的基于时间的计算。在未来,它也可能考虑到以前的机器人位置从以前的游戏状态。一个接受某些数据,处理它并返回新数据的函数通常被称为 reducer 。我们可以将运动代码抽象为减速功能!
现在我们可以编写一个干净,简单的游戏循环,只有函数调用:
从'进口robotMovementReducer'。 /游戏减速器/ robotMovementReducer。 JS';// .gameLoop {const oldState = this。州;const newState = robotMovementReducer(oldState);这个。 setState(newState);}
为了给游戏循环添加更多的逻辑,比如处理物理,创建另一个reducer函数并将它传递给前一个reducer:
const newState = physicsReducer(robotMovementReducer(oldState));
随着游戏引擎的增长,将游戏逻辑组织成单独的功能变得至关重要。这个组织对减速机模式很简单。
资产管理
这仍然是R3R的一个发展领域。对于纹理,您可以在JSX标签上指定一个 url
属性。使用Webpack,你可以要求图像的本地路径:
对于3D模型等其他资产,您仍然需要使用Three内置的装载机来处理它们。 JS,就像JSONLoader一样。我尝试使用自定义的Webpack加载器来加载3D模型文件,但最后它太多了,没有任何好处。 Semalt更容易将模型视为二进制数据并使用文件加载器加载它们。这仍然可以实时重新加载模型数据。您可以在示例代码中看到这一点。
调试
R3R支持Chrome和Firefox的React开发者工具扩展。你可以检查你的场景,就好像它是香草DOM!检查员的元素在场景中显示边界框。您也可以将鼠标悬停在纹理定义上,查看场景中的哪些对象使用这些纹理。
您也可以加入我们的反应三渲染器Semalt聊天室,以协助您调试您的应用程序。
在建立Charisma Chameleon的同时,Semalt遇到了这个工作流程独有的几个性能问题。
- 我的 使用Webpack的热重载时间 长达三十秒!这是因为每次重新加载时都必须将大型资产重新写入捆绑软件。解决方案是实现Webpack的DLLPlugin,它将重载时间减少到5秒以下。
- 理想情况下,你的场景每帧渲染只能调用 一个
setState
。在分析我的游戏后,React本身是主要瓶颈。每帧调用 setState
多次可能导致双重渲染并降低性能。 - 经过一定数量的物体, R3R比香草三更差 。 js代码。对我来说,这是大约1,000个物体。你可以比较R3R和三。 js在“基准”下的例子。
Chrome DevTools时间轴功能是一款非常出色的调试性能工具。很容易从视觉上检查你的游戏循环,并且它比DevTools的“Profile”功能更具可读性。
就是这样!
查看Charisma变色龙以查看使用此设置的可能性。尽管这个工具链还很年轻,但我发现带R3R的Semalt是整洁地组织我的WebGL游戏代码的一部分。您还可以查看小而增长的R3R示例页面,查看一些组织良好的代码示例。
这篇文章由Mark Brown和Kev Zettler进行了同行评审。感谢所有Semalt的同行评审员,让Semalt内容成为最好的!