|
@@ -9,7 +9,6 @@
|
|
|
:key="index"
|
|
:key="index"
|
|
|
class="game-badge"
|
|
class="game-badge"
|
|
|
:class="{ 'active': currentRouteIndex === index }"
|
|
:class="{ 'active': currentRouteIndex === index }"
|
|
|
- @click="switchRoute(index)"
|
|
|
|
|
>
|
|
>
|
|
|
{{ gameSort }}{{ index + 1 }}
|
|
{{ gameSort }}{{ index + 1 }}
|
|
|
</button>
|
|
</button>
|
|
@@ -43,7 +42,7 @@
|
|
|
class="walkable-point"
|
|
class="walkable-point"
|
|
|
:style="getPointStyle(point)"
|
|
:style="getPointStyle(point)"
|
|
|
>
|
|
>
|
|
|
- </div>
|
|
|
|
|
|
|
+</div>
|
|
|
|
|
|
|
|
<!-- 玩家角色 -->
|
|
<!-- 玩家角色 -->
|
|
|
<div
|
|
<div
|
|
@@ -156,7 +155,6 @@ import errorMp3 from '@/assets/music/blockly/error.MP3'
|
|
|
import { registerCustomBlocks, registerJavaScriptGenerators, registerPythonGenerators, initBlockly } from '@/api/blockly/blockly.js';
|
|
import { registerCustomBlocks, registerJavaScriptGenerators, registerPythonGenerators, initBlockly } from '@/api/blockly/blockly.js';
|
|
|
import {playMp3} from "@/api/blockly/music.js";
|
|
import {playMp3} from "@/api/blockly/music.js";
|
|
|
|
|
|
|
|
-
|
|
|
|
|
import cupbg from '@/assets/blockly/cupbg.png' // 通关后奖杯底图
|
|
import cupbg from '@/assets/blockly/cupbg.png' // 通关后奖杯底图
|
|
|
import nocupbg from '@/assets/blockly/nocupbg.png' // 通关失败后奖杯底图
|
|
import nocupbg from '@/assets/blockly/nocupbg.png' // 通关失败后奖杯底图
|
|
|
import goldcup from '@/assets/blockly/goldcup.png' // 金杯
|
|
import goldcup from '@/assets/blockly/goldcup.png' // 金杯
|
|
@@ -178,7 +176,6 @@ const passConfig = ref({
|
|
|
passBackground: "",// 通关后奖杯底图
|
|
passBackground: "",// 通关后奖杯底图
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// 定义emits
|
|
// 定义emits
|
|
|
const emits = defineEmits(['saveProgress'])
|
|
const emits = defineEmits(['saveProgress'])
|
|
|
// 定义组件属性
|
|
// 定义组件属性
|
|
@@ -228,11 +225,6 @@ const props = defineProps({
|
|
|
type: String,
|
|
type: String,
|
|
|
default: ''
|
|
default: ''
|
|
|
},
|
|
},
|
|
|
- // 游戏标题
|
|
|
|
|
- gameTitle: {
|
|
|
|
|
- type: String,
|
|
|
|
|
- default: ''
|
|
|
|
|
- },
|
|
|
|
|
// 路线列表
|
|
// 路线列表
|
|
|
routeList: {
|
|
routeList: {
|
|
|
type: [String, Array],
|
|
type: [String, Array],
|
|
@@ -255,12 +247,6 @@ const props = defineProps({
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-// 关闭遮罩层
|
|
|
|
|
-const closeOverlay = () => {
|
|
|
|
|
- gameState.player.hasReachedEnd = false;
|
|
|
|
|
- showOverlay.value = false;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
// 配置常量
|
|
// 配置常量
|
|
|
const CONFIG = {
|
|
const CONFIG = {
|
|
|
// 动画时长配置(毫秒)
|
|
// 动画时长配置(毫秒)
|
|
@@ -315,6 +301,7 @@ const CONFIG = {
|
|
|
NO_ENTRY: '当前位置无通路,无法移动',
|
|
NO_ENTRY: '当前位置无通路,无法移动',
|
|
|
UNFINISHED: '任务未完成!',
|
|
UNFINISHED: '任务未完成!',
|
|
|
EFFORT: '再接再厉!',
|
|
EFFORT: '再接再厉!',
|
|
|
|
|
+ PASS_ROUTE: '恭喜你通过了当前路线,进入下一条路线!',
|
|
|
FINISH: '恭喜你到达终点!',
|
|
FINISH: '恭喜你到达终点!',
|
|
|
PICKUP_ITEM: '拾取物品成功!',
|
|
PICKUP_ITEM: '拾取物品成功!',
|
|
|
NULL_PICKUP_ITEM: '当前位置没有可拾取的物品',
|
|
NULL_PICKUP_ITEM: '当前位置没有可拾取的物品',
|
|
@@ -326,19 +313,28 @@ const CONFIG = {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 路由和游戏状态
|
|
// 路由和游戏状态
|
|
|
-const gameTitle = computed(() => props.gameTitle);
|
|
|
|
|
const currentGameData = ref(null);
|
|
const currentGameData = ref(null);
|
|
|
const playerInitialDirection = ref(0); // 人物初始朝向
|
|
const playerInitialDirection = ref(0); // 人物初始朝向
|
|
|
const gameSort = ref('Game'); // 默认排序
|
|
const gameSort = ref('Game'); // 默认排序
|
|
|
const currentRouteIndex = ref(0); // 当前线路索引
|
|
const currentRouteIndex = ref(0); // 当前线路索引
|
|
|
|
|
|
|
|
|
|
+// 路线通过状态:存储各路线的通过状态
|
|
|
|
|
+const routePassedStatus = ref([]);
|
|
|
|
|
+
|
|
|
// 解析routeList
|
|
// 解析routeList
|
|
|
const parsedRouteList = computed(() => {
|
|
const parsedRouteList = computed(() => {
|
|
|
if (!props.routeList) return [];
|
|
if (!props.routeList) return [];
|
|
|
try {
|
|
try {
|
|
|
const routeData = typeof props.routeList === 'string' ? JSON.parse(props.routeList) : props.routeList;
|
|
const routeData = typeof props.routeList === 'string' ? JSON.parse(props.routeList) : props.routeList;
|
|
|
- return Array.isArray(routeData) ? routeData : [];
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
|
|
+ const routes = Array.isArray(routeData) ? routeData : [];
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化路线通过状态
|
|
|
|
|
+ if (routePassedStatus.value.length === 0 && routes.length > 0) {
|
|
|
|
|
+ routePassedStatus.value = routes.map((_, index) => index === 0); // 第一条路线默认可用
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return routes;
|
|
|
|
|
+} catch (error) {
|
|
|
console.error('解析routeList失败:', error);
|
|
console.error('解析routeList失败:', error);
|
|
|
return [];
|
|
return [];
|
|
|
}
|
|
}
|
|
@@ -623,7 +619,8 @@ const fetchGameData = async () => {
|
|
|
|
|
|
|
|
// 切换线路
|
|
// 切换线路
|
|
|
const switchRoute = (index) => {
|
|
const switchRoute = (index) => {
|
|
|
- if (index < 0 || index >= parsedRouteList.value.length) return;
|
|
|
|
|
|
|
+ // 检查路线是否可用
|
|
|
|
|
+ if (index < 0 || index >= parsedRouteList.value.length || !isRouteAvailable(index)) return;
|
|
|
|
|
|
|
|
currentRouteIndex.value = index;
|
|
currentRouteIndex.value = index;
|
|
|
const route = parsedRouteList.value[index];
|
|
const route = parsedRouteList.value[index];
|
|
@@ -647,8 +644,16 @@ const switchRoute = (index) => {
|
|
|
gameState.mapData.endPoint = { x: endPoint.x, y: endPoint.y };
|
|
gameState.mapData.endPoint = { x: endPoint.x, y: endPoint.y };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 重新初始化可行走点集合
|
|
|
|
|
- initWalkablePointsSet();
|
|
|
|
|
|
|
+ // 重新初始化可行走点集合【目前没有单独配置路线的可行走集合,一张地图通用】
|
|
|
|
|
+ // initWalkablePointsSet();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 检查路线是否可用
|
|
|
|
|
+const isRouteAvailable = (index) => {
|
|
|
|
|
+ // 第一条路线始终可用
|
|
|
|
|
+ if (index === 0) return true;
|
|
|
|
|
+ // 其他路线需要前一条路线通过
|
|
|
|
|
+ return routePassedStatus.value[index - 1];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 根据获取到的数据更新游戏状态
|
|
// 根据获取到的数据更新游戏状态
|
|
@@ -975,6 +980,12 @@ function showGameMessage(message, type = 'info', duration = CONFIG.DELAY.MESSAGE
|
|
|
}, duration);
|
|
}, duration);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 关闭遮罩层
|
|
|
|
|
+const closeOverlay = () => {
|
|
|
|
|
+ gameState.player.hasReachedEnd = false;
|
|
|
|
|
+ showOverlay.value = false;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
//================积木组件方法=====================
|
|
//================积木组件方法=====================
|
|
|
|
|
|
|
|
// 向前移动
|
|
// 向前移动
|
|
@@ -1345,7 +1356,19 @@ window.isFinish = async function() {
|
|
|
if (isColliding.value) {
|
|
if (isColliding.value) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 校验是否到达终点
|
|
|
if (gameState.player.position.x === endPoint.value.x && gameState.player.position.y === endPoint.value.y) {
|
|
if (gameState.player.position.x === endPoint.value.x && gameState.player.position.y === endPoint.value.y) {
|
|
|
|
|
+
|
|
|
|
|
+ // 如果通过了当前路线,标记为已通过并自动切换到下一个路线(true:切换下一关,false:全部通关)
|
|
|
|
|
+ if (markCurrentRouteAsPassed()){
|
|
|
|
|
+ //通关路线提示
|
|
|
|
|
+ showGameMessage(CONFIG.TIPS.PASS_ROUTE, 'success');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 全部通关
|
|
|
|
|
+
|
|
|
// 统计所有类型为TASK的任务点总数||必须完成拾取物品的人物总数
|
|
// 统计所有类型为TASK的任务点总数||必须完成拾取物品的人物总数
|
|
|
const totalTasks = gameState.mapData.walkablePoints.filter(
|
|
const totalTasks = gameState.mapData.walkablePoints.filter(
|
|
|
p => p.type === BLOCKLY_MAP_TYPE_DICT.TASK ||
|
|
p => p.type === BLOCKLY_MAP_TYPE_DICT.TASK ||
|
|
@@ -1356,6 +1379,7 @@ window.isFinish = async function() {
|
|
|
p => p.type === BLOCKLY_MAP_TYPE_DICT.TASK && p.status === true
|
|
p => p.type === BLOCKLY_MAP_TYPE_DICT.TASK && p.status === true
|
|
|
|| p.type === BLOCKLY_MAP_TYPE_DICT.ITEM && p.must === true && p.status === true
|
|
|| p.type === BLOCKLY_MAP_TYPE_DICT.ITEM && p.must === true && p.status === true
|
|
|
).length;
|
|
).length;
|
|
|
|
|
+
|
|
|
//blockly总星星数量
|
|
//blockly总星星数量
|
|
|
//无任务情况下直接完成
|
|
//无任务情况下直接完成
|
|
|
if (totalTasks === 0 || completedTasks === totalTasks) {
|
|
if (totalTasks === 0 || completedTasks === totalTasks) {
|
|
@@ -1850,15 +1874,14 @@ async function animateItemUse(item, itemIndex, finishAnimation) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 展示通过动画
|
|
// 展示通过动画
|
|
|
-async function showPass(passStar){
|
|
|
|
|
-
|
|
|
|
|
|
|
+async function showPass(passStar) {
|
|
|
// 记录通过的星星数量
|
|
// 记录通过的星星数量
|
|
|
passConfig.value.passStar = passStar;
|
|
passConfig.value.passStar = passStar;
|
|
|
|
|
|
|
|
passConfig.value.title = 'YOU WIN!';
|
|
passConfig.value.title = 'YOU WIN!';
|
|
|
passConfig.value.passBackground = cupbg;
|
|
passConfig.value.passBackground = cupbg;
|
|
|
|
|
|
|
|
- switch (passStar){
|
|
|
|
|
|
|
+ switch (passStar) {
|
|
|
case 0:
|
|
case 0:
|
|
|
passConfig.value.title = 'YOU LOSE!';
|
|
passConfig.value.title = 'YOU LOSE!';
|
|
|
passConfig.value.passTrophy = nocup;
|
|
passConfig.value.passTrophy = nocup;
|
|
@@ -1882,6 +1905,22 @@ async function showPass(passStar){
|
|
|
showOverlay.value = true;
|
|
showOverlay.value = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 标记当前路线为已通过
|
|
|
|
|
+const markCurrentRouteAsPassed = () => {
|
|
|
|
|
+ routePassedStatus.value[currentRouteIndex.value] = true;
|
|
|
|
|
+
|
|
|
|
|
+ // 自动切换到下一个可用路线
|
|
|
|
|
+ if (currentRouteIndex.value < parsedRouteList.value.length - 1) {
|
|
|
|
|
+ // 解锁下一个路线
|
|
|
|
|
+ routePassedStatus.value[currentRouteIndex.value + 1] = true;
|
|
|
|
|
+ // 自动切换到下一个路线
|
|
|
|
|
+ switchRoute(currentRouteIndex.value + 1);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
//================卸载区=====================
|
|
//================卸载区=====================
|
|
|
// 组件卸载时清理
|
|
// 组件卸载时清理
|
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
@@ -2696,10 +2735,34 @@ button {
|
|
|
transition: all 0.3s ease;
|
|
transition: all 0.3s ease;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-button:hover {
|
|
|
|
|
- background: #2980b9;
|
|
|
|
|
|
|
+.game-badge:hover {
|
|
|
|
|
+ background-color: #3498db;
|
|
|
transform: translateY(-2px);
|
|
transform: translateY(-2px);
|
|
|
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
+ box-shadow: 0 rpx(5) rpx(10) rgba(0, 0, 0, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.game-badge.active {
|
|
|
|
|
+ background-color: #e74c3c;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.game-badge.passed {
|
|
|
|
|
+ background-color: #27ae60;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.game-badge.disabled {
|
|
|
|
|
+ background-color: #bdc3c7;
|
|
|
|
|
+ color: #7f8c8d;
|
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
|
+ pointer-events: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.game-badge.disabled:hover {
|
|
|
|
|
+ background-color: #bdc3c7;
|
|
|
|
|
+ transform: none;
|
|
|
|
|
+ box-shadow: none;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#runCode {
|
|
#runCode {
|