飞机大战相信你们都玩过,好多同窗甚至本身写过,无论你是用js仍是用java,是用原生代码实现仍是使用游戏引擎实现。无非就是使用鼠标或者手指触控来在屏幕上拖动飞机移动来打飞机,但我相信你应该尚未玩过使用手势隔空来控制飞机吧。javascript
那今天咱们就来开发一款飞机大战游戏,而后使用手势隔空操控飞机。css
先上demo: 飞机大战html
注意:须要开启电脑摄像头java
为了实现手势控制,咱们就须要可以经过电脑摄像头来识别手部的动做。这里咱们使用到了MediaPip。android
MediaPipe 是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架。在谷歌,一系列重要产品,如 、Google Lens、ARCore、Google Home 以及 ,都已深度整合了 MediaPipe。git
做为一款跨平台框架,MediaPipe 不只能够被部署在服务器端,更能够在多个移动端 (安卓和苹果 iOS)和嵌入式平台(Google Coral 和树莓派)中做为设备端机器学习推理 (On-device Machine Learning Inference)框架npm
Media Pip支持使用js实现人脸网格拓扑,人脸检测,手部检测,全身检测和姿式识别等。canvas
为了实现使用手势控制飞机,那么咱们须要识别出手部动做。api
MediaPip能够识别人手,而且将手部结构按关节进行拓扑,识别结果为保存在两个对象中:数组
原理很简单,就是使用摄像头手别手部,MediaPip能够识别手部21个关节,咱们可使用食指尖这个点来控制飞机移动。即下标为8的点:INDEX_FINGER_TIP的坐标赋值给飞机。其实就至关于使用食指替代了鼠标。
好,原理清楚以后,上代码:
建立html文件,引入三个js库:
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script>
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script> <link rel="stylesheet" href="demo.css"> </head> <body> <div class="container"> <!-- 小飞机 -->  <!-- video用来开启摄像头 --> <video class="input_video"></video> <!-- 用来绘制识别内容 --> <canvas class="output_canvas" width="1280px" height="720px" ></canvas> <!-- loading 效果,当摄像头开启成功后会隐藏 --> <div class="loading"> <div class="spinner"></div> <div class="message"> Loading </div> </div> </div> <script src="./demo.js"></script> </body> </html>
建立Hands对象:
const hands = new Hands({ locateFile: (file) => { return `https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.1/${file}`; } });
里面这个file是为了识别手须要加载的资源文件。
设置默认选项:
hands.setOptions({ selfieMode: true, //是否自拍,便是否使用前置摄像头 maxNumHands: 1, //最大识别手部数量 minDetectionConfidence: 0.5, //识别精度,这个数值越高,则要求图像高评分才能被识别 默认 0.5 minTrackingConfidence: 0.5 //跟踪速度,数值越高,花费时间越长 });
开启摄像头,把摄像头捕捉的画面传给hands对象:
const camera = new Camera(videoElement, { onFrame: async () => { await hands.send({ image: videoElement }); }, width: 1280, height: 720 }); camera.start();
获取识别结果:
function onResults(results) { // 隐藏loading动画 document.body.classList.add('loaded'); // Draw the overlays. canvasCtx.save(); // 清空画布 canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height); // 绘制摄像头捕捉画面 canvasCtx.drawImage( results.image, 0, 0, canvasElement.width, canvasElement.height); // 识别结果保存在multiHandLandmarks和multiHandedness对象中,若是这两个对象不为null,则说明识别成功 if (results.multiHandLandmarks && results.multiHandedness) { // 遍历multiHandLandmarks,得到每一个hand的信息 for (let index = 0; index < results.multiHandLandmarks.length; index++) { const classification = results.multiHandedness[index]; const isRightHand = classification.label === 'Right'; // 一个手的关节信息 const landmarks = results.multiHandLandmarks[index]; // 下标为8的关节就是食指,坐标值为宽高的百分比,和画布宽高相乘就获得坐标 let x = landmarks[8].x * 1280; let y = landmarks[8].y * 720; //把手指坐标赋值非小飞机 hero.style.left = x - 50 + 'px'; hero.style.top = y - 40 + 'px'; // 绘制手部拓扑图 drawConnectors( canvasCtx, landmarks, HAND_CONNECTIONS, { color: isRightHand ? '#00FF00' : '#FF0000' }), drawLandmarks(canvasCtx, landmarks, { color: isRightHand ? '#00FF00' : '#FF0000', fillColor: isRightHand ? '#FF0000' : '#00FF00', radius: (x) => { return lerp(x.from.z, -0.15, .1, 10, 1); } }); } } canvasCtx.restore(); } hands.onResults(onResults);
识别结果保存在multiHandLandmarks和multiHandedness对象中:
multiHandLandmarks是一个二维数组,每个数组中保存了21个关节坐标信息。把食指坐标赋值给飞机,就能够控制飞机移动了。
而后再加一点点细节,咱们的飞机大战就完成了:
好了完成了。
这里咱们只实现了简单的跟随效果。若是再经过计算关节之间的位置关系和运动方向,那么就能够识别更复杂的手势,好比实现手势翻页,点击按钮,相似华为手机的手势识别。
不过除此以外,咱们还能够作得更多,加上面部识别和体态识别,你甚至能够开发体感游戏。
后期我也会尝试开发一些更有意思的应用,欢迎你们持续关注。
关注公众号H5Talks ,在公众号后台回复:飞机大战获取完整代码。
若是本文对你有帮助,欢迎关注、点赞、评论。