当前位置: 首页 > news >正文

为什么网站打不开域名服务器ip地址

为什么网站打不开,域名服务器ip地址,百度糯米做网站多少钱,佛山网站排名推广介绍 物理是WebGL可以添加到项目体验中最酷的功能之一。人们喜欢真实物理感的物体#xff0c;看到它们碰撞、倒塌、坠落和弹跳#xff0c;就像我的作品集一样#xff1a; https: //bruno-simon.com/ 有很多方法可以将物理功能添加到您的项目中#xff0c;这取决于您想要实…介绍 物理是WebGL可以添加到项目体验中最酷的功能之一。人们喜欢真实物理感的物体看到它们碰撞、倒塌、坠落和弹跳就像我的作品集一样 https: //bruno-simon.com/ 有很多方法可以将物理功能添加到您的项目中这取决于您想要实现的目标。您可以使用一些数学和解决方案例如Raycaster来创建自己的物理学 理论 这个想法很简单。我们将创建一个物理世界。这个物理世界是纯理论的。在这个物理世界上东西会产生掉落、碰撞、摩擦、滑动等等交互。 当我们创建一个 Three.js 网格时我们还将在物理世界中创建该网格的一个物理版本。如果我们在 Three.js 中创建一个 Box我们也会在物理世界中创建一个Box框。 然后在每一帧上在渲染任何东西之前我们告诉物理世界进行自我更新我们获取物理对象的坐标位置和旋转并将它们应用于相应的 Three.js 网格。 就是这么简单的原理。这里最困难的是将我们的代码组织成一个合理的结构。这是一个完全和原本文件路径分开的路径部分。每个开发人员都会有自己的习惯这也取决于你想做什么以及你想把这个物理世界变得多复杂。 首先我们将简单地创建球体和盒子。 物理功能依赖库 物理功能有多个可用的库。首先您必须决定是需要 3D 库还是 2D 库。虽然您可能认为它必须是一个 3D 库因为 Three.js 完全是关于 3D 的但您可能错了。2D 库通常性能更高如果您可以总结 2D 碰撞的物理经验则最好使用 2D 库。 举一个例子是如果你想创建一个类似⚾️弹球游戏。球可以在墙上碰撞和弹跳您就可以使用 2D 库将所有东西投影到二维平面上。您可以将球设计成物理世界中的圆圈而墙壁是简单的矩形。事实上这么做您将无法通过击球底部来使球跳过其他球。 像这样完成的项目的一个很好的例子是Merci Michel的Ouigo Let’s play。他们使用了 2D 物理库因为每个碰撞和动画都可以在 2D 空间中表示。 3D物理 对于 3D 物理主要有三个库 ammo.js 网站 http: //schteppe.github.io/ammo.js-demos/Git 存储库https://github.com/kripken/ammo.js/文档无文档Bullet 的直接 JavaScript 端口用 C 编写的物理引擎体积大有点重社区仍然在更新 cannon.js 网站 https: //schteppe.github.io/cannon.js/Git 存储库 https: //github.com/schteppe/cannon.js文档 http: //schteppe.github.io/cannon.js/docs/比 Ammo.js 更轻比 Ammo.js 更容易实现主要由一名开发人员维护多年未更新有一个维护的叉子 Oimo.js 网站 https: //lo-th.github.io/Oimo.js/Git 存储库https://github.com/lo-th/Oimo.js文档http://lo-th.github.io/Oimo.js/docs.html比 Ammo.js 更轻比 Ammo.js 更容易实现主要由一名开发人员维护2年没更新了 2D物理 对于 2D 物理有很多库但这里是最流行的 matter.js 网站 https: //brm.io/matter-js/Git 存储库 https: //github.com/liabru/matter-js文档 https: //brm.io/matter-js/docs/主要由一名开发人员维护还是有点更新 P2.js 网站 https: //schteppe.github.io/p2.js/Git 存储库 https: //github.com/schteppe/p2.js文档 http: //schteppe.github.io/p2.js/docs/主要由一名开发人员维护与 Cannon.js 相同2年没更新了 planck.js 网站 https: //piqnt.com/planck.js/Git 存储库 https: //github.com/shakiba/planck.js文档 https: //github.com/shakiba/planck.js/tree/master/docs主要由一名开发人员维护现在还在更新 Box2D.js 网站http://kripken.github.io/box2d.js/demo/webgl/box2d.htmlGit 存储库 https: //github.com/kripken/box2d.js/文档无文档主要由一名开发人员维护与 Ammo.js 相同现在还在更新 我们不会在本课中使用 2D 库但 2D 库代码与 3D 库代码非常相似。主要区别在于您必须更新的轴。 已经有尝试将 Three.js 与Physijs等库结合起来的解决方案。尽管如此我们不会使用这些已经做好封装的现成解决方案我们要手动结合物理库来获得更好的学习体验并更好地理解内部运行的逻辑。 虽然 Ammo.js 是最常用的库尤其是在 Three.js中正如您在示例中看到的那样我们将选择 Cannon.js。这个库在我们的项目中实现起来更舒服也更容易使用。 导入 Cannon.js 要将 Cannon.js 添加到我们的项目中我们首先需要添加依赖项。 在您的终端的项目文件夹中运行此命令npm install --save cannon。 我们现在可以使用经典的 JavaScript 在我们的 JavaScript 中import导入 Cannon.js import CANNON from cannon我们需要的一切都在CANNON变量中可用。 设置 我们的启动器由平面上的一个球体组成并且出于美学原因已经启用了阴影。 基础 世界 首先我们需要创建一个 Cannon.js世界 /*** Physics*/ const world new CANNON.World()现在我们获得了一个感觉在没有重力漂浮在太空中的 WebGL 体验感让我们增加重力脚踏实地。您可以使用Cannon.js Vec3 的 gravity属性更改重力。 **Cannon.js **Vec3就像 Three.js Vector3一样。它也有**x**、**y**和**z**属性还有一个**set(...)**方法 world.gravity.set(0, - 9.82, 0)我们把第二个参数值 改为 - 9.82 是因为- 9.82它是地球上的重力常数但如果您想让物体下落得更慢或者如果您的场景发生在火星上您可以使用其他重力值。 目的 因为我们的场景中已经有了一个球体所以让我们在 Cannon.js World中也创建一个球体。 为此我们必须创建一个Body。Body是会掉落的并与其他物体碰撞的。 在我们创建一个Body之前我们必须决定一个形状。有许多可用的基本形状如Box、Cylinder、Plane等。我们将选择一个与 Three.js 球体具有相同半径的Sphere const sphereShape new CANNON.Sphere(0.5)然后我们可以创建我们的body并指定质量和位置 const sphereBody new CANNON.Body({mass: 1,position: new CANNON.Vec3(0, 3, 0),shape: sphereShape })最后我们可以将Body 通过addBody(...)添加到世界中 world.addBody(sphereBody)现在页面里什么都没有发生因为我们仍然需要更新我们的 Cannon.js 世界并相应地更新我们的 Three.js 球体。 更新 Cannon.js 世界和 Three.js 场景 要更新我们的world世界我们必须使用step(...). 该方法底层的代码很难理解我们不会在本课中对其进行解释但您可以在本文中找到更多相关信息。 要让它工作您必须提供一个固定的时间步长、自上一步以来经过了多少时间以及世界world可以应用多少次迭代来赶上潜在的延迟。 我们不会解释什么是时间步长但我们希望体验以 60fps 的速度运行所以我们将使用1 / 60来表示. 别担心在帧率更高和更低的设备上体验将以相同的速度运行。 迭代次数由你决定但体验是否流畅就没那么重要了。 对于三角洲时间它有点复杂。我们需要计算自上一帧以来经过了多少时间。不要使用Clock类中的getDelta()方法。你不会得到预期的结果而且你会搞乱类的内部逻辑。 为了获得正确的增量时间我们需要从前一帧elapsedTime减去当前帧elapsedTime获得 const clock new THREE.Clock() let oldElapsedTime 0const tick () {const elapsedTime clock.getElapsedTime()const deltaTime elapsedTime - oldElapsedTimeoldElapsedTime elapsedTime// ... }我们终于可以更新我们的世界了 const tick () {// ...// Update physicsworld.step(1 / 60, deltaTime, 3) }似乎没有任何东西在移动。其实现实是我们的sphereBody正在无限的堕入深渊只是因为相机一直跟着物体坠落所以你难以发现你可以通过在更新world世界后记录它的位置来看到 world.step(1 / 60, deltaTime, 3)console.log(sphereBody.position.y)我们现在需要做的是使用sphereBody坐标更新我们的sphere。 Three.js 有两种方法可以做到这一点。您可以单独更新每个position属性 sphere.position.x sphereBody.position.xsphere.position.y sphereBody.position.ysphere.position.z sphereBody.position.z或者您可以使用以下方法将所有属性作为一个复制copy(...) sphere.position.copy(sphereBody.position)copy(...)在许多类中可用例如Vector2、Vector3、Euler、Quaternion甚至类如Material、Object3D、Geometry等。 你最终应该看到你的项目中球体正在自由落体。问题是我们的球体似乎从地板上掉了下来。这是因为该地板存在于 Three.js 场景中但不存在于 Cannon.js 世界中。 我们可以使用Plane形状简单地添加一个新的Body但我们不希望我们的地板受到重力影响而掉落。换句话说我们希望我们的地板是静态的。要使Body静态请将其设置为mass 0 const floorShape new CANNON.Plane() const floorBody new CANNON.Body() floorBody.mass 0 floorBody.addShape(floorShape) world.addBody(floorBody)如您所见这次我们的做法大不相同。我们创建了一个没有参数的Body 然后我们设置了这些参数。结果是一样的我们这样做的唯一原因是为了上课讲解。一件有趣的事情是您可以创建一个由多个Shapes组成的Body。它对于复杂但坚固的物体很有用。 您应该看到球体朝一个方向可能朝向相机跳跃。这不是预期的结果。原因是我们的地板plane默认正对着相机。我们需要像在 Three.js 中旋转地板一样旋转它让他转到离开相机的区域。 使用 Cannon.js 进行旋转比使用 Three.js 稍微困难一些因为您必须使用Quaternion来实现。有多种旋转Body的方法但必须使用其quaternion属性。我们将使用setFromAxisAngle(...)方法旋转body. 第一个参数是一个轴。您可以将其想象成穿过身体的一根线。第二个参数是角度。这是你围绕这条线旋转身体的角度。 floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(- 1, 0, 0), Math.PI * 0.5)我们将轴设置为负轴相对于相机的左侧穿过身体的线并将x角度设置为四分之一圆。Math.PI * 0.5 您现在应该看到球体下落然后停在地板上。 我们不需要用 Cannon.js 地板更新 Three.js 地板因为这个对象不会再移动了。 ContactMaterial 关联材料 如您所见球落地后基本不会弹跳。这是默认行为我们可以使用Material不是 Three.js 中的 Material和ContactMaterial来让它变的富有弹性。 材料只是一个参考。您可以给它起一个名字并将它与一个Body相关联。然后为场景中的每种材质创建一个材质。 如果场景中有多种材质假设一种木料材质用于地板一种金属材质用于球。然后您应该创建各种材质并为它们命名例如concrete和plastic。 (假设你世界里的一切都是塑料材质制成的。在这种情况下您只需创建一种材料并将其命名为default’即可。) 你可以给他们互相关联到ground和ball中。尽管如此如果您想对墙壁和立方体等其他对象使用相同的材质都名为ground即可. 在创建球体和地板之前创建这两个材质 const concreteMaterial new CANNON.Material(concrete) const plasticMaterial new CANNON.Material(plastic)现在我们有了Material我们必须创建一个ContactMaterial。它是两种材质的组合用来关联两种材料并模拟碰撞发生包含对象发生碰撞时的属性。 前两个参数是Materials。第三个参数是一个**{}**包含两个重要属性的对象**friction**系数摩擦系数和**restitution**系数弹跳系数——两者的默认值为0.3. 创建后使用以下方法addContactMaterial(...)将ContactMaterial添加到世界 const concretePlasticContactMaterial new CANNON.ContactMaterial(concreteMaterial,plasticMaterial,{friction: 0.1,restitution: 0.7} ) world.addContactMaterial(concretePlasticContactMaterial)混凝土和塑料材质之间没有太大的摩擦力但是如果你让一个橡胶球落在混凝土地板上你会看到它会反弹的很高。 我们现在可以在身体上使用我们的材质。您可以在实例化Body时或在material属性之后直接传递材质。我们做这两件事 const sphereBody new CANNON.Body({// ...material: plasticMaterial })// ...const floorBody new CANNON.Body() floorBody.material concreteMaterial在停止之前您应该看到球反弹了很多次。我们看不到friction动作因为我们的球完全笔直地落在我们的地板上而且球大部分时间都在空中。 拥有不同的材料并为每种组合创建一个接触材料可能会令人费解。为了简化一切让我们将两种材质替换为默认材质并将其用于每个Bodies const defaultMaterial new CANNON.Material(default) const defaultContactMaterial new CANNON.ContactMaterial(defaultMaterial,defaultMaterial,{friction: 0.1,restitution: 0.7} ) world.addContactMaterial(defaultContactMaterial)// ...const sphereBody new CANNON.Body({// ...material: defaultMaterial })// ...floorBody.material defaultMaterial我们应该得到相同的结果。 我们可以更进一步将我们的材质设置为World的默认材质。为此只需将defaultContactMaterial 分配给world.defaultContactMaterial属性 world.defaultContactMaterial defaultContactMaterial我们现在可以删除或注释floorBody的sphereBody材料分配。 施力 有很多方法可以对Body施加力 applyForce从空间中的指定点不一定在Body的表面向Body施加一个力就像风一直将所有东西推一点点可以是多米诺骨牌穿导的推力可以是更大爆发力让愤怒的小鸟飞向敌人的城堡。applyImpulse与applyForce类似但它不是自增导致速度变化的力而是直接应用于速度。applyLocalForce与applyForce相同但坐标是Body的内部中心坐标意味着它将是Body0, 0, 0的中心。applyLocalImpulse与applyImpulse相同但坐标是Body的内部中心坐标。 因为用“力”的方式会造成速度的变化我们还是不要用“冲量”的方式 让我们在开始时applyLocalForce(...)对我们的sphereBody施加一个小的力推动它 sphereBody.applyLocalForce(new CANNON.Vec3(150, 0, 0), new CANNON.Vec3(0, 0, 0))您可以看到球向右弹跳并滚动。 现在让我们使用applyForce(...)施加一些风的感觉。因为风是永久性的所以我们应该在更新World之前将此力应用于每一帧。要正确施加此力重点应该是**sphereBody.position** const tick () {// ...// Update physicssphereBody.applyForce(new CANNON.Vec3(- 0.5, 0, 0), sphereBody.position)world.step(1 / 60, deltaTime, 3)// ... }处理多个对象 处理一两个对象很容易但管理几十个对象可能会很麻烦。我们需要稍微优化一下让多个对象也能同时管理。 首先删除或注释sphere、 sphereShape和 sphereBody的相关代码。 自动化功能 首先让我们改进我们创建球体的方式该函数将同时包括 Three.js 和 Cannon.js 创建球体的方法。 作为此函数的参数我们向函数传递radius和position两个值但你也可以再随意添加其他参数例如mass、material、subdivisions等。 /*** Utils*/ const createSphere (radius, position) { }现在我们可以创建 Three.js网格 const createSphere (radius, position) {// Three.js meshconst mesh new THREE.Mesh(new THREE.SphereGeometry(radius, 20, 20),new THREE.MeshStandardMaterial({metalness: 0.3,roughness: 0.4,envMap: environmentMapTexture,envMapIntensity: 0.5}))mesh.castShadow truemesh.position.copy(position)scene.add(mesh) }和 Cannon.js主体 const createSphere (radius, position) {// ...// Cannon.js bodyconst shape new CANNON.Sphere(radius)const body new CANNON.Body({mass: 1,position: new CANNON.Vec3(0, 3, 0),shape: shape,material: defaultMaterial})body.position.copy(position)world.addBody(body) }我们可以删除之前创建的球体并调用createSphere(...)在创建 Cannon.js 世界和 Three.js 场景之后。不要忘记删除tick()函数中的球体更新代码 createSphere(0.5, { x: 0, y: 3, z: 0 })如您所见位置不必是 Three.js Vector3或 Cannon.js Vec3 两个标准中心点 我们可以简单地使用具有x,y和z属性的对象对我们来说很幸运。 您应该看到球体漂浮在地板上方但不幸的是它不再移动了。这是完全正常的因为我们刚才注释或者删除了将 Cannon.js Body 的position属性应用于 Three.js Mesh 的 position 属性的代码。 使用对象数组 为了处理这个问题我们将创建一个包含所有需要更新的对象的数组。然后我们将对象内新创建的Mesh和Body添加到该数组 const objectsToUpdate []const createSphere (radius, position) {// ...// Save in objects to updateobjectsToUpdate.push({mesh: mesh,body: body}) }您可以这样优化重写最后一部分JavaScript 中变量名相同时无需指定属性 objectsToUpdate.push({ mesh, body })我们现在可以在tick()函数内循环遍历该数组在我们更新世界之后并将每个数组body.position数值复制到mesh.position属性里 const tick () {// ...world.step(1 / 60, deltaTime, 3)for(const object of objectsToUpdate){object.mesh.position.copy(object.body.position)} }球体应该再次开始下降。 添加到 Dat.GUI 现在我们可以向我们的 Dat.GUI 添加一个按钮createSphere。问题是使用该gui.add(...)方法时第一个参数应该是一个对象第二个参数应该是一个属性名。不幸的是我们的createSphere是个函数不是一个对象而且还需要向它传递参数。这种情况经常会发生。一个不错的解决方案是我们再创建一个对象其唯一目的是将那些丢失的功能作为属性 const gui new dat.GUI() const debugObject {}然后在需要时向其添加函数在createSphere创建函数之后 debugObject.createSphere () {createSphere(0.5, { x: 0, y: 3, z: 0 }) }最后我们可以将这个新createSphere属性添加到 Dat.GUI gui.add(debugObject, createSphere)如果您单击新创建的createSphere按钮您应该会看到球体相互重叠。这是由于球体在完全相同的位置弹出。让我们添加一些随机性即可防止球体重叠了 debugObject.createSphere () {createSphere(Math.random() * 0.5,{x: (Math.random() - 0.5) * 3,y: 3,z: (Math.random() - 0.5) * 3}) }像下雨了一样 为了尽量不要烧毁你的电脑此代码需要优化。 优化 因为Three.js Mesh的几何体和材质是一样的我们应该把它们从createSphere函数中提取出来。问题是我们正在根据半径radius来创建我们的几何体。一个简单的解决方案是将SphereGeometry的半径radius固定为1然后缩放Mesh const sphereGeometry new THREE.SphereGeometry(1, 20, 20) const sphereMaterial new THREE.MeshStandardMaterial({metalness: 0.3,roughness: 0.4,envMap: environmentMapTexture,envMapIntensity: 0.5 }) const createSphere (radius, position) {// Three.js meshconst mesh new THREE.Mesh(sphereGeometry, sphereMaterial)mesh.castShadow truemesh.scale.set(radius, radius, radius)mesh.position.copy(position)scene.add(mesh)// ... }这样材质都是相同的你应该得到和之前相同的结果并且大大优化了性能。 添加立方体 现在我们的球体运行良好让我们用立方体也进行一次相同的实现过程。 要创建一个立方体我们必须使用一个BoxGeometry和一个Box形状。当心; 参数不一样。BoxGeometry需要一个width、一个height和一个depth。与此同时一个Box形状需要一个halfExtents. 它由Vec3 表示该 Vec3对应于从框的中心开始并连接该框角之一的段 // Create box const boxGeometry new THREE.BoxGeometry(1, 1, 1) const boxMaterial new THREE.MeshStandardMaterial({metalness: 0.3,roughness: 0.4,envMap: environmentMapTexture,envMapIntensity: 0.5 }) const createBox (width, height, depth, position) {// Three.js meshconst mesh new THREE.Mesh(boxGeometry, boxMaterial)mesh.scale.set(width, height, depth)mesh.castShadow truemesh.position.copy(position)https://www.yuque.com/channel1/wvnr6v/dtdmh6s06vgyxn6p/edit#kKBqSscene.add(mesh)// Cannon.js bodyconst shape new CANNON.Box(new CANNON.Vec3(width * 0.5, height * 0.5, depth * 0.5))const body new CANNON.Body({mass: 1,position: new CANNON.Vec3(0, 3, 0),shape: shape,material: defaultMaterial})body.position.copy(position)world.addBody(body)// Save in objectsobjectsToUpdate.push({ mesh, body }) }createBox(1, 1.5, 2, { x: 0, y: 3, z: 0 })debugObject.createBox () {createBox(Math.random(),Math.random(),Math.random(),{x: (Math.random() - 0.5) * 3,y: 3,z: (Math.random() - 0.5) * 3}) } gui.add(debugObject, createBox)不要忘记删除第一个createSphere(...)调用否则您将同时在同一位置创建球体和长方体这可能会变得混乱。 如果你点击Dat.GUI 的createBox按钮, 您应该会看到一个盒子掉落并突然弹跳平移向地板。它看起来不太正常。 我们忘记了一件重要的事情我们的网格没有旋转。这里发生的事情应该是盒子在地板上弹跳起来并倒向一边。但我们所能看到的只是盒子跳起来并一直立着移动了起来很怪异因为 Three.js网格不像 Cannon.js主体那样可以进行旋转所以立方体就一直立着运动了。 我们之前没有看到这个问题因为我们使用的是球体无论我们是否旋转它们它们落地后的物理表现看起来都一样其实他们都不会旋转这不正确。 我们可以通过将Body quaternion复制到Mesh quaternion来解决这个问题就像我们复制position时一样: const tick () {// ...for(const object of objectsToUpdate){object.mesh.position.copy(object.body.position)object.mesh.quaternion.copy(object.body.quaternion)}// ... }箱子现在应该会在落地后倒下了您可以根据需要创建球体和盒子。一如既往尽量不要烧毁你的电脑显卡。 性能 Performance 广相 broadphase 在测试对象之间的碰撞时一种天真的方法是测试每个Body与其他每个Body 的对比。虽然这很容易做到但在性能方面代价高昂。 这就是 broadphase 出现的地方。broadphase在测试之前对身体进行粗略的分类。想象一下两堆箱子彼此远离。你为什么要用一堆的盒子和另一堆的盒子进行测试它们相距太远不会发生碰撞。 Cannon.js 中有 3 种 broadphase 算法可用 NaiveBroadphase : 测试每一个身体对抗每一个其他身体GridBroadphase : Quadrilles the world 并且仅在同一个网格框或邻居的网格框中针对其他主体测试主体。SAPBroadphasebroadphase 扫描和修剪 在多个步骤中测试任意轴上的主体。 broadphase 默认的算法 是NaiveBroadphase我建议你切换到SAPBroadphase。使用这个 broadphase 可能会产生物体不发生碰撞的错误行为但这种情况很少见并且它涉及到做一些事情比如非常快速地移动物体时导致不发生碰撞。 要切换到SAPBroadphase只需在属性中对其进行实例化world.broadphase并使用相同的世界作为参数 world.broadphase new CANNON.SAPBroadphase(world)休眠 Sleep 就算我们使用改进的 broadphase 算法我们所有的身体还是都会被物理测试浪费了性能。那些不再移动的身体我们可以使用sleep称为睡眠的功能。 当Body速度变得非常慢时在您看不到它移动的点Body可能会休眠并且不会被测试除非通过代码对其施加足够的力或者如果另一个Body击中它。 要激活此功能只需将[World](http://schteppe.github.io/cannon.js/docs/classes/World.html).allowSleep属性设置为true world.allowSleep true您还可以使用sleepSpeedLimit和sleepTimeLimit属性控制Body入睡的范围但我们这节课不会更改这些。 事件 您可以在Body上收听事件。如果你想做一些事情比如在物体碰撞时播放声音或者如果你想知道子弹发射是否碰到了敌人这会很有用。 您可以收听Body上的事件例如colide,sleep或wakeup。 当我们的球体和盒子与任何物体发生碰撞时让我们播放撞击声。首先在原生 JavaScript 中创建声音并创建一个播放声音的函数。 某些浏览器如 Chrome会阻止播放声音除非用户与页面进行了交互例如单击任何地方因此如果您没有听到第一个声音请不要担心。 /*** Sounds*/ const hitSound new Audio(/sounds/hit.mp3)const playHitSound () {hitSound.play() }只是播放声音有点牵强但我们稍后会为该功能添加更多内容。 现在让我们来听听collide关于Bodies的事件。我们将只关注createBox函数并在完成后将其添加到createSphere函数中。 现在监听碰撞事件并使用该playHitSound函数作为回调 const createBox (width, height, depth, position) {// ...body.addEventListener(collide, playHitSound)// ... }当立方体接触地面或立方体碰撞时您应该会听到撞击声。如果您使用的是 Chrome请不要忘记在框落地之前点击页面因为如果尚未发生用户交互Chrome 会拒绝播放声音。 声音似乎还不错。不幸的是当我们添加多个框时事情变得非常奇怪那个声音像是犯病了一样一直哒哒哒哒。 第一个问题是当我们在调用hitSound.play()播放声音时没有任何反应因为它已经在播放了。我们可以通过将声音currentTime重置为属性来解决这个0问题 const playHitSound () {hitSound.currentTime 0hitSound.play() }虽然这在物体掉落开始时比较好但即使一个立方体轻微接触另一个立方体我们也会听到太多的撞击声。我们需要知道影响力有多强如果不够强我们就什么都不播放才行。 要获得冲击强度我们首先需要获得有关碰撞的信息。我们可以通过向collide回调这是我们的playHitSound函数添加一个参数来做到这一点 const playHitSound (collision) {console.log(collision)// ... }该collision变量现在包含大量碰撞信息。可以通过调用属性getImpactVelocityAlongNormal()上的方法来找到冲击强度contact const playHitSound (collision) {console.log(collision.contact.getImpactVelocityAlongNormal())// ... }如果您查看日志您应该会看到一个数字。冲击力越强数值越高。 我们测试impactStrength该值并仅在足够强的情况下播放声音 const playHitSound (collision) {const impactStrength collision.contact.getImpactVelocityAlongNormal()if(impactStrength 1.5){hitSound.currentTime 0hitSound.play()} }为了更加真实我们可以为音量添加一些随机性 const playHitSound (collision) {const impactStrength collision.contact.getImpactVelocityAlongNormal()if(impactStrength 1.5){hitSound.volume Math.random()hitSound.currentTime 0hitSound.play()} }如果我们想更加完善这个功能我们可以有多个略有不同的击打声音。为了防止同时播放太多声音我们可以添加一个非常短的延迟使声音在播放一次后无法再次播放。 我们不会在本课中做这些但请随意尝试。 让我们将createBox函数中使用的代码复制到createSphere函数中 const createSphere (radius, position) {// ...body.addEventListener(collide, playHitSound)// ... }移除物体 Remove things 让我们添加一个reset按钮。 创建一个reset函数并将其添加到您的 Dat.GUI 中就像我们对createBox和 createSphere 所做的那样 // Reset debugObject.reset () {console.log(reset) } gui.add(debugObject, reset)现在让我们循环遍历objectsToUpdate数组中的每个对象。然后从object.body 中删除world和从 object.mesh 中删除 scene。另外不要忘记像在本机 JavaScript 中那样删除 eventListener debugObject.reset () {for(const object of objectsToUpdate){// Remove bodyobject.body.removeEventListener(collide, playHitSound)world.removeBody(object.body)// Remove meshscene.remove(object.mesh)} }我们还需要清空objectsToUpdate数组。在 JS 中有许多清空数组的神奇方法其中之一是用splice方法将其内容替换为空 debugObject.reset () {// ...objectsToUpdate.splice(0, objectsToUpdate.length) }就是这样。您可以单击reset按钮删除所有内容。 使用 Cannon.js 走得更远 虽然我们介绍了基础知识并且您已经可以做很多事情但这里有一些需要改进的地方。 约束条件 顾名思义约束可以在两个主体之间启用约束。我们不会在本课中介绍这些内容但这是约束列表 HingeConstraint就像门铰链一样。DistanceConstraint强制物体彼此保持一定距离。LockConstraint合并实体就像它们是一件一样。PointToPointConstraint将主体粘附到特定点。 类、方法、属性和事件 有许多类每个类都有不同的方法、属性和事件。尝试至少浏览一次所有这些以了解它们的存在。它可能会为您在未来的项目中节省一些时间。 例子 文档并不完美。如果您花一些时间在演示和研究中以了解如何开发将会有所帮助。许多人可能遇到了您可能遇到的问题。不要犹豫依靠社区。 多线程workers 运行物理模拟需要时间。执行这项工作的计算机组件是 CPU。当你运行 Three.js、Cannon.js、你的代码逻辑等时一切都由你 CPU 中的同一个线程完成。如果有太多事情要做例如物理模拟中的对象太多该线程会很快过载从而导致帧速率下降。 正确的解决方案是使用多线程。Workers 允许您将一部分代码放在不同的线程中以分散负载。然后您可以从该代码发送和接收数据。它可以显著提高性能。 问题是代码必须明显分开防止竞争资源。您可以在页面源代码中找到一个很好的简单示例。 Cannon-es 正如我们之前所说Cannon.js 多年未更新。幸运的是有些人 fork 了存储库并开始进行更新。多亏了他们我们才能访问更好且维护得更好的 Cannon.js 版本 Git 存储库 https: //github.com/pmndrs/cannon-esNPM 页面https://www.npmjs.com/package/cannon-es 要使用此版本而不是原始版本请在项目文件夹中打开终端或关闭服务器删除之前的 cannon.js 依赖项npm uninstall --save cannon。 至于cannon-es您可以安装最新版本并npm install --save cannon-es更改您在代码中导入 Cannon.js 的方式 import * as CANNON from cannon-es一切都应该像以前一样工作。您可以在Git 存储库页面上查看版本改动。 最新版本应该可以作为直接替代品但如果出现错误您可以使用更具体的版本如0.20测试过的通过运行npm install --save cannon-es0.20. Ammo.js 我们使用 Cannon.js 是因为该库易于实施和理解。它最大的竞争对手之一是 Ammo.js。虽然在您的项目中更难使用和实施但您可能会对以下功能感兴趣 它是 Bullet 的一个移植版Bullet 是一个众所周知且运行良好的物理引擎用 C 编写。它具有 WebAssembly (wasm) 支持。WebAssembly 是大多数最新浏览器都支持的低级语言。因为它是低级别的所以它具有更好的性能。它更受欢迎您可以找到更多 Three.js 的示例。它支持更多功能。 如果您需要最佳性能或在您的项目中具有特定功能您可能应该选择 Ammo.js 而不是 Cannon.js。 Physijs Physijs 简化了 Three.js 项目中物理的实现。它使用 Ammo.js 并原生支持 workers。 网站 https: //chandlerprall.github.io/Physijs/Git 存储库https://github.com/chandlerprall/Physijs文档 https: //github.com/chandlerprall/Physijs/wiki 您无需创建 Three.js 对象和物理对象而是同时创建两者即可 box new Physijs.BoxMesh(new THREE.CubeGeometry(5, 5, 5),new THREE.MeshBasicMaterial({ color: 0x888888 }) ) scene.add(box)Physijs 会处理剩下的事情。 虽然它很吸引人尤其是对于初学者来说但当您尝试做该库不支持的事情时事情就会变得复杂。查找错误的来源也可能很麻烦因为封装过头了。 就像 Ammo.js 一样花点时间想想用哪个物理库是您项目的最佳解决方案。
http://www.zqtcl.cn/news/710802/

