当前位置:   article > 正文

用three.js做一个3D汉诺塔游戏(上)

用three.js做一个3D汉诺塔游戏(上)

入门 three.js 也有一阵子了,我发现用它做 3D 挺有趣的,而且学习门槛也不算高。在这篇博文中,我想分享一下利用 three.js 做一个 3D 版汉诺塔(河内塔)的过程,以及对 three.js 相关知识点进行一次较为全面的实战总结。希望能与大家交流技术心得和经验,一起共同进步。

效果展示

游戏规则:将串在左边柱杆(A 柱)上的盘子全部挪进右边柱杆(C 柱)即可获胜;一次只能挪动最上面的一个盘子;每个盘子的上面只能放置比它小的盘子;可利用中间的柱杆(B 柱)来中转、倒换盘子。

可自由选择游戏难度(盘子数量),游戏中途可随时重开,获胜后会有该局耗时和步数的统计信息。

本文知识点

  • 3D 场景初始化:场景、相机、渲染器
  • 透视相机的位置调整
  • 几何体:BoxGeometry、CylinderGeometry、LatheGeometry
  • 材质:MeshLambertMaterial、MeshPhongMaterial、MeshBasicMaterial
  • 光源:AmbientLight、SpotLightHelper、DirectionalLight
  • 更新材质的纹理:TextureLoader
  • 渲染 3D 文本:TextGeometry、FontLoader
  • 实现物体阴影效果
  • 3D 坐标的计算
  • 物体交互的实现:Raycaster、坐标归一化
  • 3D 资源的销毁释放
  • 补间动画、动画编排
  • MVP 架构、class 等

初始化

为了方便演示,避免引入底层框架(Vue、React、Angular...)的代码增加复杂度,本文中的案例没有使用前端底层框架和工程脚手架,而采用传统的 HTML 单文件方式来编写代码。

首先,准备一个空白容器,让它的尺寸与浏览器视窗大小相同,以充分利用屏幕空间。

  1. <style>
  2. body {
  3. padding: 0;
  4. margin: 0;
  5. font: normal 14px/1.42857 Tahoma;
  6. }
  7. #app {height: 100vh;}
  8. </style>
  9. <div id="app"></div> <!-- 空白容器 -->

对于 JS 脚本,使用 导入映射 配置资源的 CDN 地址,这样就可以像使用 npm 包一样导入相关资源。

  1. <script type="importmap">
  2. {
  3. "imports": {
  4. "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/+esm",
  5. "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
  6. }
  7. }
  8. </script>
  9. <script type="module">
  10. import * as THREE from 'three'; // 丝滑导入 three.js
  11. </script>

接下来,创建一个场景(Scene)、一个透视相机(PerspectiveCamera)和一个 WebGL 渲染器(WebGLRenderer),并将渲染器添加到 DOM 中。同时,编写一个渲染函数,使用 requestAnimationFrame 方法循环渲染场景。以下是最基础的初始化代码:

  1. <script type="module">
  2. import * as THREE from 'three';
  3. const containerEl = document.getElementById('app');
  4. const { width, height } = containerEl.getBoundingClientRect();
  5. /* 场景 */
  6. const scene = new THREE.Scene();
  7. /* 相机 */
  8. const fov = 45; // 视野角度
  9. const camera = new THREE.PerspectiveCamera(fov, width / height, 1, 500);
  10. /* 渲染器 */
  11. const renderer = new THREE.WebGLRenderer({ alpha: true });
  12. renderer.setSize(width, height);
  13. renderer.setClearColor('#f8f8f6', 1); // 设置初始化背景
  14. containerEl.appendChild(renderer.domElement);
  15. // 渲染场景(循环)
  16. (function animate() {
  17. requestAnimationFrame(animate);
  18. renderer.render(scene, camera);
  19. }());
  20. </script>

上面 PerspectiveCamera 设置了 4 个参数,其中最后 2 个参数分别是相机视锥体的近端面和远端面,默认是 0.1 和 2000。这里将其设为 1 和 500,让相机与物体产生的视椎体 “更小、更接近”,以节省渲染性能。

添加桌台

汉诺塔游戏中,场景里主要的 3D 物体包括桌台、柱杆和盘子,我们先来添加最简单的桌台到场景中。

桌台的形状是一个长方体,我们可以使用 BoxGeometry 来实现它,网格材质则使用 MeshLambertMaterial 模拟木质的非光泽表面。

  1. const tableSize = {
  2. width: 30, //
  3. depth: 10, //
  4. height: 0.5 //
  5. };
  6. const geometry = new THREE.BoxGeometry( // 立方缓冲几何体
  7. ...['width', 'height', 'depth'].map(key => tableSize[key])
  8. );
  9. const material = new THREE.MeshLambertMaterial({ color: '#cccca6' }); // 材质
  10. const table = new THREE.Mesh(geometry, material);
  11. scene.add(table); // 添加到场景

为方便调试࿰

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/416625
推荐阅读
相关标签
  

闽ICP备14008679号