瀏覽代碼

1、优化编程课修建模块单独处理任务完成动画效果

liyanbo 3 月之前
父節點
當前提交
fd8355e86b
共有 1 個文件被更改,包括 203 次插入10 次删除
  1. 203 10
      src/components/blockly/MapGame.vue

+ 203 - 10
src/components/blockly/MapGame.vue

@@ -294,6 +294,8 @@ const CONFIG = {
     USE_ITEM_SUCCESS: '使用物品成功',
     USE_SPECIAL_ITEM: '需要特殊物品才能使用',
     NO_USE_ITEM: '当前位置不需要使用物品',
+    TASK_SUCCESS: '任务完成成功!',
+    NO_TASK: '当前位置无任务可操作!',
     ERROR_ERROR: '错了错了',//任务消失时的错误提示
   }
 };
@@ -1184,10 +1186,10 @@ window.pickupItem = async function()  {
 
   // 判断是否是要拾取的方块类型
   if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.ITEM) {
-    showGameMessage(tileMap.tip || CONFIG.TIPS.PICKUP_ITEM, 'warning');
 
     // 处理携带物品逻辑
     if (tileMap && tileMap.img) {
+      showGameMessage(tileMap.tip || CONFIG.TIPS.PICKUP_ITEM);
 
       // 从地图上移除图标
       const pointIndex = gameState.mapData.walkablePoints.findIndex(
@@ -1213,9 +1215,11 @@ window.pickupItem = async function()  {
           originalY: y
         });
       }
+    } else {
+      showGameMessage(CONFIG.TIPS.NULL_PICKUP_ITEM, 'warning');
     }
   } else {
-    showGameMessage(CONFIG.TIPS.NULL_PICKUP_ITEM, 'info');
+    showGameMessage(CONFIG.TIPS.NULL_PICKUP_ITEM, 'warning');
   }
 
   await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
@@ -1252,7 +1256,7 @@ window.useItem = async function() {
       // 从携带物品中移除已使用的物品
       gameState.player.carriedItems.splice(itemIndex, 1);
       // 执行物品使用动画,传递finishAnimation
-      await animateItemUse(itemToUse, itemIndex, tileMap.finishAnimation);
+      await taskEndUseItem(itemToUse, itemIndex, tileMap.finishAnimation);
 
       // 使用物品成功
       showGameMessage(tileMap.finishedTip || CONFIG.TIPS.USE_ITEM_SUCCESS, 'success');
@@ -1335,9 +1339,24 @@ window.construct = async function() {
     return;
   }
 
-  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.TEMP_ITEM_FADE_DURATION));
-  //处理特殊任务消失
-  processingSpecialTasksDisappearing()
+  //取人物当前位置
+  let x = playerPosition.value.x;
+  let y = playerPosition.value.y;
+  let tileMap = walkablePointsMap.get(`${x},${y}`);
+
+  // 判断当前位置是否有特殊需求
+  if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.TASK) {
+
+    // 执行物品使用动画,传递finishAnimation
+    await taskEndNoItem(tileMap.finishAnimation);
+
+    // 任务完成
+    showGameMessage(tileMap.finishedTip || CONFIG.TIPS.TASK_SUCCESS, 'success');
+  } else {
+    showGameMessage(CONFIG.TIPS.NO_TASK, 'info');
+  }
+
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
 };
 
 // 当经过指定形状时执行的函数(返回布尔值,可作为参数使用)
@@ -1689,8 +1708,8 @@ async function animateItemPickup(item, itemX, itemY) {
   }
 }
 
-// 物品使用动画函数
-async function animateItemUse(item, itemIndex, finishAnimation) {
+// 任务完成-物品使用动画函数
+async function taskEndUseItem(item, itemIndex, finishAnimation) {
   // 创建临时动画元素
   const tempItem = document.createElement('div');
   const finalSize = tileSize.value * CONFIG.STYLES.ITEM_CONTAINER_RATIO;
@@ -1877,6 +1896,180 @@ async function animateItemUse(item, itemIndex, finishAnimation) {
       playerElement.style.zIndex = '150';
     }, CONFIG.DELAY.PLAYER_FADE_DURATION);
   }
