|
|
@@ -34,14 +34,23 @@
|
|
|
:key="index"
|
|
|
class="walkable-point"
|
|
|
:style="getPointStyle(point)"
|
|
|
- ></div>
|
|
|
+ >
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 玩家角色 -->
|
|
|
<div
|
|
|
class="player"
|
|
|
:style="playerStyle"
|
|
|
:class="{ 'collision': isColliding, 'success': hasReachedEnd }"
|
|
|
- ></div>
|
|
|
+ >
|
|
|
+ <!-- 携带的物品 - 移动到玩家内部 -->
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in gameState.player.carriedItems"
|
|
|
+ :key="index"
|
|
|
+ class="carried-item"
|
|
|
+ :style="getCarriedItemStyle(index, item)"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 游戏状态提示 -->
|
|
|
@@ -59,10 +68,11 @@
|
|
|
<!-- 移动控制积木 -->
|
|
|
<category name="移动控制" colour="%{BKY_MOTION_HUE}">
|
|
|
<block type="move_forward"></block>
|
|
|
- <block type="move_backward"></block>
|
|
|
<block type="turn_left"></block>
|
|
|
<block type="turn_right"></block>
|
|
|
<block type="turn_around"></block>
|
|
|
+ <block type="pickup_item"></block>
|
|
|
+ <block type="use_item"></block>
|
|
|
</category>
|
|
|
|
|
|
<!-- 逻辑控制积木 -->
|
|
|
@@ -115,7 +125,6 @@ import { ArrowLeftBold } from '@element-plus/icons-vue';
|
|
|
import * as Blockly from "blockly";
|
|
|
import 'blockly/msg/zh-hans';
|
|
|
import { javascriptGenerator } from "blockly/javascript";
|
|
|
-// import mapBackgroundImage from '@/assets/images/blockly/mapGame.png';
|
|
|
import playerImage from '@/assets/images/blockly/user.png';
|
|
|
|
|
|
// 游戏接口数据
|
|
|
@@ -195,7 +204,7 @@ const gameState = reactive({
|
|
|
// 玩家相关状态
|
|
|
player: {
|
|
|
// 玩家当前位置坐标
|
|
|
- position: { x: 1, y: 1 },
|
|
|
+ position: {},
|
|
|
// 玩家当前朝向:0=上, 1=右, 2=下, 3=左
|
|
|
direction: 1,
|
|
|
// 是否正在发生碰撞
|
|
|
@@ -204,6 +213,8 @@ const gameState = reactive({
|
|
|
hasReachedEnd: false,
|
|
|
// 是否正在冰块上滑行
|
|
|
isSliding: false,
|
|
|
+ // 携带的物品数组
|
|
|
+ carriedItems: [],
|
|
|
},
|
|
|
|
|
|
// 游戏状态信息
|
|
|
@@ -217,19 +228,18 @@ const gameState = reactive({
|
|
|
// 地图数据信息
|
|
|
mapData: {
|
|
|
// 游戏起点位置
|
|
|
- startPoint: { x: 1, y: 1 },
|
|
|
+ startPoint: {},
|
|
|
// 游戏终点位置
|
|
|
- endPoint: { x: 4, y: 3 },
|
|
|
+ endPoint: {},
|
|
|
// 地图上所有可行走的点坐标集合,添加type属性区分普通点和冰块
|
|
|
- walkablePoints: [
|
|
|
- { 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 },
|
|
|
- ],
|
|
|
+ walkablePoints: [],
|
|
|
+ // 保存原始的可行走点数据,用于重置
|
|
|
+ originalWalkablePoints: [],
|
|
|
}
|
|
|
});
|
|
|
const BLOCKLY_MAP_TYPE_DICT = {
|
|
|
ICE: 'ice',//冰块
|
|
|
+ YC: 'yaoshi',//钥匙
|
|
|
};
|
|
|
|
|
|
// 计算属性 - 提高性能和可读性
|
|
|
@@ -277,7 +287,6 @@ const tileSize = computed(() => {
|
|
|
return Math.min(tileWidth, tileHeight);
|
|
|
});
|
|
|
|
|
|
-
|
|
|
// 生命周期钩子
|
|
|
onMounted(async () => {
|
|
|
// 获取游戏数据
|
|
|
@@ -372,8 +381,10 @@ const updateGameStateFromData = (gameData) => {
|
|
|
function initWalkablePointsSet() {
|
|
|
walkablePointsMap.clear();
|
|
|
gameState.mapData.walkablePoints.forEach(point => {
|
|
|
- walkablePointsMap.set(`${point.x},${point.y}`, point.type);
|
|
|
+ walkablePointsMap.set(`${point.x},${point.y}`, point);
|
|
|
});
|
|
|
+ // 保存原始的可行走点数据,用于重置
|
|
|
+ gameState.mapData.originalWalkablePoints = JSON.parse(JSON.stringify(gameState.mapData.walkablePoints));
|
|
|
}
|
|
|
|
|
|
// 可行走检查函数
|
|
|
@@ -381,22 +392,34 @@ function isWalkable(x, y) {
|
|
|
return walkablePointsMap.has(`${x},${y}`);
|
|
|
}
|
|
|
|
|
|
-// 检查是否是冰块点 - 基于walkablePoints中的type属性
|
|
|
-function isIce(x, y) {
|
|
|
- return walkablePointsMap.get(`${x},${y}`) === BLOCKLY_MAP_TYPE_DICT.ICE;
|
|
|
-}
|
|
|
-
|
|
|
// 计算点的样式
|
|
|
function getPointStyle(point) {
|
|
|
- return {
|
|
|
+ const style = {
|
|
|
left: point.x * tileSize.value - tileSize.value + 'px',
|
|
|
top: point.y * tileSize.value - tileSize.value + 'px',
|
|
|
width: tileSize.value + 'px',
|
|
|
height: tileSize.value + 'px',
|
|
|
- backgroundColor: 'rgba(52, 152, 219, 0.2)',
|
|
|
- border: '1px solid rgba(52, 152, 219, 0.5)',
|
|
|
- boxShadow: 'none',
|
|
|
};
|
|
|
+
|
|
|
+ // 如果point有img属性,则添加图标
|
|
|
+ if (point.img) {
|
|
|
+ const iconSize = tileSize.value * CONFIG.STYLES.PLAYER_SIZE_RATIO;
|
|
|
+ const marginSize = tileSize.value * CONFIG.STYLES.PLAYER_SIZE_MARGIN;
|
|
|
+
|
|
|
+ // 重置可能影响背景图显示的样式
|
|
|
+ style.backgroundColor = 'transparent';
|
|
|
+ style.backgroundImage = `url(${point.img})`;
|
|
|
+ style.backgroundSize = 'contain';
|
|
|
+ style.backgroundPosition = 'center';
|
|
|
+ style.backgroundRepeat = 'no-repeat';
|
|
|
+
|
|
|
+ // 设置与玩家相同的宽高和边距
|
|
|
+ style.width = iconSize + 'px';
|
|
|
+ style.height = iconSize + 'px';
|
|
|
+ style.margin = marginSize + 'px';
|
|
|
+ }
|
|
|
+
|
|
|
+ return style;
|
|
|
}
|
|
|
|
|
|
// 计算玩家样式
|
|
|
@@ -411,15 +434,26 @@ const playerStyle = computed(() => ({
|
|
|
margin: (tileSize.value * CONFIG.STYLES.PLAYER_SIZE_MARGIN) + 'px',
|
|
|
}));
|
|
|
|
|
|
-// 显示游戏消息
|
|
|
-function showGameMessage(message, type = 'info') {
|
|
|
- gameState.status.message = message;
|
|
|
- gameState.status.messageType = type;
|
|
|
+// 计算携带物品样式
|
|
|
+function getCarriedItemStyle(index, item) {
|
|
|
+ const baseSize = tileSize.value * CONFIG.STYLES.PLAYER_SIZE_RATIO * 0.3;
|
|
|
+ const baseSize2 = tileSize.value * CONFIG.STYLES.PLAYER_SIZE_RATIO * 0.7;
|
|
|
+ console.log(baseSize2, baseSize2 * index)
|
|
|
|
|
|
- // 消息显示时间后自动清除消息
|
|
|
- setTimeout(() => {
|
|
|
- gameState.status.message = '';
|
|
|
- }, CONFIG.DELAY.MESSAGE_DISPLAY);
|
|
|
+ return {
|
|
|
+ position: 'absolute',
|
|
|
+ width: baseSize + 'px',
|
|
|
+ height: baseSize + 'px',
|
|
|
+ backgroundSize: 'contain',
|
|
|
+ backgroundPosition: 'center',
|
|
|
+ backgroundRepeat: 'no-repeat',
|
|
|
+ bottom: index * baseSize2 * 0.5 + 'px',
|
|
|
+ left: baseSize2 + 'px', // 根据索引计算位置,从左到右排列
|
|
|
+ transform: 'none',
|
|
|
+ transformOrigin: 'center',
|
|
|
+ zIndex: -1,
|
|
|
+ backgroundImage: `url(${item.img})`
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
// 导航返回
|
|
|
@@ -444,21 +478,6 @@ function registerCustomBlocks() {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // 向后移动积木
|
|
|
- Blockly.Blocks['move_backward'] = {
|
|
|
- init: function() {
|
|
|
- this.jsonInit({
|
|
|
- "type": "move_backward",
|
|
|
- "message0": "向后移动",
|
|
|
- "previousStatement": null,
|
|
|
- "nextStatement": null,
|
|
|
- "colour": 230,
|
|
|
- "tooltip": "控制角色向后移动一格",
|
|
|
- "helpUrl": ""
|
|
|
- });
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
// 向左转积木
|
|
|
Blockly.Blocks['turn_left'] = {
|
|
|
init: function() {
|
|
|
@@ -503,6 +522,36 @@ function registerCustomBlocks() {
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ // 拾取物品积木
|
|
|
+ Blockly.Blocks['pickup_item'] = {
|
|
|
+ init: function() {
|
|
|
+ this.jsonInit({
|
|
|
+ "type": "pickup_item",
|
|
|
+ "message0": "拾取物品",
|
|
|
+ "previousStatement": null,
|
|
|
+ "nextStatement": null,
|
|
|
+ "colour": 30,
|
|
|
+ "tooltip": "尝试拾取当前位置的物品",
|
|
|
+ "helpUrl": ""
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 使用物品积木
|
|
|
+ Blockly.Blocks['use_item'] = {
|
|
|
+ init: function() {
|
|
|
+ this.jsonInit({
|
|
|
+ "type": "use_item",
|
|
|
+ "message0": "使用物品",
|
|
|
+ "previousStatement": null,
|
|
|
+ "nextStatement": null,
|
|
|
+ "colour": 30,
|
|
|
+ "tooltip": "在当前位置使用物品",
|
|
|
+ "helpUrl": ""
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
// 注册JavaScript生成器
|
|
|
@@ -512,11 +561,6 @@ function registerJavaScriptGenerators() {
|
|
|
return 'await moveForward();\n';
|
|
|
};
|
|
|
|
|
|
- // 向后移动生成器
|
|
|
- javascriptGenerator.forBlock['move_backward'] = function(block) {
|
|
|
- return 'await moveBackward();\n';
|
|
|
- };
|
|
|
-
|
|
|
// 向左转生成器
|
|
|
javascriptGenerator.forBlock['turn_left'] = function(block) {
|
|
|
return 'await turnLeft();\n';
|
|
|
@@ -532,6 +576,16 @@ function registerJavaScriptGenerators() {
|
|
|
return 'await turnAround();\n';
|
|
|
};
|
|
|
|
|
|
+ // 拾取物品生成器
|
|
|
+ javascriptGenerator.forBlock['pickup_item'] = function(block) {
|
|
|
+ return 'await pickupItem();\n';
|
|
|
+ };
|
|
|
+
|
|
|
+ // 使用物品生成器
|
|
|
+ javascriptGenerator.forBlock['use_item'] = function(block) {
|
|
|
+ return 'await useItem();\n';
|
|
|
+ };
|
|
|
+
|
|
|
// 为重复循环块注册自定义生成器,确保支持异步操作
|
|
|
javascriptGenerator.forBlock['controls_repeat_ext'] = function(block) {
|
|
|
const repeats = javascriptGenerator.valueToCode(block, 'TIMES', javascriptGenerator.ORDER_ATOMIC) || '0';
|
|
|
@@ -593,6 +647,8 @@ function initBlockly() {
|
|
|
trashcan: true,
|
|
|
horizontalLayout: false,
|
|
|
toolboxPosition: 'start',
|
|
|
+ toolboxCollapse: false, // 设置工具箱默认展开
|
|
|
+ toolboxAlwaysExpanded: true, // 确保点击类别后保持展开状态
|
|
|
css: true,
|
|
|
media: 'https://unpkg.com/blockly/media/',
|
|
|
rtl: false,
|
|
|
@@ -641,7 +697,7 @@ async function smoothMoveTo(targetX, targetY) {
|
|
|
|
|
|
gameState.player = {
|
|
|
...gameState.player,
|
|
|
- position: { x: currentX, y: currentY }
|
|
|
+ position: { x: currentX, y: currentY },
|
|
|
};
|
|
|
|
|
|
// 检查是否到达终点
|
|
|
@@ -658,111 +714,85 @@ async function smoothMoveTo(targetX, targetY) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-// 创建通用的移动函数
|
|
|
-async function move(direction) {
|
|
|
- if (shouldStopExecution || isColliding.value || isSliding.value) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let newX = playerPosition.value.x;
|
|
|
- let newY = playerPosition.value.y;
|
|
|
+// 处理冰块滑行逻辑(根据人物当前位置判断)
|
|
|
+async function switchMapType(isMapType = null) {
|
|
|
+ //取人物当前位置
|
|
|
+ let x = playerPosition.value.x;
|
|
|
+ let y = playerPosition.value.y;
|
|
|
+ let tileMap = walkablePointsMap.get(`${x},${y}`);
|
|
|
|
|
|
- // 根据当前方向和移动类型计算新位置
|
|
|
- if (direction === 1) {
|
|
|
- // 向前移动
|
|
|
- switch(playerDirection.value) {
|
|
|
- case CONFIG.GAME.DIRECTIONS.UP: newY--; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.RIGHT: newX++; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.DOWN: newY++; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.LEFT: newX--; break;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 向后移动
|
|
|
- switch(playerDirection.value) {
|
|
|
- case CONFIG.GAME.DIRECTIONS.UP: newY++; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.RIGHT: newX--; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.DOWN: newY--; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.LEFT: newX++; break;
|
|
|
- }
|
|
|
+ //判断是否是指定地图类型
|
|
|
+ if (isMapType) {
|
|
|
+ return isMapType === tileMap.type;
|
|
|
}
|
|
|
|
|
|
- // 检查是否可以移动
|
|
|
- if (isWalkable(newX, newY)) {
|
|
|
- // 使用平滑移动动画
|
|
|
- await smoothMoveTo(newX, newY);
|
|
|
-
|
|
|
- // 检查新位置是否是冰块,如果是则触发滑行
|
|
|
- if (isIce(newX, newY)) {
|
|
|
- await handleIceSliding();
|
|
|
- }
|
|
|
-
|
|
|
- await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
|
|
|
- } else {
|
|
|
- // 发生碰撞
|
|
|
- gameState.player.isColliding = true;
|
|
|
- showGameMessage(CONFIG.TIPS.NO_ENTRY, 'error');
|
|
|
-
|
|
|
- // 立即中止整个代码执行
|
|
|
- if (executionAbortController) {
|
|
|
- executionAbortController.abort();
|
|
|
- }
|
|
|
-
|
|
|
- // 碰撞状态重置时间后取消碰撞状态
|
|
|
- setTimeout(() => {
|
|
|
- gameState.player.isColliding = false;
|
|
|
- }, CONFIG.DELAY.COLLISION_RESET);
|
|
|
-
|
|
|
- // 添加碰撞延迟
|
|
|
- await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.COLLISION_DELAY));
|
|
|
+ //判断方块类型并处理逻辑
|
|
|
+ switch (tileMap.type) {
|
|
|
+ case BLOCKLY_MAP_TYPE_DICT.ICE:
|
|
|
+ do {
|
|
|
+ showGameMessage(tileMap.tip, 'warning',300)
|
|
|
+ await handleIceSliding();
|
|
|
+
|
|
|
+ tileMap = walkablePointsMap.get(`${playerPosition.value.x},${playerPosition.value.y}`);
|
|
|
+ }while (tileMap.type === BLOCKLY_MAP_TYPE_DICT.ICE && !isColliding.value)
|
|
|
+ break;
|
|
|
+ case BLOCKLY_MAP_TYPE_DICT.YC:
|
|
|
+ // showGameMessage(tileMap.tip, 'warning', 1000)
|
|
|
+ // // 处理携带物品逻辑
|
|
|
+ // if (tileMap && tileMap.img) {
|
|
|
+ // // 将物品添加到玩家携带物品中
|
|
|
+ // gameState.player.carriedItems.push({
|
|
|
+ // ...tileMap,
|
|
|
+ // originalX: x,
|
|
|
+ // originalY: y
|
|
|
+ // });
|
|
|
+ //
|
|
|
+ // // 从地图上移除图标(但保留点的可通行性)
|
|
|
+ // const pointIndex = gameState.mapData.walkablePoints.findIndex(
|
|
|
+ // p => p.x === x && p.y === y
|
|
|
+ // );
|
|
|
+ // if (pointIndex !== -1) {
|
|
|
+ // // 保留点但移除img属性
|
|
|
+ // const updatedPoint = { ...gameState.mapData.walkablePoints[pointIndex] };
|
|
|
+ // delete updatedPoint.img;
|
|
|
+ // gameState.mapData.walkablePoints.splice(pointIndex, 1, updatedPoint);
|
|
|
+ // // 更新映射
|
|
|
+ // walkablePointsMap.set(`${x},${y}`, updatedPoint);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理冰块滑行逻辑
|
|
|
async function handleIceSliding() {
|
|
|
+ if (shouldStopExecution || isColliding.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
gameState.player.isSliding = true;
|
|
|
|
|
|
try {
|
|
|
- // 循环检查是否可以继续滑行
|
|
|
- while (true) {
|
|
|
- // 计算下一个位置
|
|
|
- let nextX = playerPosition.value.x;
|
|
|
- let nextY = playerPosition.value.y;
|
|
|
-
|
|
|
- // 根据当前方向计算下一个位置
|
|
|
- switch(playerDirection.value) {
|
|
|
- case CONFIG.GAME.DIRECTIONS.UP: nextY--; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.RIGHT: nextX++; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.DOWN: nextY++; break;
|
|
|
- case CONFIG.GAME.DIRECTIONS.LEFT: nextX--; break;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查下一个位置是否可行走
|
|
|
- if (isWalkable(nextX, nextY)) {
|
|
|
- // 执行平滑移动到下一个位置
|
|
|
- await smoothMoveTo(nextX, nextY);
|
|
|
-
|
|
|
- // 检查下一个位置是否还是冰块
|
|
|
- if (!isIce(nextX, nextY)) {
|
|
|
- // 如果不是冰块,结束滑行
|
|
|
- break;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 下一个位置不可行走,检查是否是墙体
|
|
|
- gameState.player.isColliding = true;
|
|
|
- showGameMessage(CONFIG.TIPS.NO_ENTRY, 'error');
|
|
|
+ // 计算下一个位置
|
|
|
+ let nextX = playerPosition.value.x;
|
|
|
+ let nextY = playerPosition.value.y;
|
|
|
|
|
|
- // 立即中止整个代码执行
|
|
|
- if (executionAbortController) {
|
|
|
- executionAbortController.abort();
|
|
|
- }
|
|
|
+ // 根据当前方向计算下一个位置
|
|
|
+ switch(playerDirection.value) {
|
|
|
+ case CONFIG.GAME.DIRECTIONS.UP: nextY--; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.RIGHT: nextX++; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.DOWN: nextY++; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.LEFT: nextX--; break;
|
|
|
+ }
|
|
|
|
|
|
- // 碰撞状态重置时间后取消碰撞状态
|
|
|
- setTimeout(() => {
|
|
|
- gameState.player.isColliding = false;
|
|
|
- }, CONFIG.DELAY.COLLISION_RESET);
|
|
|
+ // 检查下一个位置是否可行走
|
|
|
+ if (isWalkable(nextX, nextY)) {
|
|
|
+ // 执行平滑移动到下一个位置
|
|
|
+ await smoothMoveTo(nextX, nextY);
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ // 使用统一的碰撞处理方法,但不等待延迟(因为handleIceSliding不需要这个延迟)
|
|
|
+ await handleWallCollision();
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('滑行过程中发生错误:', error);
|
|
|
@@ -772,13 +802,114 @@ async function handleIceSliding() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 保留原有的API接口
|
|
|
+// 拾取物品函数
|
|
|
+window.pickupItem = async function() {
|
|
|
+ //取人物当前位置
|
|
|
+ let x = playerPosition.value.x;
|
|
|
+ let y = playerPosition.value.y;
|
|
|
+ let tileMap = walkablePointsMap.get(`${x},${y}`);
|
|
|
+
|
|
|
+ // 判断是否是要拾取的方块类型
|
|
|
+ if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.YC) {
|
|
|
+ showGameMessage(tileMap.tip || '成功拾取物品!', 'warning', 1000)
|
|
|
+
|
|
|
+ // 处理携带物品逻辑
|
|
|
+ if (tileMap && tileMap.img) {
|
|
|
+ // 将物品添加到玩家携带物品中
|
|
|
+ gameState.player.carriedItems.push({
|
|
|
+ ...tileMap,
|
|
|
+ originalX: x,
|
|
|
+ originalY: y
|
|
|
+ });
|
|
|
+
|
|
|
+ // 从地图上移除图标(但保留点的可通行性)
|
|
|
+ const pointIndex = gameState.mapData.walkablePoints.findIndex(
|
|
|
+ p => p.x === x && p.y === y
|
|
|
+ );
|
|
|
+ if (pointIndex !== -1) {
|
|
|
+ // 保留点但移除img属性
|
|
|
+ const updatedPoint = { ...gameState.mapData.walkablePoints[pointIndex] };
|
|
|
+ delete updatedPoint.img;
|
|
|
+ gameState.mapData.walkablePoints.splice(pointIndex, 1, updatedPoint);
|
|
|
+ // 更新映射
|
|
|
+ walkablePointsMap.set(`${x},${y}`, updatedPoint);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ showGameMessage('当前位置没有可拾取的物品', 'info', 1000)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 使用物品函数
|
|
|
+window.useItem = async function() {
|
|
|
+ //取人物当前位置
|
|
|
+ let x = playerPosition.value.x;
|
|
|
+ let y = playerPosition.value.y;
|
|
|
+ let tileMap = walkablePointsMap.get(`${x},${y}`);
|
|
|
+
|
|
|
+ // 判断当前位置是否有特殊需求
|
|
|
+ if (tileMap && tileMap.need) {
|
|
|
+ // 检查玩家是否携带了需要的物品
|
|
|
+ const requiredItems = tileMap.need;
|
|
|
+ let hasRequiredItem = false;
|
|
|
+ let itemIndex = -1;
|
|
|
+
|
|
|
+ // 检查玩家携带的物品中是否有满足需求的物品
|
|
|
+ for (let i = 0; i < gameState.player.carriedItems.length; i++) {
|
|
|
+ const item = gameState.player.carriedItems[i];
|
|
|
+ if (requiredItems.includes(item.type)) {
|
|
|
+ hasRequiredItem = true;
|
|
|
+ itemIndex = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasRequiredItem) {
|
|
|
+ // 使用物品成功
|
|
|
+ showGameMessage(tileMap.tip || '物品使用成功!', 'success', 1500);
|
|
|
+
|
|
|
+ // 从携带物品中移除已使用的物品
|
|
|
+ gameState.player.carriedItems.splice(itemIndex, 1);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // 提示缺少所需物品
|
|
|
+ showGameMessage(tileMap.tip || `需要特殊物品才能使用`, 'warning', 1500);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ showGameMessage('当前位置不需要使用物品', 'info', 1000);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 向前移动
|
|
|
window.moveForward = async function() {
|
|
|
- await move(1);
|
|
|
-};
|
|
|
+ if (shouldStopExecution || isColliding.value || isSliding.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
-window.moveBackward = async function() {
|
|
|
- await move(-1);
|
|
|
+ let newX = playerPosition.value.x;
|
|
|
+ let newY = playerPosition.value.y;
|
|
|
+
|
|
|
+ // 向前移动
|
|
|
+ switch(playerDirection.value) {
|
|
|
+ case CONFIG.GAME.DIRECTIONS.UP: newY--; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.RIGHT: newX++; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.DOWN: newY++; break;
|
|
|
+ case CONFIG.GAME.DIRECTIONS.LEFT: newX--; break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否可以移动
|
|
|
+ if (isWalkable(newX, newY)) {
|
|
|
+ // 使用平滑移动动画
|
|
|
+ await smoothMoveTo(newX, newY);
|
|
|
+
|
|
|
+ // 处理方块类型逻辑
|
|
|
+ await switchMapType();
|
|
|
+
|
|
|
+ await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
|
|
|
+ } else {
|
|
|
+ // 发生碰撞 使用统一的碰撞处理方法
|
|
|
+ await handleWallCollision();
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
//向左转(逆时针旋转90度)
|
|
|
@@ -1039,6 +1170,15 @@ const resetPlayer = () => {
|
|
|
currentExecutionPromise = null;
|
|
|
}
|
|
|
|
|
|
+ // 重置携带的物品回地图
|
|
|
+ if (gameState.mapData.originalWalkablePoints.length > 0) {
|
|
|
+ gameState.mapData.walkablePoints = JSON.parse(JSON.stringify(gameState.mapData.originalWalkablePoints));
|
|
|
+ }
|
|
|
+ // 清空携带物品
|
|
|
+ gameState.player.carriedItems = [];
|
|
|
+ // 重新初始化可行走点集合
|
|
|
+ initWalkablePointsSet();
|
|
|
+
|
|
|
gameState.player.position = { ...startPoint.value };
|
|
|
gameState.player.direction = playerInitialDirection.value; // 重置为初始方向
|
|
|
gameState.player.isColliding = false; //碰撞标志
|
|
|
@@ -1065,6 +1205,39 @@ function updateMapContainerDimensions() {
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+// 显示游戏消息
|
|
|
+function showGameMessage(message, type = 'info', duration = CONFIG.DELAY.MESSAGE_DISPLAY) {
|
|
|
+ gameState.status.message = message;
|
|
|
+ gameState.status.messageType = type;
|
|
|
+
|
|
|
+ // 消息显示时间后自动清除消息
|
|
|
+ setTimeout(() => {
|
|
|
+ gameState.status.message = '';
|
|
|
+ }, duration);
|
|
|
+}
|
|
|
+
|
|
|
+// 统一处理撞到墙时的停止逻辑
|
|
|
+async function handleWallCollision() {
|
|
|
+ // 设置碰撞状态
|
|
|
+ gameState.player.isColliding = true;
|
|
|
+ // 显示错误消息
|
|
|
+ showGameMessage(CONFIG.TIPS.NO_ENTRY, 'error');
|
|
|
+
|
|
|
+ // 立即中止整个代码执行
|
|
|
+ if (executionAbortController) {
|
|
|
+ executionAbortController.abort();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 碰撞状态重置时间后取消碰撞状态
|
|
|
+ setTimeout(() => {
|
|
|
+ gameState.player.isColliding = false;
|
|
|
+ }, CONFIG.DELAY.COLLISION_RESET);
|
|
|
+
|
|
|
+ // 返回一个Promise,允许调用者等待碰撞延迟
|
|
|
+ return new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.COLLISION_DELAY));
|
|
|
}
|
|
|
|
|
|
// 组件卸载时清理
|
|
|
@@ -1255,11 +1428,11 @@ onUnmounted(() => {
|
|
|
/* 可行走区域样式 */
|
|
|
.walkable-point {
|
|
|
position: absolute;
|
|
|
- background-color: rgba(52, 152, 219, 0.2);
|
|
|
- border: 1px solid rgba(52, 152, 219, 0.5);
|
|
|
- box-sizing: border-box;
|
|
|
+ //background-color: rgba(52, 152, 219, 0.2);
|
|
|
+ //border: 1px solid rgba(52, 152, 219, 0.5);
|
|
|
+ //box-sizing: border-box;
|
|
|
//是否显示可行路线
|
|
|
- opacity: 0;
|
|
|
+ opacity: 1;
|
|
|
}
|
|
|
|
|
|
/* 玩家样式 */
|
|
|
@@ -1345,6 +1518,12 @@ onUnmounted(() => {
|
|
|
border: 1px solid #bee5eb;
|
|
|
}
|
|
|
|
|
|
+.game-message.warning {
|
|
|
+ background-color: #baeff8;
|
|
|
+ color: #035767;
|
|
|
+ border: 1px solid #9be9f6;
|
|
|
+}
|
|
|
+
|
|
|
/* Blockly区域样式 */
|
|
|
.blockly-section {
|
|
|
flex: 1;
|