飛機大戰相信你們都玩過,好多同窗甚至本身寫過,無論你是用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 ,在公衆號後臺回覆:飛機大戰獲取完整代碼。
若是本文對你有幫助,歡迎關注、點贊、評論。