相关文章:

  • 做架构图的网站网站和网店的区别
  • 做红包网站简单个人网站设计
  • 新手学做网站pdf手wordpress修改搜索框
  • 做湲兔费网站视颍如何通过查询网站注册时间
  • 重庆cms建站模板南通网站建设推广优化
  • 合肥网站建设的公司新闻类网站如何做量化统计
  • 好用的在线地图网站十六局集团门户网
  • 网站开发数据库连接失败广州网站建站平台
  • 鄂尔多斯北京网站建设加盟网站建设的内容
  • 网站 被 抄袭不属于营销型网站的特点
  • 浙江英文网站建设互联网公司排名2021完整版
  • 完美代码的网站python开发工具
  • 餐饮网站开发参考文献网站建设500错误代码
  • 网站开发关键技术网站自动推广软件免费
  • 前端学习网站南阳东莞网站建设公司哪家好
  • 关于做网站的了解点wordpress小程序插曲
  • PHP网站开发与管理设计心得个人可以做聊天网站备案吗
  • 开公司可以在哪些网站做推广上海画册设计
  • 成都高新区规划建设局网站网络营销方式有哪些?举例说明
  • 国家企业信用公信系统入口seo服务
  • 个人网站网页模板室内装修设计自学软件
  • 什么网站可以做告白的网页网站模板套用湖南岚鸿
  • 膜结构网站推广怎么做怎样把网站上传到空间
  • 三维网站是怎么做的商城网站 运营
  • 程序员网站开发框架无锡网络公司网站建设app微信公众号平
  • 中关村网站建设网络营销策划书范文
  • 电商网站建设与课程设计科技网站模版
  • 建设部网站资质漳州最专业的网站建设公司
  • 网站建设需求和页面需求怎么提一个静态网站怎么做
  • 宝塔wordpress广州网站营销seo