林旭祥 2 روز پیش
والد
کامیت
7e6e1a75b9
1فایلهای تغییر یافته به همراه199 افزوده شده و 4 حذف شده
  1. 199 4
      src/views/game/basketball.vue

+ 199 - 4
src/views/game/basketball.vue

@@ -5,8 +5,160 @@
   </div>
 </template>
 
-<script setup>
+<script setup name="Basketball" lang="ts">
 import { onMounted, ref, reactive, onBeforeUnmount } from 'vue';
+import { initSpeech, speckText, playMusic, controlMusic, speckCancel, chineseNumber } from '@/utils/speech';
+import { useWebSocket } from '@/utils/bodyposeWs';
+const { proxy } = getCurrentInstance() as any;
+const router = useRouter();
+const { bodyposeWs, startDevice, checkBodypose, openBodypose, terminateBodypose, suspendBodypose, resumeBodypose, getBodyposeState, closeWS } = useWebSocket();
+
+const data = reactive<any>({
+  bodyposeData: {},//姿态信息
+  bodyposeState: false,//姿态识别窗口状态
+  parameter: {},//参数
+  deviceInfo: {},//设备信息
+  againNum: 0,//再次启动次数
+  againTimer: null,//定时状态
+  wsState: false,//WS状态
+  clientObj: {},//浏览器对象
+});
+
+const { bodyposeData, bodyposeState, parameter, deviceInfo, againNum, againTimer, wsState, clientObj } = toRefs(data);
+
+/**
+ * 初始化
+ */
+const getInit = async () => {
+  console.log("触发姿态识别")
+  let deviceid = localStorage.getItem('deviceid') || '';
+  if (!deviceid) {
+    proxy?.$modal.msgError(`请重新登录绑定设备号后使用`);
+    return false;
+  }
+  bodyposeState.value = true;
+  if (wsState.value) {
+    proxy?.$modal.msgWarning(`操作过快,请稍后重试`);
+    setTimeout(() => {
+      bodyposeState.value = false;
+    }, 1000)
+    return false;
+  }
+  speckText("正在姿态识别");
+  bodyposeWs((e: any) => {
+    console.log("bodyposeWS", e)
+    if (e?.wksid) {
+      wsState.value = true;
+      //获取设备信息
+      startDevice({ deviceid: deviceid });
+      console.log("获取设备信息")
+    }
+    if (e?.type == 'fe_device_init_result') {
+      //接收设备信息并发送请求
+      if (e?.device_info) {
+        deviceInfo.value = e.device_info;
+        getCheckBodypose();
+        console.log("返回设备信息,检查是否支持姿态识别")
+      } else {
+        proxy?.$modal.msgError(`设备信息缺失,请重新登录绑定设备号后使用`);
+      }
+    }
+    if (e?.cmd == 'check_bodyposecontroller_available') {
+      let handcontroller_id = deviceInfo.value.handcontroller_id;
+      if (e?.code == 0) {
+        //查看姿态识别状态,如果不处于关闭就先关闭再重新启动(可能会APP退出然后工作站还在运行的可能性)
+        getBodyposeState(handcontroller_id);
+        againNum.value = 0;
+        againTimer.value = null;
+        clearTimeout(againTimer.value);
+        console.log("查看姿态识别状态")
+      } else {
+        //尝试多次查询姿态识别状态
+        if (againNum.value <= 2) {
+          againTimer.value = setTimeout(() => {
+            getCheckBodypose();
+          }, 500)
+          againNum.value++;
+        } else {
+          let msg = "";
+          if (e.code == 102402) {
+            msg = `多次连接失败请重试,姿态识别模块被占用`;
+          } else {
+            msg = `多次连接失败请重试,姿态识别模块不可用,code:${e.code}`;
+          }
+          proxy?.$modal.msgWarning(msg);
+          againNum.value = 0;
+          againTimer.value = null;
+          clearTimeout(againTimer.value);
+          getCloseBodypose();//直接关闭 
+        }
+
+      }
+    }
+    if (e?.cmd == 'get_bodyposecontroller_state') {
+      let handcontroller_id = deviceInfo.value.handcontroller_id;
+      //state说明: 0:关闭,3:空闲,36:工作中
+      if ([3, 36].includes(e.state)) {
+        getCloseBodypose();
+        proxy?.$modal.msgWarning(`请重新姿态识别`);
+      } else {
+        openBodypose(handcontroller_id);
+      }
+    }
+    if (e?.type == 'bodyposecontroller_result') {
+      let arr = e.data.result.keypoints;
+      let result = [];
+      for (let i = 0; i < arr.length; i += 3) {
+        result.push(arr.slice(i, i + 2));
+      }
+      console.log("result", result)
+      bodyposeData.value = result;
+      getCanvas(result);
+    }
+    if (e?.cmd == 'terminate_bodyposecontroller') {
+      if (e?.code == 0) {
+        closeWS();
+        bodyposeState.value = false;
+      }
+    }
+    if (e?.type == 'disconnect') {
+      wsState.value = false;
+    }
+  });
+};
+
+
+/**
+ * 查询姿态识别状态
+*/
+const getCheckBodypose = () => {
+  let handcontroller_id = deviceInfo.value.handcontroller_id;
+  //检查是否支持姿态识别
+  checkBodypose(handcontroller_id);
+};
+
+/**
+ * 关闭姿态识别
+*/
+const getCloseBodypose = () => {
+  let handcontroller_id = deviceInfo.value.handcontroller_id;
+  terminateBodypose(handcontroller_id);
+  bodyposeState.value = false;
+  speckCancel(); //停止播报
+  setTimeout(() => {
+    if (wsState.value) {
+      closeWS();
+    }
+  }, 3000)
+};
+
+
+const getCanvas = (data) => {
+  const analyzer = new TrendAnalyzer();
+  if (analyzer.addPoint(data[10][0],data[10][1])) {
+    handleMouseDown();
+  }
+};
 
 // 游戏主类的响应式状态
 const gameState = reactive({
@@ -524,12 +676,50 @@ const initGame = async () => {
   gameState.animationFrameId = requestAnimationFrame(gameLoop);
 };
 
+class TrendAnalyzer {
+  constructor(minPoints = 5, threshold = 0) {
+    this.points = [];
+    this.minPoints = minPoints; // 判断趋势所需的最小点数
+    this.threshold = threshold; // 定义最小上升幅度
+  }
+
+  addPoint(x, y) {
+    this.points.push({ x, y });
+    // 保持数组长度适中,仅保留分析所需的点
+    if (this.points.length > this.minPoints + 1) {
+      this.points.shift();
+    }
+    return this.isIncreasing();
+  }
+
+  isIncreasing() {
+    if (this.points.length < this.minPoints) {
+      return false;
+    }
+
+    let increasingCount = 0;
+    for (let i = 1; i < this.points.length; i++) {
+      // 计算斜率:(y2 - y1) / (x2 - x1)
+      const slope = (this.points[i].y - this.points[i - 1].y) /
+        (this.points[i].x - this.points[i - 1].x);
+
+      // 若斜率大于阈值,则视为上升
+      if (slope > this.threshold) {
+        increasingCount++;
+      }
+    }
+
+    // 要求至少有 minPoints-1 个连续上升的线段
+    return increasingCount >= this.points.length - 1;
+  }
+}
+
 // 生命周期钩子
 onMounted(() => {
   initGame();
-  setInterval(()=>{
-    handleMouseDown()
-  },500)
+  // setInterval(() => {
+  //   handleMouseDown()
+  // }, 500)
 });
 
 onBeforeUnmount(() => {
@@ -537,6 +727,11 @@ onBeforeUnmount(() => {
     cancelAnimationFrame(gameState.animationFrameId);
   }
   window.removeEventListener('resize', resizeToWindow);
+  getInit();
+});
+
+onBeforeUnmount(() => {
+  closeWS();
 });
 </script>