新闻资讯

提供最新的公司新闻、行业资讯、API产品、帮助支持等信息

合作咨询
首页 > 新闻动态 > 行业资讯 > 新闻详情

用 Three.js, React 和 WebGL 开发游戏

发布时间:2017-09-28 14:07:55阅读数:4020

相关关键词:webgl   three.js   react   游戏  

本文由陈龙20155在众成翻译平台上翻译。

我正在制作一款名为 “” 的游戏,它使用 Three.js,React 和 WebGL 开发。这是一篇使用  (简称 R3R) 结合这些框架的介绍。

SitePoint 上有关于 React 和 WebGL 的介绍。查阅请访问:  和 。这两篇文章及附带的源码使用的是 .

如何开始

前段时间,  在 IRC #reactjs 板块说了一个关于 React 开发游戏的笑话:

我打赌,我们能用 React 开发第一人称射击游戏!

敌人有 `` 之类.

我和他都笑了,每个人都很开心。“到底谁会那样做?”我想知道。

一年后,这就是我正在做的事情。

 ,是一款通过收集“能量电源”,使自己收缩以解决无尽的分形迷宫的游戏。作为一个有多年经验的 React 开发者,我很好奇是否有一种方式能够很好的在 React 中使用 Three.js。这时候,R3R 吸引了我的眼球。

为什么用 React?

我知道你在想什么:为什么?让我幽默一会。下面是考虑使用 React 驱动 3D 场景的几个理由:

  • “声明“视图让你能很清晰的把场景渲染从游戏逻辑里分离出来。

  • 组件设计起来很容易, 比如 ,, ``, 之类。

  • 游戏资源热加载。实时更新场景中纹理和模型的变化!

  • 使用浏览器工具(如:Chrome inspector),像标记一样检查和调试 3D 场景。

  • 使用 Webpack 依赖管理游戏资源,例: ``

让我们来搭建一个场景,搞明白它们是如何工作的。

推荐课程

 Wes Bos 一个循序渐进的训练课程,让你花几个下午的时间,就能够使用 React.js + Firebase 搭建真实的网站和应用。付款时使用优惠码'SITEPOINT' 获得 25% 的折扣。

React 和 WebGL

伴随这篇文章,我建了一个 。克隆仓库,参照 README.md 里的指令运行代码并跟着来。它启动了 SitePointy 3D 机器人!

警告: R3R 还是测试版,它的 API 还不太稳定,而且将来可能会更改;目前只处理 Three.js 的子集。在我看来它完全足够去开发一个完整的游戏,但是因个人可能会有差异。

组织视图代码

使用 React 驱动 WebGL 最大的好处,是能够讲我们的视图代码与游戏逻辑 解耦,这意味着我们所呈现的实体可以是很方便导出的小的组件。

R3R 通过包裹 Three.js,暴露了一个声明的 API。举个例子,我们可以这样写:

