Prechádzať zdrojové kódy

blockly编程游戏
1、加入冰块类型方块,滑行

liyanbo 8 mesiacov pred
rodič
commit
87a28828c9
1 zmenil súbory, kde vykonal 139 pridanie a 40 odobranie
  1. 139 40
      src/views/block/MapGame.vue

+ 139 - 40
src/views/block/MapGame.vue

@@ -117,23 +117,45 @@ const route = useRoute();
 const gameTitle = ref('地图游戏编程'); // 默认标题
 const currentGameData = ref(null);
 
+onMounted(() => {
+  //数据
+  fetchGameData();
+
+  // 初始化可行走点集合
+  initWalkablePointsSet();
+  // 注册自定义积木
+  registerCustomBlocks();
+  // 注册JavaScript生成器
+  registerJavaScriptGenerators();
+  // 初始化Blockly工作区
+  initBlockly();
+  // 重置玩家位置
+  resetPlayer();
+
+  // 获取路由参数中的gameName
+  const nameFromRoute = route.query.gameName;
+  if (nameFromRoute) {
+    gameTitle.value = nameFromRoute;
+  }
+})
+
 // 获取游戏数据
 const fetchGameData = async () => {
   try {
     const gameId = route.query.gameId;
     const nameFromRoute = route.query.gameName;
-    
+
     if (nameFromRoute) {
       gameTitle.value = nameFromRoute;
     }
-    
+
     const res = await GameList();
     if (res && res.data && res.data.list) {
       // 根据gameId找到对应的游戏数据
-      const gameItem = gameId 
+      const gameItem = gameId
         ? res.data.list.find(item => item.id === parseInt(gameId))
         : res.data.list[0]; // 如果没有gameId,使用第一个游戏
-      
+
       if (gameItem) {
         currentGameData.value = gameItem;
         updateGameStateFromData(gameItem);
@@ -159,7 +181,7 @@ const updateGameStateFromData = (gameData) => {
     // 地图起点
     if (gameData.mapStartPoint) {
       const startPoint = JSON.parse(gameData.mapStartPoint);
-      gameState.mapData.startPoint = { x: startPoint.x, y: startPoint.y }; 
+      gameState.mapData.startPoint = { x: startPoint.x, y: startPoint.y };
     }
     // 地图终点
     if (gameData.mapEndPoint) {
@@ -176,9 +198,6 @@ const updateGameStateFromData = (gameData) => {
   }
 };
 
-onMounted(() => {
-  fetchGameData();
-})
 
 
 // 创建游戏状态的响应式对象
@@ -194,13 +213,15 @@ const gameState = reactive({
   // 玩家相关状态
   player: {
     // 玩家当前位置坐标
-    position: { x: 2, y: 2 },
+    position: { x: 1, y: 1 },
     // 玩家当前朝向:0=上, 1=右, 2=下, 3=左
-    direction: 0,
+    direction: 1,
     // 是否正在发生碰撞
     isColliding: false,
     // 是否已到达终点
     hasReachedEnd: false,
+    // 是否正在冰块上滑行
+    isSliding: false,
   },
 
   // 游戏状态信息
@@ -214,14 +235,15 @@ const gameState = reactive({
   // 地图数据信息
   mapData: {
     // 游戏起点位置
-    startPoint: { x: 2, y: 2 },
+    startPoint: { x: 1, y: 1 },
     // 游戏终点位置
-    endPoint: { x: 3, y: 2 },
-    // 地图上所有可行走的点坐标集合
+    endPoint: { x: 4, y: 3 },
+    // 地图上所有可行走的点坐标集合,添加type属性区分普通点和冰块
     walkablePoints: [
-      { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 3, y: 1 },
-      { x: 2, y: 2 }, { x: 3, y: 2 },
-      { x: 1, y: 3 }, { x: 3, y: 3 },
+      { x: 1, y: 1, type: 'ice' }, { x: 2, y: 1, type: 'ice' }, { x: 3, y: 1 }, { x: 4, y: 1 },
+      { x: 1, y: 2 }, { x: 2, y: 2 }, { x: 3, y: 2, type: 'ice' }, { x: 4, y: 2 },
+      { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 3 }, { x: 4, y: 3 },
+      { x: 4, y: 3 },
     ]
   }
 });
@@ -246,33 +268,45 @@ const playerImageSrc = computed(() => {
   }
   return playerImage;
 });
+const isSliding = computed(() => gameState.player.isSliding);
+
 
 // Blockly相关状态
 let workspace = null;
 
-// 使用 Set 存储可行走点,提高查询效率
-let walkablePointsSet = new Set();
+// 使用 Map 存储可行走点及其类型,提高查询效率
+let walkablePointsMap = new Map();
 
-// 初始化可行走点集合
+// 初始化可行走点映射
 function initWalkablePointsSet() {
-  walkablePointsSet.clear();
+  walkablePointsMap.clear();
   gameState.mapData.walkablePoints.forEach(point => {
-    walkablePointsSet.add(`${point.x},${point.y}`);
+    walkablePointsMap.set(`${point.x},${point.y}`, point.type);
   });
 }
 
-// 优化后的可行走检查函数
+// 可行走检查函数
 function isWalkable(x, y) {
-  return walkablePointsSet.has(`${x},${y}`);
+  return walkablePointsMap.has(`${x},${y}`);
+}
+
+// 检查是否是冰块点 - 基于walkablePoints中的type属性
+function isIce(x, y) {
+  return walkablePointsMap.get(`${x},${y}`) === 'ice';
 }
 
 // 计算点的样式
 function getPointStyle(point) {
+  // 检查是否是冰块点,添加不同的样式
+  const isIcePoint = isIce(point.x, point.y);
   return {
     left: point.x * tileSize.value - tileSize.value + 'px',
     top: point.y * tileSize.value - tileSize.value + 'px',
     width: tileSize.value + 'px',
-    height: tileSize.value + 'px'
+    height: tileSize.value + 'px',
+    backgroundColor: isIcePoint ? 'rgba(144, 202, 249, 0.5)' : 'rgba(52, 152, 219, 0.2)',
+    border: isIcePoint ? '1px solid rgba(33, 150, 243, 0.8)' : '1px solid rgba(52, 152, 219, 0.5)',
+    boxShadow: isIcePoint ? '0 0 10px rgba(33, 150, 243, 0.5)' : 'none',
   };
 }
 
@@ -285,7 +319,7 @@ const playerStyle = computed(() => ({
   '--player-image': `url(${playerImageSrc.value})`,
   width: (tileSize.value * 0.8) + 'px',
   height: (tileSize.value * 0.8) + 'px',
-  margin: (tileSize.value * 0.1) + 'px'
+  margin: (tileSize.value * 0.1) + 'px',
 }));
 
 // 显示游戏消息
@@ -411,7 +445,6 @@ function registerJavaScriptGenerators() {
 
   // 为重复循环块注册自定义生成器,确保支持异步操作
   javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) {
-    // 获取循环次数 - 修改为使用 valueToCode 方法
     const repeats = javascriptGenerator.valueToCode(block, 'TIMES', javascriptGenerator.ORDER_ATOMIC) || '0';
 
     // 确保获取到的是数字类型,如果是字符串需要转换
@@ -535,7 +568,7 @@ async function smoothMoveTo(targetX, targetY) {
 
 // 创建通用的移动函数
 async function move(direction) {
-  if (isColliding.value) {
+  if (isColliding.value || isSliding.value) {
     return;
   }
 
@@ -565,6 +598,11 @@ async function move(direction) {
   if (isWalkable(newX, newY)) {
     // 使用平滑移动动画
     await smoothMoveTo(newX, newY);
+
+    // 检查新位置是否是冰块,如果是则触发滑行
+    if (isIce(newX, newY)) {
+      await handleIceSliding();
+    }
   } else {
     // 发生碰撞
     gameState.player.isColliding = true;
@@ -575,7 +613,6 @@ async function move(direction) {
       executionAbortController.abort();
     }
 
-    // 保留碰撞抖动效果,但确保不会改变当前朝向
     // 1秒后取消碰撞状态
     setTimeout(() => {
       gameState.player.isColliding = false;
@@ -586,6 +623,67 @@ async function move(direction) {
   }
 }
 
+// 处理冰块滑行逻辑
+async function handleIceSliding() {
+  gameState.player.isSliding = true;
+
+  try {
+    // 循环检查是否可以继续滑行
+    while (true) {
+      // 计算下一个位置
+      let nextX = playerPosition.value.x;
+      let nextY = playerPosition.value.y;
+
+      // 根据当前方向计算下一个位置
+      switch(playerDirection.value) {
+        case 0: nextY--; break;
+        case 1: nextX++; break;
+        case 2: nextY++; break;
+        case 3: nextX--; break;
+      }
+
+      // 检查下一个位置是否可行走
+      if (isWalkable(nextX, nextY)) {
+        // 执行平滑移动到下一个位置
+        await smoothMoveTo(nextX, nextY);
+
+        // 检查下一个位置是否还是冰块
+        if (!isIce(nextX, nextY)) {
+          // 如果不是冰块,结束滑行
+          break;
+        }
+
+        // 添加滑行间隔时间
+        await new Promise(resolve => setTimeout(resolve, 300));
+      } else {
+        // 下一个位置不可行走,检查是否是墙体
+        gameState.player.isColliding = true;
+        showGameMessage('哎呀,撞到墙了!', 'error');
+
+        // 立即中止整个代码执行
+        if (executionAbortController) {
+          executionAbortController.abort();
+        }
+
+        // 1秒后取消碰撞状态
+        setTimeout(() => {
+          gameState.player.isColliding = false;
+        }, 1000);
+
+        // 添加碰撞延迟
+        await new Promise(resolve => setTimeout(resolve, 300));
+
+        break;
+      }
+    }
+  } catch (error) {
+    console.error('滑行过程中发生错误:', error);
+  } finally {
+    // 无论如何都要确保滑行状态被重置
+    gameState.player.isSliding = false;
+  }
+}
+
 // 保留原有的API接口
 window.moveForward = async function() {
   await move(1);
@@ -643,9 +741,10 @@ window.isFinish = async function() {
     return;
   }
 
+  console.log(gameState.player.hasReachedEnd);
   if (gameState.player.position.x === endPoint.value.x && gameState.player.position.y === endPoint.value.y) {
     gameState.player.hasReachedEnd = true;
-    showGameMessage('恭喜你到达终点!', 'success');
+    showGameMessage('恭喜你到达终点!', 'success' );
   }
 };
 
@@ -669,6 +768,7 @@ const runCode = async () => {
 
     // 生成JavaScript代码
     const code = javascriptGenerator.workspaceToCode(workspace) + "await isFinish();";
+    console.log(code);
 
     try {
       // 增强的安全检查
@@ -743,21 +843,12 @@ const resetPlayer = () => {
   }
 
   gameState.player.position = { ...startPoint.value };
-  gameState.player.direction = 0; // 重置为向上方向
+  gameState.player.direction = 1; // 重置为向上方向
   gameState.player.isColliding = false; //碰撞标志
   gameState.player.hasReachedEnd = false;
+  gameState.player.isSliding = false; // 重置滑行状态
 };
 
-// 组件挂载时初始化
-onMounted(() => {
-  // 初始化可行走点集合
-  initWalkablePointsSet();
-
-  registerCustomBlocks();
-  registerJavaScriptGenerators();
-  initBlockly();
-});
-
 // 组件卸载时清理
 onUnmounted(() => {
   if (workspace) {
@@ -926,6 +1017,14 @@ onUnmounted(() => {
   100% { transform: rotate(var(--player-rotation)) translateX(0) translateY(0) scale(1); }
 }
 
+/* 滑行动画 */
+@keyframes sliding {
+  0% { transform: rotate(var(--player-rotation)) translateX(0) translateY(0); }
+  25% { transform: rotate(var(--player-rotation)) translateX(2px) translateY(0); }
+  75% { transform: rotate(var(--player-rotation)) translateX(-2px) translateY(0); }
+  100% { transform: rotate(var(--player-rotation)) translateX(0) translateY(0); }
+}
+
 /* 成功到达终点动画 */
 .player.success {
   animation: success 1s ease-in-out;