Răsfoiți Sursa

1、新增声音模块,使用任务逻辑触发声音特效

liyanbo 4 luni în urmă
părinte
comite
0967a3ebaa

BIN
src/assets/music/blockly/error.MP3


BIN
src/assets/music/blockly/failure.MP3


BIN
src/assets/music/blockly/pass.MP3


+ 91 - 0
src/components/blockly/MapGame.vue

@@ -85,6 +85,7 @@
             <block type="pickup_item"></block>
             <block type="use_item"></block>
             <block type="pause"></block>
+            <block type="play_sound"></block>
           </category>
 
           <!-- 逻辑控制积木 -->
@@ -131,6 +132,11 @@ import 'blockly/msg/zh-hans';
 import { javascriptGenerator } from "blockly/javascript";
 import playerImage from '@/assets/images/blockly/user.png';
 
+// 导入音频文件
+import passMp3 from '@/assets/music/blockly/pass.MP3';
+import failureMp3 from '@/assets/music/blockly/failure.MP3';
+import errorMp3 from '@/assets/music/blockly/error.MP3'
+
 // 游戏接口数据
 import { getMapGameById } from '@/api/blockly/game.js';
 
@@ -218,6 +224,7 @@ const CONFIG = {
     LOOP_PREVENTION: 10,     // 循环防止UI阻塞的延迟
     ITEMS_APPEAR: 300,      // 物品出现延迟时间
     ITEMS_FLIGHT_ANIMATION_DELAY: 800, // 飞行动画延迟时间
+    PALY_MP3_TIMES: 1000,     // 播放MP3文件的时间间隔
   },
   // 游戏配置
   GAME: {
@@ -702,6 +709,21 @@ function registerCustomBlocks() {
       });
     }
   };
+
+  // 声音积木
+  Blockly.Blocks['play_sound'] = {
+    init: function() {
+      this.jsonInit({
+        "type": "play_sound",
+        "message0": "播放声音",
+        "previousStatement": null,
+        "nextStatement": null,
+        "colour": 160,
+        "tooltip": "自动触发特效提示音,并根据当前方格类型执行相应操作",
+        "helpUrl": ""
+      });
+    }
+  };
 }
 
 // 注册JavaScript生成器
@@ -742,6 +764,11 @@ function registerJavaScriptGenerators() {
     return `await pause(${seconds});\n`;
   };
 
+  // 声音生成器
+  javascriptGenerator.forBlock['play_sound'] = function(block) {
+    return 'await playSound();\n';
+  };
+
   // 为重复循环块注册自定义生成器,确保支持异步操作
   javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) {
     const repeats = javascriptGenerator.valueToCode(block, 'TIMES', javascriptGenerator.ORDER_ATOMIC) || '0';
@@ -1573,6 +1600,70 @@ window.turnAround = async function() {
   await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
 };
 
+// 播放声音函数
+window.playSound = async function() {
+  if (shouldStopExecution || isColliding.value || isSliding.value) {
+    return;
+  }
+
+  // 取人物当前位置
+  let x = playerPosition.value.x;
+  let y = playerPosition.value.y;
+  let tileMap = walkablePointsMap.get(`${x},${y}`);
+
+  // 根据当前方格类型执行相应操作(与声音播放同时进行)
+  if (tileMap) {
+
+    // 判断当前位置是否有特殊需求
+    if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.TASK) {
+
+        // 从地图上移除图标(但保留点的可通行性)
+        const pointIndex = gameState.mapData.walkablePoints.findIndex(
+            p => p.x === x && p.y === y
+        );
+        if (pointIndex !== -1) {
+
+          // 保留点但移除img属性并设置完成状态图标
+          const updatedPoint = { ...gameState.mapData.walkablePoints[pointIndex] };
+          updatedPoint.img = updatedPoint.endImg; // 设置完成状态图标
+          updatedPoint.status = true;
+          gameState.mapData.walkablePoints.splice(pointIndex, 1, updatedPoint);
+
+          // 更新映射
+          walkablePointsMap.set(`${x},${y}`, updatedPoint);
+        }
+
+        // 使用物品成功
+        showGameMessage(tileMap.finishedTip || CONFIG.TIPS.USE_ITEM_SUCCESS, 'success');
+        //增加延迟,确保声音播放完成
+        await playMp3(passMp3);
+        await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.PALY_MP3_TIMES));
+        return
+    } else {
+      showGameMessage(CONFIG.TIPS.NO_USE_ITEM, 'info');
+    }
+  }
+
+  //增加延迟,确保声音播放完成
+  await playMp3(failureMp3);
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.PALY_MP3_TIMES));
+};
+
+const playMp3 = async function(audioUrl) {
+  try {
+    // 创建音频对象,播放声音特效
+    const soundEffect = new Audio(audioUrl);
+
+    // 非阻塞方式播放音频
+    soundEffect.play().catch(error => {
+      console.error('播放声音特效失败:', error);
+    });
+
+  } catch (error) {
+    console.error('创建声音特效失败:', error);
+  }
+};
+
 //校验是否到达终点
 window.isFinish = async function() {
   // 如果已经发生过碰撞,不再执行任何检查