+
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.COMPLETION_DISPLAY));
+}
+
+// 任务完成-不使用物品动画函数
+async function taskEndNoItem(finishAnimation) {
+  // 创建临时动画元素
+  const iconSize = tileSize.value * CONFIG.STYLES.IMG_SIZE_RATIO;
+  const marginSize = tileSize.value * CONFIG.STYLES.IMG_SIZE_MARGIN;
+
+  // 计算玩家当前位置
+  const playerLeft = playerPosition.value.x * tileSize.value - tileSize.value + marginSize;
+  const playerTop = playerPosition.value.y * tileSize.value - tileSize.value + marginSize;
+
+  // 获取玩家元素
+  const playerElement = document.querySelector('.player');
+  const originalPlayerZIndex = playerElement ? playerElement.style.zIndex : '';
+  const originalPlayerOpacity = playerElement ? playerElement.style.opacity : '1';
+
+  // 将临时元素添加到地图容器
+  const mapBackground = document.querySelector('.map-background');
+  if (!mapBackground) {
+    console.error('地图容器未找到');
+    return;
+  }
+
+  // 1. 首先让小智逐渐消失
+  if (playerElement) {
+    playerElement.style.transition = 'opacity ' + CONFIG.DELAY.PLAYER_FADE_DURATION + 'ms ease-out';
+    playerElement.style.opacity = '0';
+  }
+
+  // 等待小智消失动画完成
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.PLAYER_FADE_DURATION));
+
+  let x = playerPosition.value.x;
+  let y = playerPosition.value.y;
+  const pointIndex = gameState.mapData.walkablePoints.findIndex(
+      p => p.x === x && p.y === y
+  );
+
+  // 2. 任务视频显示(如果没有视频:任务前图片消失)
+  let videoElement = null;
+  if (finishAnimation) {
+    // 有视频的情况:显示任务视频
+    // 创建视频元素
+    videoElement = document.createElement('video');
+    videoElement.src = finishAnimation;
+    videoElement.autoplay = false; // 不自动播放
+    videoElement.playsinline = true;
+    videoElement.style.position = 'absolute';
+    videoElement.style.left = playerLeft + 'px';
+    videoElement.style.top = playerTop + 'px';
+    videoElement.style.width = iconSize + 'px';
+    videoElement.style.height = iconSize + 'px';
+    videoElement.style.zIndex = '2000'; // 提高z-index确保视频可见
+    videoElement.style.objectFit = 'contain';
+
+    // 添加渐变显示效果
+    videoElement.style.opacity = '0';
+    videoElement.style.transition = 'opacity ' + CONFIG.DELAY.VIDEO_FADE_DURATION + 'ms ease-in-out';
+
+    // 添加视频到地图容器
+    mapBackground.appendChild(videoElement);
+
+    // 触发重绘后设置透明度为1,实现渐变效果
+    setTimeout(() => {
+      videoElement.style.opacity = '1';
+    }, CONFIG.DELAY.VIDEO_FADE_DURATION);
+
+    // 开始播放视频
+    try {
+      const playPromise = videoElement.play();
+      if (playPromise !== undefined) {
+        playPromise.then(_ => {
+          console.log('Video started playing successfully');
+        }).catch(error => {
+          console.error('Error playing video:', error);
+        });
+      }
+    } catch (error) {
+      console.error('Exception when playing video:', error);
+    }
+
+    // 等待视频播放完成,添加超时处理
+    await new Promise(resolve => {
+      videoElement.onended = () => {
+        console.log('Video ended');
+        resolve();
+      };
+
+      // 添加超时处理,防止视频卡住
+      setTimeout(() => {
+        resolve();
+      }, CONFIG.DELAY.VIDEO_TIMEOUT);
+    });
+
+    // 移除视频元素 - 添加淡出效果
+    if (mapBackground.contains(videoElement)) {
+      // 设置淡出效果
+      videoElement.style.transition = 'opacity ' + CONFIG.DELAY.VIDEO_FADE_DURATION + 'ms ease-in-out';
+      videoElement.style.opacity = '0';
+
+      // 等待淡出动画完成后再移除元素
+      setTimeout(() => {
+        if (mapBackground.contains(videoElement)) {
+          mapBackground.removeChild(videoElement);
+        }
+      }, CONFIG.DELAY.VIDEO_FADE_DURATION); // 与动画时长一致
+    }
+  } else {
+    // 没有视频的情况:任务前图片消失
+    if (pointIndex !== -1) {
+      // 获取当前任务点元素
+      const walkablePointsElements = document.querySelectorAll('.walkable-point');
+      const currentPointElement = walkablePointsElements[pointIndex];
+
+      if (currentPointElement) {
+        // 任务前图片逐渐消失
+        currentPointElement.style.transition = 'opacity ' + CONFIG.DELAY.TEMP_ITEM_FADE_DURATION + 'ms ease-out';
+        currentPointElement.style.opacity = '0';
+
+        // 等待任务前图片消失动画完成
+        await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.TEMP_ITEM_FADE_DURATION));
+      }
+    }
+  }
+
+  // 3. 视频未播放的时候:将任务完成后的图片换成任务完成前的,逐渐显示
+  // 这里理解为:将任务前的图片替换为任务完成后的图片,并逐渐显示
+  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);
+
+
+    // 获取当前任务点元素
+    const walkablePointsElements = document.querySelectorAll('.walkable-point');
+    const currentPointElement = walkablePointsElements[pointIndex];
+
+    if (currentPointElement) {
+      // 任务完成后的图片逐渐显示
+      currentPointElement.style.opacity = ''; // 重置透明度
+      currentPointElement.style.transition = 'opacity ' + CONFIG.DELAY.TEMP_ITEM_FADE_DURATION + 'ms ease-in';
+      currentPointElement.style.opacity = '1';
+
+      // 检查是否有完成状态图标
+      if(updatedPoint.img){
+        // 等待任务完成后的图片显示动画完成
+        await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.TEMP_ITEM_FADE_DURATION));
+      }
+    }
+  }
+
+  // 4. 视频消失后稍作停留,让用户看到完成后的图片
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.COMPLETION_DISPLAY));
+
+  // 5. 逐步显示玩家并将其置顶
+  if (playerElement) {
+    playerElement.style.transition = 'opacity ' + CONFIG.DELAY.PLAYER_FADE_DURATION + 'ms ease-in';
+    playerElement.style.opacity = originalPlayerOpacity;
+    playerElement.style.zIndex = originalPlayerZIndex || '100';
+    // 额外设置一个较高的z-index确保盖住其他人物图片
+    setTimeout(() => {
+      playerElement.style.zIndex = '150';
+    }, CONFIG.DELAY.PLAYER_FADE_DURATION);
+  }
+
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.COMPLETION_DISPLAY));
 }
 
 // 展示通过动画
@@ -2646,9 +2839,9 @@ onUnmounted(() => {
 }
 
 .game-message.warning {
-  background-color: #baeff8;
+  background-color: #f8ecba;
   color: #035767;
-  border: 1px solid #9be9f6;
+  border: 1px solid #fdf0b5;
 }
 
 /* Blockly区域样式 */