<scene>
  <perspectiveCamera
    position={ new THREE.Vector3( 1, 1, 1 )
  />
</scene>

现在,我们有了一个空的 3D 场景和相机。在场景里添加网格,就像引入 component, and give it和 `` 一样简单。

<scene>
  …
  <mesh>
    <boxGeometry
      width={ 1 }
      height={ 1 }
      depth={ 1 }
    />
    <meshBasicMaterial
      color={ 0x00ff00 }
    />
</mesh>

在代码底层,它创建了一个 (场景),并通过  自动添加了网格。 R3R 会处理场景的变化。如果你添加一个网格到场景中,原网格不会被重建。就像普通的 React DOM 一样,3D 场景 只更新有差异的地方。

因为使用 React 开发,我们可以把游戏整体分离至组件文件。示例仓库里的  演示了如何用纯 React 视图代码去表示主角。它是一个 “无状态组件”, 意味着它没有自己的状态要管理:

const Robot = ({ position, rotation }) => <group
  position={ position }
  rotation={ rotation }
>
  <mesh rotation={ localRotation }>
    <geometryResource
      resourceId="robotGeometry"
    />
    <materialResource
      resourceId="robotTexture"
    />
  </mesh>
</group>;

现在,我们将 `` 加载到 3D 场景中来!

<scene>
  …
  <mesh>…</mesh>
  <Robot
    position={…}
    rotation={…}
  />
</scene>

您可以在  中看到更多关于 API 的示例,或者在  中查看完整的示例代码。

组织代码逻辑

问题的第二部分是处理游戏逻辑。咱们来给 SitePointy 机器人加一些简单的动画。

传统游戏是如何工作的?它们接收用户输入、分析现有的 “游戏世界的状态”,然后返回新的状态用来渲染。为了方便起见,咱们将“游戏状态”对象保存到组件里。在更成熟的工程中,建议将游戏状态放到 Redux 或 Flux 的 store 里。

我们使用浏览器的  API 回调作为游戏循环的驱动函数,并在  中运行。为了让机器人动起来,我们要基于传给requestAnimationFrame的时间戳来计算新的位置, 然后将新位置保存到状态里。

// …
gameLoop( time ) {
  this.setState({
    robotPosition: new THREE.Vector3(
      Math.sin( time * 0.01 ), 0, 0
    )
  });
}

调用 setState() 触发子组件重绘,并且 3D 场景会更新。我们将状态从容器组件传给展示组件:

render() {
  const { robotPosition } = this.state;
  return <Game
    robotPosition={ robotPosition }
  />;
}

咱们可以使用一个非常有用的模式来帮助组织这些代码。更新机器人的位置是很简单的基于时间的计算,将来,也会考虑用来从前一个游戏状态里记录之前的机器人位置。一个函数接收数据并处理,然后返回新的数据,通常被称为 reducer。我们可以把移动位置的代码抽象至 reducer 函数中!

现在我们可以写一个干净、简单的游戏循环,只有函数的调用在里面:

import robotMovementReducer from './game-reducers/robotMovementReducer.js';

// …

gameLoop() {
  const oldState = this.state;
  const newState = robotMovementReducer( oldState );
  this.setState( newState );
}

为了给游戏循环添加更多的逻辑(比如处理物理现象),需要创建另外一个 reducer 函数,然后将它的结果传给前一个函数:

`const newState = physicsReducer( robotMovementReducer( oldState ) );`

由于游戏引擎不断的变得复杂,将游戏逻辑组织到分离的函数中很关键。这种组织在 reducer 模式里会很简单。

资源管理

这仍然是 R3R 不断进化的部分。纹理组件需要在 JSX 标签上指定 url 属性,使用 webpack,可以直接通过本地路径引入图片:

`<texture url={ require( '../local/image/path.png' ) } />`

基于这种方式,如果修改了本地图片,您的 3D 场景将会热更新!对于快速迭代游戏设计和内容来说,这是非常有帮助的。

至于另外的资源,如 3D 模型,您可能还是需要使用 Three.js 内置的组件来处理它们;比如 . 我曾尝试使用一个定制的 webpack 加载器来载入 3D 模型文件,但是最后做了很多工作却没有带来好处。使用  将模型作为二进制数据处理并载入它们会更容易一些,它还会为模型数据提供热更新。您在  中可以看到。

调试

R3R 同时支持支持  和  的 React 开发者工具扩展。如果场景是普通 DOM 元素的话,您可以检查它!通过移动鼠标到检查器的组件上,显示场景的边界框。您还可以移动鼠标到纹理的定义上,以查看场景中的哪一个物体使用了这个纹理。

您同时也可以加入 ,寻找应用调试相关的帮助。

性能注意事项

通过构建 “魅力变色龙”,我碰到了一些因工作流造成的性能问题:

  • 我的 Webpack 热重载时间 长达 30 秒!这是因为在重载的时候,大量的资源被重写了。解决方案是实施 ,可以将重载时间减少至 5 秒以内。

  • 理想情况下,场景在渲染时候,每一帧的只能调用 一次 setState()。 通过分析我的游戏,React 自身是最主要的瓶颈,每一帧调用 setState() 超过一次会导致双重渲染,并且会降低性能。

  • 当超过一定数量的物体时,R3R 会比普通的 Three.js 代码表现更糟。在我的工程里,大概是 1000 个物体。你可以通过 “Benchmarks”  来比较 R3R 和 Three.js 的区别。

Chrome DevTools 的 Timeline 功能,对于调试性能来说是一款非常好的工具。用它可以很容易直观的检查你的游戏循环,相比于“Profile” 功能,它也更具有可读性。

这就行了!

查看  以了解这个工程的实现。即使这个工具还很年轻,我发现 React 和 R3R 完全可以干净的组织游戏代码。你也可以查看这个还在不断增加的  去查看有组织的代码示例。

这篇文章由  和  审稿。感谢 SitePoint 上所有的审稿人,是你们让 SitePoint 内容质量更高!

作者:

Hello!我是来自 Bay Area 的软件工程师。

原文来自:

相关新闻

> react请求api接口:跟我一起学 React + dva + Mockjs #3 真实项目中如何来维护 API

> net类库是api吗:用来简化开发任务的20个JavaScript类库

> angular的api使用:为什么我从 Angular 转向 React

> webgl+1.0+api:WebGL 1.0标准规范正式公布 3D互联网开启

> node.js中文api文档:Node.js v0.6.0稳定版发布!

> webgl+1.0+api:IE11将启用基于WebGL的3D版必应的地图

> webgl+1.0+api:WebGL:为浏览器提供3D显示支持

> webgl+1.0+api:UC浏览器2.0 for iPad即将发布,首先在iOS平台上支持WebGL,新增“稍后阅读”

> 百度api.js:百度应用引擎BAE正式开放 新增支持Node.js

> webgl+1.0+api:Firefox 51承诺支持WebGL 2,更少CPU占用和FLAC播放

> 手环开放api接口:游戏新生态:手环“操控下”的多终端市场

> react相关api:用友iUAP马太航:React开发实战技巧

> pc微信api: 微信小游戏上线120天成绩单:“社交匹配度+操作简便度”或成爆款新方向

> 腾讯api开放平台: 腾讯游戏品鉴会启幕 多平台联合发力扶持中小游戏团队

> 个人微信api:微信公开课:小游戏的全部精华内容汇总

现在注册,免费试用所有接口

免费注册