实现步骤
1.将Ammo导入 webpack使用Ammo.js - 在react中使用Ammo.js
2. 加载球架和场地模型
3. 针对模型中的每个物体的每个面进行Ammo物理构建
4. 控制相机移动
5. 创建篮球 设置篮球的球体Ammo数据
6. 按住键盘蓄力,抬起键盘投篮

代码仓库

难点:
Ammo.js对不规则形状模型添加检测

体验地址

代码:

/** @Author: hongbin* @Date: 2023-03-08 10:59:25* @LastEditors: hongbin* @LastEditTime: 2023-03-10 20:00:30* @Description:篮球游戏*/
import Layout from "@/src/components/Three/Layout";
import { ThreeHelper } from "@/src/ThreeHelper";
import { KeyBoardListener } from "@/src/ThreeHelper/utils/KeyBoardListener";
import { createRef, FC, Fragment, useImperativeHandle, useState } from "react";
import styled from "styled-components";
import * as THREE from "three";
import { Object3D } from "three";
import Ammo from "../../../../src/ThreeHelper/physics/ammo.wasm";
import { AmmoPhysics } from "../../../../src/ThreeHelper/physics/AmmoPhysics";interface IProps {}const percentRef = createRef<{ setPercent: (p: number) => void }>();const Physics: FC<IProps> = () => {const [percent, setPercent] = useState(0);useImperativeHandle(percentRef,() => ({setPercent: (percent: number) => {setPercent(percent);},}),[]);return (<Fragment><Layouttitle={"篮球游戏 物理引擎 Ammo"}init={init}desc="使用three的Ammo助手-客户端渲染"/><Bar percent={percent} /></Fragment>);
};export default Physics;const Bar = styled.div<{ percent: number }>`width: 40vw;height: 1vw;position: fixed;top: 80vh;border: 1px solid ${(props) => (!!props.percent ? "#fff" : "transparent")};left: 30vw;transition: 0.3s;::after {content: "";background: #df4b02;height: 100%;width: ${(props) => props.percent + "%"};position: absolute;}
`;const init = (helper: ThreeHelper) => {helper.addAxis();helper.addStats();helper.camera.position.set(0, 1, 2);helper.controls.target.y += 1;helper.frameByFrame();helper.addGUI();Ammo().then(async (Ammo: any) => {const ammoPhysics = AmmoPhysics(Ammo);const floor = createFloor();helper.add(floor);ammoPhysics.addMesh(floor, 0, { restitution: 0.1 });await loadArea(helper, Ammo, ammoPhysics);const [keyBoardControl, person] = controlledCamera(helper, ammoPhysics);basketball(helper, Ammo, ammoPhysics);const diff = new THREE.Vector3();helper.animation(() => {diff.copy(person.position);const deltaTime = helper.clock.getDelta();keyBoardControl.update();ammoPhysics.stepSimulation(deltaTime, 10);diff.sub(person.position);helper.camera.position.sub(diff);helper.controls.target.sub(diff);});});
};class KeyBoardControl {private vector = new THREE.Vector3();private _call?: (v: Vector3) => void;private scaled = 0.1;private readonly moveCodeEvent = {KeyW: (vec: Vector3) => {vec.z = -this.scaled;},KeyS: (vec: Vector3) => {vec.z = this.scaled;},KeyA: (vec: Vector3) => {vec.x = -this.scaled;},KeyD: (vec: Vector3) => {vec.x = this.scaled;},Space: (vec: Vector3) => {vec.y = this.scaled;},};private moveCode = Object.keys(this.moveCodeEvent) as Array<keyof typeof this.moveCodeEvent>;private KeyBoardListener = new KeyBoardListener();call(back: (v: Vector3) => void) {this._call = back;this.moveCode.forEach((code) => {this.KeyBoardListener.listenKey(code, () => {});});this.KeyBoardListener.keyBoardListen();}update() {if (this._call) {this.vector.set(0, 0, 0);this.moveCode.forEach((code) => {if (this.KeyBoardListener.listenPool[code].isPress) {this.moveCodeEvent[code](this.vector);}});// if (this.vector.x || this.vector.y || this.vector.z) {this._call(this.vector);// }}}
}function createFloor(): Mesh {const width = 50;const height = 2;const depth = 50;const mesh = new THREE.Mesh(new THREE.BoxGeometry(width, height, depth),new THREE.MeshPhysicalMaterial({color: new THREE.Color("#2f029f"),metalness: 0.5,roughness: 1,transparent: true,opacity: 0.4,}));mesh.position.y = -2;return mesh;
}/*** 控制相机移动*/
function controlledCamera(helper: ThreeHelper,ammoPhysics: ReturnType<typeof AmmoPhysics>
): [KeyBoardControl, Mesh] {helper.add(helper.camera);const keyBoardControl = new KeyBoardControl();const person = helper.generateRect({ width: 0.5, height: 1, depth: 0.2 });// helper.add(person);ammoPhysics.addMesh(person, 10, {needMove: true,});const position = new THREE.Vector3();const quaternion = new THREE.Quaternion();keyBoardControl.call((v) => {if (v.x || v.y || v.z) {position.copy(person.position);const angle = helper.controls.getAzimuthalAngle();v.applyAxisAngle(Object3D.DefaultUp, angle);position.add(v);ammoPhysics.setMeshPosition(person, position);ammoPhysics.setMeshQuaternion(person, quaternion);}});return [keyBoardControl, person];
}/*** 加载场地*/
async function loadArea(helper: ThreeHelper,ammo: any,ammoPhysics: ReturnType<typeof AmmoPhysics>
) {const gltf = await helper.loadGltf("/models/boll.glb");helper.add(gltf.scene);gltf.scene.traverse((obj) => {//@ts-ignoreif (obj.isMesh) {ammoPhysics.addMeshByTriangle(obj as Mesh,0,{restitution: 0.1,friction: 1,},obj.name.includes("篮筐"));}});
}/*** 篮球*/
function basketball(helper: ThreeHelper,ammo: any,ammoPhysics: ReturnType<typeof AmmoPhysics>
) {const sphere = new THREE.Mesh(new THREE.SphereGeometry(0.1, 12, 12),new THREE.MeshPhysicalMaterial({ color: 0x4411ff }));sphere.position.copy(helper.camera.position);sphere.position.z -= 1;sphere.position.y += 1;ammoPhysics.addMesh(sphere, 1, { restitution: 1, needMove: true });const dir = new THREE.Vector3();let start = 0;let duration = 0;/*** 按下Q键 根据时间决定力度*/const press = () => {start == 0 && (start = performance.now());duration = Math.min(100, (performance.now() - start) / 10);percentRef.current?.setPercent(duration);};/*** 抬起Q键*/const up = () => {start = 0;percentRef.current?.setPercent(0);const p = helper.camera.position.clone();ammoPhysics.setMeshPosition(sphere, p);helper.camera.getWorldDirection(dir);const body = sphere.userData.body;dir.multiplyScalar(duration / 4);body.setLinearVelocity(new ammo.btVector3(dir.x, dir.y * 1.4, dir.z));};helper.listenKey("KeyQ", press, up);helper.add(sphere);return sphere;
}

Three.js使用ammo.js实现投篮游戏相关推荐

  1. 微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js)

    微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js) 微信小游戏 demo 飞机大战 代码分析(一)(main.js) 微信小游戏 demo 飞 ...

  2. 打砖块小游戏php程序,利用原生js实现html5打砖块小游戏(代码示例)

    本篇文章给大家通过代码示例介绍一下利用原生js实现html5打砖块小游戏的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 前言 PS:本次项目中使用了大量 es6 语法,故对于 ...

  3. php跳一跳小游戏,原生JS实现的跳一跳小游戏完整实例

    本文实例讲述了原生JS实现的跳一跳小游戏.分享给大家供大家参考,具体如下: 以下说的是闲暇编写的一个小游戏--跳一跳,类似于微信的跳一跳,大体实现功能有: 1.先随机生成地图: 2.按住按钮释放后完成 ...

  4. html实现跳跳棋游戏,原生JS实现的跳一跳小游戏完整实例

    本文实例讲述了原生JS实现的跳一跳小游戏.分享给大家供大家参考,具体如下: 以下说的是闲暇编写的一个小游戏--跳一跳,类似于微信的跳一跳,大体实现功能有: 1.先随机生成地图: 2.按住按钮释放后完成 ...

  5. web版拳皇,使用html,css,js来制作一款拳皇游戏

    web版拳皇,使用html,css,js来制作一款拳皇游戏 游戏简介 <拳皇>是1994年日本SNK公司旗下在MVS游戏机板上发售的一款著名对战型格斗街机游戏,简称"KOF&qu ...

  6. C语言编一个金山打字通小游戏,js实现金山打字通小游戏

    本文实例为大家分享了js实现金山打字通小游戏的具体代码,供大家参考,具体内容如下 字母匀速随机下落,键盘按下对应字母按键,字母消失重新生成新字母,新字母可帮助回调一部分初始高度 效果 1.页面内容 列 ...

  7. 单机版斗地主游戏源代码,纯JS编写的斗地主单机版小游戏源代码

    单机版斗地主游戏源代码,纯JS编写的斗地主单机版小游戏源代码,下载游戏后,直接运行index.html即可. 完整代码下载地址:单机版斗地主游戏源代码 index.html <!DOCTYPE ...

  8. js HTML5 网页版植物大战僵尸游戏

    js HTML5 网页版植物大战僵尸游戏 源于:http://www.huiyi8.com/moban/ 植物大战僵尸Javascript版 HTML5模版 body{-moz-user-select ...

  9. 使用CocosCreator+JS 完成Flappybrid(像素鸟)小游戏

    使用CocosCreator+JS 完成Flappybrid(像素鸟)小游戏 前言 这是我在刚开始学Cocos做游戏时做的第一个小游戏.当时做了两个版本数学版和碰撞组件版. 环境 开发工具: Coco ...

最新文章

  1. Java:网络编程值TCP的使用
  2. Karaf 基于 osgi
  3. python数据分析和可视化——一篇文章足以(未完成)
  4. flow 静态类型检查 js
  5. 降低前端业务复杂度新视角:状态机范式
  6. android系统电视缺点,高清智能电视安卓系统优势与不足解析
  7. crc循环校验原理和实现
  8. linux php7 yum 卸载,Linux_在Centos中yum安装和卸载软件的使用方法,安装一个软件时 yum -y install h - phpStudy...
  9. C/C++ 工具函数 —— 大端模式和小端模式的互换
  10. 《正版 图解语音识别 语音识别入门实践教程 语音识别技术书 人工智能机器学习深度学习计算机网络编程书籍R3Z978》[日]荒木雅弘著【摘要 书评 在线阅读】-苏宁易购图书...
  11. 【原创翻译】深入理解javascript事件处理函数绑定三部曲(一)——早期的事件处理函数...
  12. 基于jQuery的判断iPad、iPhone、Android是横屏还是竖屏的代码
  13. java 调用oracle函数_java – 用Spring的SimpleJdbcCall来调用Oracle函数
  14. 图像处理之图像分割(一)之活动轮廓模型:Snake算法简单梳理
  15. 【经典】zheng项目搭建
  16. 自学Java语言网络编程局域网内与电脑无线传输视频,图片文件,调用系统媒体播放视频图片文件
  17. C++中const int*, const int * const, 和 int const *区别
  18. MySQL 基础知识入门教程
  19. 防火墙对FTP主动和被动模式的影响
  20. centos搭建samba服务器

热门文章

  1. web怎么将dwg转换图片_CAD转JPG图片,在线转换成高质量彩色图片
  2. Openstack容器项目之Magnum
  3. STS配置Gradle
  4. 企业微信应用授权,第一次不授权手机号后如何再次开启
  5. 创建maven或者Gradle项目的时候GroupId和ArtifactId以及Version是什么意思?
  6. OpenLayers3加载百度地图
  7. 基于java+jsp+mysql的酒店预订系统
  8. Flash游戏制作规划与流程漫谈
  9. 26个顶级开源项目,87个开放任务,阿里巴巴编程之夏2022学生报名通道开启
  10. 大学计算机教程 曾俊,大学计算机基础教程:曾俊//李柳柏 : 电子电脑 :计算机技术 :计算机原理与基础 :浙江新华书店网群...