Commit fad6862c by Hantao

feat: 新增第四关卡并优化关卡导航与进度管理

- 新增第四关卡页面,包含完成弹窗和徽章展示
- 在游戏状态管理中添加第四关卡状态跟踪
- 优化第二关导航流程,调整part4起始页跳转逻辑
- 在第二、三关卡添加成功组件展示徽章
- 更新首页进度计算逻辑,支持第四关卡显示
- 添加静态资源文件支持新关卡
parent 0abe465b
......@@ -81,6 +81,12 @@
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/fourth/index",
"style": {
"navigationStyle": "custom"
}
}
],
"globalStyle": {
......
<script setup>
import { ref } from 'vue';
import { useGameStore } from '@/stores/game';
import navBar from '@/components/navBar.vue';
import success from '@/components/success.vue';
const gameStore = useGameStore();
const ASSETS = Object.freeze({
completionPopup: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d204d71cf2a54b18a6404e6132618cd6%E5%AE%8C%E6%88%90%E5%BC%B9%E7%AA%97.webp',
});
const showCompletionModal = ref(false);
const showSuccess1 = ref(false);
const showSuccess2 = ref(false);
const handleFinish = () => {
showCompletionModal.value = true;
};
const closeCompletionModal = () => {
showCompletionModal.value = false;
showSuccess1.value = true;
};
const handleSuccess1Confirm = () => {
showSuccess1.value = false;
showSuccess2.value = true;
};
const handleSuccess2Confirm = () => {
showSuccess2.value = false;
gameStore.setFourthLevelStatus(true);
uni.reLaunch({ url: '/pages/start/index' });
};
</script>
<template>
<navBar />
<view class="next" @click="handleFinish">完成</view>
<!-- 完成弹窗 - 全屏覆盖 -->
<view class="completion-modal" v-if="showCompletionModal" @click="closeCompletionModal">
<image
class="modal-image"
:src="ASSETS.completionPopup"
mode="scaleToFill"
/>
</view>
<!-- 第一个徽章 -->
<success
:show="showSuccess1"
:badge-index="4"
title="精准控水达人"
sub-title="已完成第四关卡"
@close="showSuccess1 = false"
@confirm="handleSuccess1Confirm"
/>
<!-- 第二个徽章 -->
<success
:show="showSuccess2"
:badge-index="5"
title="水质专家"
sub-title="已完成全部关卡"
@close="showSuccess2 = false"
@confirm="handleSuccess2Confirm"
/>
</template>
<style scoped lang="scss">
.next {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 40rpx;
color: #333;
}
.completion-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
.modal-image {
width: 100%;
height: 100%;
}
}
</style>
\ No newline at end of file
<script setup>
import navBar from '@/components/navBar.vue';
import success from '@/components/success.vue';
import { ref, computed } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { useGameStore } from '@/stores/game';
const gameStore = useGameStore();
const showSuccess = ref(false);
const ASSETS = Object.freeze({
bg: '/static/second/bg.webp',
......@@ -34,7 +36,8 @@ const currentStep = computed(() => {
});
const currentInfo = computed(() => {
const step = currentStep.value >= 4 ? 3 : currentStep.value;
const step = currentStep.value;
if (step >= 4) return ASSETS.info; // 全部完成显示 info
return INFO_MAP[step] || ASSETS.info1;
});
......@@ -46,8 +49,7 @@ const currentJdt = computed(() => {
const handleNext = () => {
const step = currentStep.value;
if (step >= 4) {
// 如果已经全部完成,跳转到第三关
uni.navigateTo({ url: '/pages/third/index' });
showSuccess.value = true;
return;
}
......@@ -55,11 +57,16 @@ const handleNext = () => {
0: '/pages/second/part1',
1: '/pages/second/part2',
2: '/pages/second/part3',
3: '/pages/second/part4/index',
3: '/pages/second/part4/start',
};
const url = urlMap[step];
uni.navigateTo({ url });
};
const handleSuccessConfirm = () => {
showSuccess.value = false;
uni.reLaunch({ url: '/pages/start/index' });
};
</script>
<template>
......@@ -89,6 +96,14 @@ const handleNext = () => {
</view>
</view>
</view>
<success
:show="showSuccess"
:badge-index="2"
title="滤芯工程师"
sub-title="已完成第二关卡"
@confirm="handleSuccessConfirm"
@close="showSuccess = false"
/>
</view>
</template>
......
<script setup>
import { useGameStore } from '@/stores/game';
import navBar from '@/components/navBar.vue';
const gameStore = useGameStore();
......@@ -10,6 +11,7 @@ const handleNext = () => {
</script>
<template>
<navBar />
<view class="next" @click="handleNext">下一关</view>
</template>
......
......@@ -122,9 +122,7 @@ const handleComplete = () => isComplete.value && (showCompletion.value = true);
const closeCompletion = () => {
showCompletion.value = false;
gameStore.setSecondLevelPartStatus('part4', true);
uni.reLaunch({
url: '/pages/second/index'
});
uni.reLaunch({ url: '/pages/second/index' });
};
// 获取电池图标
......@@ -662,4 +660,4 @@ onMounted(() => {
height: 100%;
}
}
</style>
</style>
\ No newline at end of file
<script setup>
import navBar from '@/components/navBar.vue';
const ASSETS = Object.freeze({
bg: '/static/second/part4/start/bg.webp',
battery1: '/static/second/part4/start/1.webp',
......@@ -15,10 +16,15 @@ const ASSETS = Object.freeze({
sz: '/static/sz.webp',
jt: '/static/second/part4/start/jt.webp',
});
const handleStart = () => {
uni.navigateTo({ url: '/pages/second/part4/index' });
};
</script>
<template>
<view class="container">
<navBar />
<image class="bg-img" :src="ASSETS.bg" mode="aspectFill" />
<view class="title">滤芯排序游戏</view>
<view class="info">
......@@ -39,7 +45,7 @@ const ASSETS = Object.freeze({
<view class="battery-container"></view>
<image class="drag-bg" :src="ASSETS.dragBg" mode="scaleToFill" />
<view class="hint-text">拖到这里!</view>
<image class="right-icon" :src="ASSETS.right" mode="scaleToFill" />
<image class="right-icon" :src="ASSETS.right" mode="scaleToFill" @click="handleStart" />
</view>
<view class="desc">
<view class="desc-text">后置碳棒在第四层!</view>
......@@ -259,4 +265,4 @@ const ASSETS = Object.freeze({
text-shadow: 1rpx 1rpx 0 #FFF, -1rpx -1rpx 0 #FFF, 1rpx -1rpx 0 #FFF, -1rpx 1rpx 0 #FFF;
}
}
</style>
</style>
\ No newline at end of file
......@@ -31,18 +31,32 @@ const ASSETS = Object.freeze ({
// 根据 store 计算进度
const progressLevel = computed(() => {
if (gameStore.levels.third.completed) return 5;
if (gameStore.levels.second.completed) return 4;
// 第二关的部分进度
const parts = gameStore.levels.second.parts;
const completedParts = Object.values(parts).filter(p => p).length;
if (completedParts > 0) {
// 映射到 1-4 之间的进度
return 1 + completedParts;
}
if (gameStore.levels.first.completed) return 1;
const { first, second, third, fourth } = gameStore.levels;
if (fourth.completed) return 5;
if (fourth.started) return 4;
if (third.completed) return 4;
if (third.started) return 3;
if (second.completed) return 3;
if (second.started) return 2;
if (first.completed) return 2;
if (first.started) return 1;
return 0;
});
// 根据 store 计算获得的勋章数
const badgeLevel = computed(() => {
const { first, second, third, fourth } = gameStore.levels;
if (fourth.completed) return 5;
if (third.completed) return 3;
if (second.completed) return 2;
if (first.completed) return 1;
return 0;
});
......@@ -60,15 +74,14 @@ const getProgressImage = () => {
};
const getBadgeImage = () => {
const level = Math.floor(progressLevel.value);
const level = badgeLevel.value;
switch (level) {
case 0: return;
case 1: return ASSETS.badge1;
case 2: return ASSETS.badge2;
case 3: return ASSETS.badge3;
case 4: return ASSETS.badge4;
case 5: return ASSETS.badge5;
default: return ASSETS.badge1;
default: return;
}
};
......@@ -76,13 +89,21 @@ const getBadgeImage = () => {
const isSidebarExpanded = ref(false);
const handleStart = () => {
const level = Math.floor(progressLevel.value);
if (level === 0) {
const { first, second, third, fourth } = gameStore.levels;
if (!first.completed) {
gameStore.setLevelStarted('first');
uni.navigateTo({ url: '/pages/first/index' });
} else if (level < 4) {
} else if (!second.completed) {
gameStore.setLevelStarted('second');
uni.navigateTo({ url: '/pages/second/index' });
} else {
} else if (!third.completed) {
gameStore.setLevelStarted('third');
uni.navigateTo({ url: '/pages/third/index' });
} else if (!fourth.completed) {
gameStore.setLevelStarted('fourth');
// 跳转到第四关的起始页
uni.navigateTo({ url: '/pages/fourth/index' });
}
};
......@@ -93,15 +114,18 @@ const handleRestart = () => {
success: (res) => {
if (res.confirm) {
gameStore.resetAllProgress();
uni.showToast({
title: '进度已重置',
icon: 'success'
});
}
}
});
};
const navToBadgePage = () => {
const badge = Math.floor(progressLevel.value);
uni.navigateTo({
url: `/pages/badge/index?badge=${badge}`
url: `/pages/badge/index?badge=${badgeLevel.value}`
});
};
......@@ -166,7 +190,7 @@ onShareAppMessage(() => {
<!-- 按钮区域 -->
<view class="btn-group">
<view class="btn-item" @click="handleStart">
<image class="btn-img start-btn" :src="progressImgs === 5 ? ASSETS.finishBtn : ASSETS.startBtn" mode="widthFix" />
<image class="btn-img start-btn" :src="progressLevel === 5 ? ASSETS.finishBtn : ASSETS.startBtn" mode="widthFix" />
</view>
<view class="btn-item" @click="handleRestart">
......
......@@ -2,12 +2,14 @@
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import navBar from '@/components/navBar.vue';
import success from '@/components/success.vue';
import Beaker from './components/beaker.vue';
import TabsInstructionsPanel from './components/TabsInstructionsPanel.vue';
import BottomActionBar from './components/BottomActionBar.vue';
import { useGameStore } from '@/stores/game';
const gameStore = useGameStore();
const showSuccess = ref(false);
const assets = {
bg: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/963079c98b914f349fe9ff5e600d0f65%E6%B0%B4%E8%B4%A8%E6%A3%80%E6%B5%8B%E7%AB%99_%E7%BA%AF%E8%83%8C%E6%99%AF%201.webp',
......@@ -61,9 +63,12 @@ const handleShowCompletion = () => {
const closeCompletion = () => {
showCompletion.value = false;
gameStore.setThirdLevelStatus(true);
uni.reLaunch({
url: '/pages/start/index'
});
showSuccess.value = true;
};
const handleSuccessConfirm = () => {
showSuccess.value = false;
uni.reLaunch({ url: '/pages/start/index' });
};
</script>
......@@ -107,6 +112,15 @@ const closeCompletion = () => {
@click.stop="closeCompletion"
/>
</view>
<success
:show="showSuccess"
:badge-index="3"
title="水质分析高手"
sub-title="已完成第三关卡"
@confirm="handleSuccessConfirm"
@close="showSuccess = false"
/>
</view>
</template>
......
......@@ -5,10 +5,12 @@ export const useGameStore = defineStore('game', {
// 关卡完成状态
levels: {
first: {
started: false,
completed: false,
lastStage: 'garbageCleanup', // 当前完成到的阶段
},
second: {
started: false,
completed: false,
parts: {
part1: false,
......@@ -18,11 +20,22 @@ export const useGameStore = defineStore('game', {
}
},
third: {
started: false,
completed: false
},
fourth: {
started: false,
completed: false
}
}
}),
actions: {
// 设置关卡开始状态
setLevelStarted(level) {
if (this.levels[level]) {
this.levels[level].started = true;
}
},
// 设置第一关状态
setFirstLevelStatus(status, stage) {
this.levels.first.completed = status;
......@@ -46,14 +59,20 @@ export const useGameStore = defineStore('game', {
setThirdLevelStatus(status) {
this.levels.third.completed = status;
},
// 设置第四关状态
setFourthLevelStatus(status) {
this.levels.fourth.completed = status;
},
// 重置所有进度
resetAllProgress() {
this.levels = {
first: {
started: false,
completed: false,
lastStage: 'garbageCleanup',
},
second: {
started: false,
completed: false,
parts: {
part1: false,
......@@ -63,6 +82,11 @@ export const useGameStore = defineStore('game', {
}
},
third: {
started: false,
completed: false
},
fourth: {
started: false,
completed: false
}
};
......@@ -75,4 +99,4 @@ export const useGameStore = defineStore('game', {
setItem: (key, value) => uni.setStorageSync(key, value),
},
},
});
});
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment