|
@@ -4,11 +4,164 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<script setup name="Fruit">
|
|
|
+<script setup name="Fruit" lang="ts">
|
|
|
import { onMounted, ref } from 'vue';
|
|
|
import Phaser from 'phaser';
|
|
|
-const { proxy } = getCurrentInstance();
|
|
|
+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 gameRef = ref(null); // 用于保存游戏实例的ref
|
|
|
+
|
|
|
+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) => {
|
|
|
+ console.log("data",data)
|
|
|
+ externalMethod(data[10][0],data[10][1])
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
// 游戏容器和尺寸相关
|
|
|
|
|
|
const width = document.documentElement.clientWidth;
|
|
@@ -564,7 +717,7 @@ class Blade {
|
|
|
});
|
|
|
// 监听鼠标移动事件(可选,也可在update中处理)
|
|
|
this.game.input.on('pointermove', (pointer) => {
|
|
|
- console.log("11111",pointer)
|
|
|
+ //console.log("11111", pointer)
|
|
|
if (this.allowBlade) {
|
|
|
this.handleMouseMove(pointer);
|
|
|
}
|
|
@@ -802,7 +955,7 @@ class MainScene extends Phaser.Scene {
|
|
|
// this.home_mask.setOrigin(0, 0);
|
|
|
// this.home_mask.setScale(wRatio);
|
|
|
// this.home_mask.y = -200;
|
|
|
-
|
|
|
+
|
|
|
//logo
|
|
|
this.logo = this.add.image(20, 50, "logo");
|
|
|
this.logo.setOrigin(0, 0);
|
|
@@ -1362,6 +1515,54 @@ class PlayScene extends Phaser.Scene {
|
|
|
}
|
|
|
|
|
|
|
|
|
+// 外部方法(如Vue组件中的某个按钮点击事件)
|
|
|
+const externalMethod = (autoX, autoY) => {
|
|
|
+
|
|
|
+ // 1. 获取游戏实例(从之前保存的gameRef中)
|
|
|
+ const game = gameRef.value;
|
|
|
+ if (!game) {
|
|
|
+ console.error("游戏未初始化");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ console.log("game", game)
|
|
|
+ // 2. 获取目标场景(根据当前活跃场景选择'main'或'play')
|
|
|
+ // 例如:获取PlayScene(场景key为'play')
|
|
|
+ const currentScene = getActiveScene();
|
|
|
+ const targetScene = game.scene.getScene(currentScene);
|
|
|
+ // 若当前在主场景,可改为 game.scene.getScene('main')
|
|
|
+
|
|
|
+ // 3. 检查场景中的Blade实例是否存在且已启用
|
|
|
+ if (!targetScene || !targetScene.blade || !targetScene.blade.allowBlade) {
|
|
|
+ console.error("Blade实例未初始化或未启用");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 4. 构造模拟的pointer参数(包含x和y)
|
|
|
+ const mockPointer = {
|
|
|
+ x: autoX, // 外部传入的X坐标
|
|
|
+ y: autoY // 外部传入的Y坐标
|
|
|
+ };
|
|
|
+
|
|
|
+ // 5. 调用Blade的handleMouseMove方法
|
|
|
+ targetScene.blade.handleMouseMove(mockPointer);
|
|
|
+};
|
|
|
+
|
|
|
+const getActiveScene = () => {
|
|
|
+ const game = gameRef.value; // 获取游戏实例
|
|
|
+ if (!game) return null;
|
|
|
+
|
|
|
+ // 获取所有活跃场景(通常只有一个)
|
|
|
+ const activeScenes = game.scene.getScenes(true);
|
|
|
+
|
|
|
+ // 返回第一个活跃场景(如果有)
|
|
|
+ return activeScenes.length > 0 ? activeScenes[0].scene.key : null;
|
|
|
+};
|
|
|
+
|
|
|
+onBeforeMount(() => {
|
|
|
+ getInit();
|
|
|
+});
|
|
|
+
|
|
|
// 初始化游戏
|
|
|
onMounted(() => {
|
|
|
// 获取容器尺寸
|
|
@@ -1383,6 +1584,30 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
+ gameRef.value = game;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 模拟自动接收坐标数据(例如WebSocket回调)
|
|
|
+ function onReceiveCoordinate(data) {
|
|
|
+ // data格式:{ x: 100, y: 200 }
|
|
|
+ if (data.x !== undefined && data.y !== undefined) {
|
|
|
+ externalMethod(data.x, data.y); // 调用外部方法,传入坐标
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 示例:每50ms发送一组随机坐标
|
|
|
+ // setInterval(() => {
|
|
|
+ // const randomX = Math.random() * width; // width是屏幕宽度
|
|
|
+ // const randomY = Math.random() * height; // height是屏幕高度
|
|
|
+ // onReceiveCoordinate({ x: randomX, y: randomY });
|
|
|
+ // }, 50);
|
|
|
+
|
|
|
+
|
|
|
+});
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ closeWS();
|
|
|
});
|
|
|
</script>
|
|
|
|