update:语音优化
This commit is contained in:
@@ -20,6 +20,12 @@ export const audioFils = {
|
|||||||
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrda0amn5kqr4j.mp3",
|
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrda0amn5kqr4j.mp3",
|
||||||
距离不足:
|
距离不足:
|
||||||
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6hr2faw28t0ianh0.mp3",
|
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6hr2faw28t0ianh0.mp3",
|
||||||
|
"靶纸不符!请更换靶纸":
|
||||||
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E9%9D%B6%E7%BA%B8%E4%B8%8D%E7%AC%A6%EF%BC%81%E8%AF%B7%E6%9B%B4%E6%8D%A2%E9%9D%B6%E7%BA%B8.MP3",
|
||||||
|
"站距与靶纸合格":
|
||||||
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E7%AB%99%E8%B7%9D%E4%B8%8E%E9%9D%B6%E7%BA%B8%E5%90%88%E6%A0%BC.MP3",
|
||||||
|
"请射箭!测试站距与靶纸":
|
||||||
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E8%AF%B7%E5%B0%84%E7%AE%AD%EF%BC%81%E6%B5%8B%E8%AF%95%E7%AB%99%E8%B7%9D%E4%B8%8E%E9%9D%B6%E7%BA%B8.MP3",
|
||||||
"未发现靶纸,请瞄准靶纸射箭":
|
"未发现靶纸,请瞄准靶纸射箭":
|
||||||
"https://static.shelingxingqiu.com/shootmini/static/audio/%E6%9C%AA%E5%8F%91%E7%8E%B0%E9%9D%B6%E7%BA%B8%EF%BC%8C%E8%AF%B7%E7%9E%84%E5%87%86%E9%9D%B6%E7%BA%B8%E5%B0%84%E7%AE%AD.MP3",
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E6%9C%AA%E5%8F%91%E7%8E%B0%E9%9D%B6%E7%BA%B8%EF%BC%8C%E8%AF%B7%E7%9E%84%E5%87%86%E9%9D%B6%E7%BA%B8%E5%B0%84%E7%AE%AD.MP3",
|
||||||
轮到你了:
|
轮到你了:
|
||||||
@@ -54,6 +60,8 @@ export const audioFils = {
|
|||||||
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%E6%A3%80%E6%9F%A5%E8%B7%9D%E7%A6%BB%E5%92%8C%E9%9D%B6%E7%BA%B8.mp3",
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%E6%A3%80%E6%9F%A5%E8%B7%9D%E7%A6%BB%E5%92%8C%E9%9D%B6%E7%BA%B8.mp3",
|
||||||
"射箭无效,距离不足":
|
"射箭无效,距离不足":
|
||||||
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E8%B7%9D%E7%A6%BB%E4%B8%8D%E8%B6%B3.MP3",
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E8%B7%9D%E7%A6%BB%E4%B8%8D%E8%B6%B3.MP3",
|
||||||
|
"射箭无效,距离不足且靶纸错误":
|
||||||
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E8%B7%9D%E7%A6%BB%E4%B8%8D%E8%B6%B3%E4%B8%94%E9%9D%B6%E7%BA%B8%E9%94%99%E8%AF%AF.MP3",
|
||||||
"射箭无效,未识别到靶纸":
|
"射箭无效,未识别到靶纸":
|
||||||
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E6%9C%AA%E8%AF%86%E5%88%AB%E5%88%B0%E9%9D%B6%E7%BA%B8.MP3",
|
"https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E6%9C%AA%E8%AF%86%E5%88%AB%E5%88%B0%E9%9D%B6%E7%BA%B8.MP3",
|
||||||
"射箭无效,靶纸错误":
|
"射箭无效,靶纸错误":
|
||||||
@@ -126,8 +134,12 @@ const AUDIO_WARM_PRIORITY_KEYS = [
|
|||||||
"比赛结束",
|
"比赛结束",
|
||||||
"射击无效",
|
"射击无效",
|
||||||
"射箭无效,距离不足",
|
"射箭无效,距离不足",
|
||||||
|
"射箭无效,距离不足且靶纸错误",
|
||||||
"射箭无效,未识别到靶纸",
|
"射箭无效,未识别到靶纸",
|
||||||
"射箭无效,靶纸错误",
|
"射箭无效,靶纸错误",
|
||||||
|
"靶纸不符!请更换靶纸",
|
||||||
|
"站距与靶纸合格",
|
||||||
|
"请射箭!测试站距与靶纸",
|
||||||
"中场休息",
|
"中场休息",
|
||||||
"下半场开始",
|
"下半场开始",
|
||||||
"决金箭轮",
|
"决金箭轮",
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
import { ref, watch, onMounted, onBeforeUnmount } from "vue";
|
import { ref, watch, onMounted, onBeforeUnmount } from "vue";
|
||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDirectionText, getInvalidShotAudioKey } from "@/util";
|
import {
|
||||||
|
getDirectionText,
|
||||||
|
getInvalidShotAudioKey,
|
||||||
|
getInvalidShotText,
|
||||||
|
} from "@/util";
|
||||||
|
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
@@ -88,7 +92,7 @@ async function onReceiveMessage(message) {
|
|||||||
currentRoundEnded.value = true;
|
currentRoundEnded.value = true;
|
||||||
} else if (type === MESSAGETYPESV2.InvalidShot) {
|
} else if (type === MESSAGETYPESV2.InvalidShot) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "距离不足,无效",
|
title: getInvalidShotText(shootData),
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
audioManager.play(getInvalidShotAudioKey(shootData));
|
audioManager.play(getInvalidShotAudioKey(shootData));
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue";
|
import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue";
|
||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDirectionText, getInvalidShotAudioKey } from "@/util";
|
import {
|
||||||
|
getDirectionText,
|
||||||
|
getInvalidShotAudioKey,
|
||||||
|
getInvalidShotText,
|
||||||
|
} from "@/util";
|
||||||
|
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
@@ -171,7 +175,7 @@ async function onReceiveMessage(msg) {
|
|||||||
audioManager.play("中场休息");
|
audioManager.play("中场休息");
|
||||||
} else if (msg.type === MESSAGETYPESV2.InvalidShot) {
|
} else if (msg.type === MESSAGETYPESV2.InvalidShot) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "距离不足,无效",
|
title: getInvalidShotText(msg.shootData),
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
audioManager.play(getInvalidShotAudioKey(msg.shootData));
|
audioManager.play(getInvalidShotAudioKey(msg.shootData));
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Avatar from "@/components/Avatar.vue";
|
|||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { simulShootAPI } from "@/apis";
|
import { simulShootAPI } from "@/apis";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
|
import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -26,6 +27,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const arrow = ref({});
|
const arrow = ref({});
|
||||||
const distance = ref(0);
|
const distance = ref(0);
|
||||||
|
const statusText = ref("");
|
||||||
const showsimul = ref(false);
|
const showsimul = ref(false);
|
||||||
const count = ref(props.count);
|
const count = ref(props.count);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
@@ -34,7 +36,7 @@ const updateTimer = (value) => {
|
|||||||
count.value = Math.round(value);
|
count.value = Math.round(value);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
audioManager.play("请射箭测试距离");
|
audioManager.play("请射箭!测试站距与靶纸");
|
||||||
if (props.isBattle) {
|
if (props.isBattle) {
|
||||||
timer.value = setInterval(() => {
|
timer.value = setInterval(() => {
|
||||||
count.value -= 1;
|
count.value -= 1;
|
||||||
@@ -51,14 +53,12 @@ onBeforeUnmount(() => {
|
|||||||
async function onReceiveMessage(msg) {
|
async function onReceiveMessage(msg) {
|
||||||
if (Array.isArray(msg)) return;
|
if (Array.isArray(msg)) return;
|
||||||
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
||||||
const rawDistance = Number(msg.shootData?.distance);
|
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
||||||
distance.value = Number.isFinite(rawDistance)
|
distance.value = Number.isFinite(rawDistance)
|
||||||
? Number((rawDistance / 100).toFixed(2))
|
? Number((rawDistance / 100).toFixed(2))
|
||||||
: 0;
|
: 0;
|
||||||
if (rawDistance === 0) {
|
statusText.value = getDistanceCheckText(msg.shootData);
|
||||||
audioManager.play("未发现靶纸,请瞄准靶纸射箭");
|
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
||||||
} else if (distance.value >= 5) audioManager.play("距离合格");
|
|
||||||
else audioManager.play("距离不足");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,13 +101,12 @@ onBeforeUnmount(() => {
|
|||||||
模拟射箭
|
模拟射箭
|
||||||
</button>
|
</button>
|
||||||
<view class="warnning-text">
|
<view class="warnning-text">
|
||||||
<block v-if="distance > 0">
|
<block v-if="statusText">
|
||||||
<text>当前距离{{ distance }}米</text>
|
<text v-if="distance > 0">当前距离{{ distance }}米</text>
|
||||||
<text v-if="distance >= 5">已达到距离要求</text>
|
<text>{{ statusText }}</text>
|
||||||
<text v-else>请调整站位</text>
|
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<text>请射箭,测试站距</text>
|
<text>请射箭,测试站距与靶纸</text>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
<view class="user-row">
|
<view class="user-row">
|
||||||
|
|||||||
+11
-25
@@ -9,7 +9,11 @@ import {
|
|||||||
getServerMessageTypeName,
|
getServerMessageTypeName,
|
||||||
} from "@/utils/matchProtocol";
|
} from "@/utils/matchProtocol";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDirectionText, getInvalidShotAudioKey } from "@/util";
|
import {
|
||||||
|
getDirectionText,
|
||||||
|
getDistanceCheckAudioKey,
|
||||||
|
getInvalidShotAudioKey,
|
||||||
|
} from "@/util";
|
||||||
import {
|
import {
|
||||||
normalizeId,
|
normalizeId,
|
||||||
normalizeMatchInfo,
|
normalizeMatchInfo,
|
||||||
@@ -49,20 +53,6 @@ const ENABLE_REALTIME_MESSAGE_LOG = (() => {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function getServerMessageLogSummary(message = {}) {
|
|
||||||
const practiceInfo = message.practice_info || message.practiceInfo || {};
|
|
||||||
const matchInfo = message.match_info || message.matchInfo || {};
|
|
||||||
return {
|
|
||||||
type: message.type,
|
|
||||||
matchId: normalizeId(pickField(message, "matchId", "match_id")),
|
|
||||||
sequence: message.sequence,
|
|
||||||
practiceDetailCount: Array.isArray(practiceInfo.details)
|
|
||||||
? practiceInfo.details.length
|
|
||||||
: 0,
|
|
||||||
roundCount: Array.isArray(matchInfo.rounds) ? matchInfo.rounds.length : 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 比赛服消息类型先映射成项目里已有的 V2 业务消息,页面仍然复用原来的 socket-inbox 流程。
|
// 比赛服消息类型先映射成项目里已有的 V2 业务消息,页面仍然复用原来的 socket-inbox 流程。
|
||||||
const BUSINESS_TYPE_BY_SERVER_TYPE = {
|
const BUSINESS_TYPE_BY_SERVER_TYPE = {
|
||||||
[ServerMessageType.SERVER_MSG_MATCH_READY]: MESSAGETYPESV2.AboutToStart,
|
[ServerMessageType.SERVER_MSG_MATCH_READY]: MESSAGETYPESV2.AboutToStart,
|
||||||
@@ -87,6 +77,9 @@ function normalizeShootData(shootData) {
|
|||||||
if (normalized.distance === undefined && normalized.dst !== undefined) {
|
if (normalized.distance === undefined && normalized.dst !== undefined) {
|
||||||
normalized.distance = normalized.dst;
|
normalized.distance = normalized.dst;
|
||||||
}
|
}
|
||||||
|
if (normalized.targetOk === undefined && normalized.target_ok !== undefined) {
|
||||||
|
normalized.targetOk = normalized.target_ok;
|
||||||
|
}
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,10 +361,8 @@ function getShootResultAudioKeys(shootData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTestDistanceAudioKeys(shootData) {
|
function getTestDistanceAudioKeys(shootData) {
|
||||||
const distance = Number(shootData?.distance ?? shootData?.dst);
|
if (!shootData) return [];
|
||||||
if (Number.isNaN(distance)) return [];
|
return [getDistanceCheckAudioKey(shootData)];
|
||||||
if (distance === 0) return ["未发现靶纸,请瞄准靶纸射箭"];
|
|
||||||
return [distance / 100 >= 5 ? "\u8ddd\u79bb\u5408\u683c" : "\u8ddd\u79bb\u4e0d\u8db3"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAckAudioKeys(message, businessMessage) {
|
function getAckAudioKeys(message, businessMessage) {
|
||||||
@@ -805,13 +796,8 @@ function handleMessage(data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeName = getServerMessageTypeName(message.type);
|
|
||||||
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
||||||
console.log(
|
console.log("收到比赛服 WebSocket 消息", message);
|
||||||
"收到比赛服 WebSocket 消息",
|
|
||||||
typeName,
|
|
||||||
getServerMessageLogSummary(message)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const decodedMatchId = normalizeId(pickField(message, "matchId", "match_id"));
|
const decodedMatchId = normalizeId(pickField(message, "matchId", "match_id"));
|
||||||
|
|||||||
+11
-9
@@ -22,7 +22,12 @@ import {
|
|||||||
} from "@/apis";
|
} from "@/apis";
|
||||||
import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket";
|
import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket";
|
||||||
import { sharePractiseData } from "@/canvas";
|
import { sharePractiseData } from "@/canvas";
|
||||||
import { wxShare, debounce } from "@/util";
|
import {
|
||||||
|
wxShare,
|
||||||
|
debounce,
|
||||||
|
getDistanceCheckAudioKey,
|
||||||
|
getShootValidation,
|
||||||
|
} from "@/util";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
@@ -154,14 +159,11 @@ async function onReceiveMessage(msg) {
|
|||||||
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
||||||
setTimeout(() => onOver(msg), 1500);
|
setTimeout(() => onOver(msg), 1500);
|
||||||
} else if (msg.type === MESSAGETYPESV2.TestDistance && step.value === 3) {
|
} else if (msg.type === MESSAGETYPESV2.TestDistance && step.value === 3) {
|
||||||
const rawDistance = Number(msg.shootData?.distance);
|
const result = getShootValidation(msg.shootData);
|
||||||
if (rawDistance === 0) {
|
const isQualified = result.distanceOk && result.targetOk;
|
||||||
audioManager.play("未发现靶纸,请瞄准靶纸射箭");
|
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
||||||
} else if (rawDistance / 100 >= 5) {
|
btnDisabled.value = !isQualified;
|
||||||
audioManager.play("距离合格");
|
showGuide.value = isQualified;
|
||||||
btnDisabled.value = false;
|
|
||||||
showGuide.value = true;
|
|
||||||
} else audioManager.play("距离不足");
|
|
||||||
}
|
}
|
||||||
// messages.forEach((msg) => {
|
// messages.forEach((msg) => {
|
||||||
// if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) {
|
// if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Avatar from "./Avatar.vue";
|
|||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { simulShootAPI } from "@/apis";
|
import { simulShootAPI } from "@/apis";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
|
import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -26,6 +27,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const arrow = ref({});
|
const arrow = ref({});
|
||||||
const distance = ref(0);
|
const distance = ref(0);
|
||||||
|
const statusText = ref("");
|
||||||
const showsimul = ref(false);
|
const showsimul = ref(false);
|
||||||
const count = ref(props.count);
|
const count = ref(props.count);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
@@ -34,7 +36,7 @@ const updateTimer = (value) => {
|
|||||||
count.value = Math.round(value);
|
count.value = Math.round(value);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
audioManager.play("请射箭测试距离");
|
audioManager.play("请射箭!测试站距与靶纸");
|
||||||
if (props.isBattle) {
|
if (props.isBattle) {
|
||||||
timer.value = setInterval(() => {
|
timer.value = setInterval(() => {
|
||||||
count.value -= 1;
|
count.value -= 1;
|
||||||
@@ -51,14 +53,12 @@ onBeforeUnmount(() => {
|
|||||||
async function onReceiveMessage(msg) {
|
async function onReceiveMessage(msg) {
|
||||||
if (Array.isArray(msg)) return;
|
if (Array.isArray(msg)) return;
|
||||||
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
||||||
const rawDistance = Number(msg.shootData?.distance);
|
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
||||||
distance.value = Number.isFinite(rawDistance)
|
distance.value = Number.isFinite(rawDistance)
|
||||||
? Number((rawDistance / 100).toFixed(2))
|
? Number((rawDistance / 100).toFixed(2))
|
||||||
: 0;
|
: 0;
|
||||||
if (rawDistance === 0) {
|
statusText.value = getDistanceCheckText(msg.shootData);
|
||||||
audioManager.play("未发现靶纸,请瞄准靶纸射箭");
|
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
||||||
} else if (distance.value >= 5) audioManager.play("距离合格");
|
|
||||||
else audioManager.play("距离不足");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,13 +101,12 @@ onBeforeUnmount(() => {
|
|||||||
模拟射箭
|
模拟射箭
|
||||||
</button>
|
</button>
|
||||||
<view class="warnning-text">
|
<view class="warnning-text">
|
||||||
<block v-if="distance > 0">
|
<block v-if="statusText">
|
||||||
<text>当前距离{{ distance }}米</text>
|
<text v-if="distance > 0">当前距离{{ distance }}米</text>
|
||||||
<text v-if="distance >= 5">已达到距离要求</text>
|
<text>{{ statusText }}</text>
|
||||||
<text v-else>请调整站位</text>
|
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<text>请射箭,测试站距</text>
|
<text>请射箭,测试站距与靶纸</text>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
<view class="user-row">
|
<view class="user-row">
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ import {
|
|||||||
MATCH_WS_STATE_EVENT,
|
MATCH_WS_STATE_EVENT,
|
||||||
} from "@/matchWebsocket";
|
} from "@/matchWebsocket";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDirectionText, getInvalidShotAudioKey } from "@/util";
|
import {
|
||||||
|
getDirectionText,
|
||||||
|
getInvalidShotAudioKey,
|
||||||
|
getInvalidShotText,
|
||||||
|
} from "@/util";
|
||||||
import { takeMatchReturnSnapshot } from "@/utils/matchReturn";
|
import { takeMatchReturnSnapshot } from "@/utils/matchReturn";
|
||||||
import audioManager, {
|
import audioManager, {
|
||||||
AUDIO_INTERRUPTION_BEGIN_EVENT,
|
AUDIO_INTERRUPTION_BEGIN_EVENT,
|
||||||
@@ -1133,7 +1137,7 @@ async function runBattleEndTask(task, runId) {
|
|||||||
async function runInvalidShotTask(task, runId) {
|
async function runInvalidShotTask(task, runId) {
|
||||||
if (!isQueueAlive(runId)) return;
|
if (!isQueueAlive(runId)) return;
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "距离不足,无效",
|
title: getInvalidShotText(task.message?.shootData),
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
await playAudioKeys(getInvalidShotAudioKey(task.message?.shootData), {
|
await playAudioKeys(getInvalidShotAudioKey(task.message?.shootData), {
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue";
|
import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue";
|
||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDirectionText, getInvalidShotAudioKey } from "@/util";
|
import {
|
||||||
|
getDirectionText,
|
||||||
|
getInvalidShotAudioKey,
|
||||||
|
getInvalidShotText,
|
||||||
|
} from "@/util";
|
||||||
import Avatar from "@/components/Avatar.vue";
|
import Avatar from "@/components/Avatar.vue";
|
||||||
|
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
@@ -238,7 +242,7 @@ async function onReceiveMessage(msg) {
|
|||||||
audioManager.play("中场休息");
|
audioManager.play("中场休息");
|
||||||
} else if (msg.type === MESSAGETYPESV2.InvalidShot) {
|
} else if (msg.type === MESSAGETYPESV2.InvalidShot) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "距离不足,无效",
|
title: getInvalidShotText(msg.shootData),
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
audioManager.play(getInvalidShotAudioKey(msg.shootData));
|
audioManager.play(getInvalidShotAudioKey(msg.shootData));
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Avatar from "@/components/Avatar.vue";
|
|||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { simulShootAPI } from "@/apis";
|
import { simulShootAPI } from "@/apis";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
|
import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -30,6 +31,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const arrow = ref({});
|
const arrow = ref({});
|
||||||
const distance = ref(0);
|
const distance = ref(0);
|
||||||
|
const statusText = ref("");
|
||||||
const showsimul = ref(false);
|
const showsimul = ref(false);
|
||||||
const count = ref(props.count);
|
const count = ref(props.count);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
@@ -38,7 +40,7 @@ const updateTimer = (value) => {
|
|||||||
count.value = Math.round(value);
|
count.value = Math.round(value);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
audioManager.play("请射箭测试距离");
|
audioManager.play("请射箭!测试站距与靶纸");
|
||||||
if (props.isBattle) {
|
if (props.isBattle) {
|
||||||
timer.value = setInterval(() => {
|
timer.value = setInterval(() => {
|
||||||
count.value -= 1;
|
count.value -= 1;
|
||||||
@@ -55,14 +57,12 @@ onBeforeUnmount(() => {
|
|||||||
async function onReceiveMessage(msg) {
|
async function onReceiveMessage(msg) {
|
||||||
if (Array.isArray(msg)) return;
|
if (Array.isArray(msg)) return;
|
||||||
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
||||||
const rawDistance = Number(msg.shootData?.distance);
|
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
||||||
distance.value = Number.isFinite(rawDistance)
|
distance.value = Number.isFinite(rawDistance)
|
||||||
? Number((rawDistance / 100).toFixed(2))
|
? Number((rawDistance / 100).toFixed(2))
|
||||||
: 0;
|
: 0;
|
||||||
if (rawDistance === 0) {
|
statusText.value = getDistanceCheckText(msg.shootData);
|
||||||
audioManager.play("未发现靶纸,请瞄准靶纸射箭");
|
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
||||||
} else if (distance.value >= 5) audioManager.play("距离合格");
|
|
||||||
else audioManager.play("距离不足");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +100,12 @@ onBeforeUnmount(() => {
|
|||||||
</button>
|
</button>
|
||||||
<view class="warnning-text">
|
<view class="warnning-text">
|
||||||
<view class="target-tip">当前靶纸为<text class="text-yellow">{{ targetType }}cm</text>全环靶</view>
|
<view class="target-tip">当前靶纸为<text class="text-yellow">{{ targetType }}cm</text>全环靶</view>
|
||||||
<block v-if="distance > 0">
|
<block v-if="statusText">
|
||||||
<text>当前距离<text class="text-yellow">{{ distance }}</text>米</text>
|
<text v-if="distance > 0">当前距离<text class="text-yellow">{{ distance }}</text>米</text>
|
||||||
<text v-if="distance >= 5">已达到距离要求</text>
|
<text>{{ statusText }}</text>
|
||||||
<text v-else>请调整站位</text>
|
|
||||||
</block>
|
</block>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<text>请射箭,测试站距</text>
|
<text>请射箭,测试站距与靶纸</text>
|
||||||
</block>
|
</block>
|
||||||
</view>
|
</view>
|
||||||
<view class="user-row">
|
<view class="user-row">
|
||||||
|
|||||||
+60
-8
@@ -329,18 +329,70 @@ export const getDirectionText = (angle = 0) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 正式射箭阶段的距离单位为厘米,按距离异常类型选择对应语音。
|
// 射箭数据中的距离单位为厘米;旧版本会明确上报 target_ok=true。
|
||||||
export const getInvalidShotAudioKey = (shootData) => {
|
export const getShootValidation = (shootData) => {
|
||||||
if (!shootData || typeof shootData !== "object") return "射击无效";
|
if (!shootData || typeof shootData !== "object") {
|
||||||
// protobuf 会省略值为 0 的标量字段;消息体存在且距离缺失时按 0 处理。
|
return {
|
||||||
|
rawDistance: 0,
|
||||||
|
distance: 0,
|
||||||
|
distanceOk: false,
|
||||||
|
targetOk: false,
|
||||||
|
targetDetected: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const rawDistance = Number(shootData.distance ?? shootData.dst ?? 0);
|
const rawDistance = Number(shootData.distance ?? shootData.dst ?? 0);
|
||||||
if (!Number.isFinite(rawDistance)) return "射击无效";
|
const finiteDistance = Number.isFinite(rawDistance) ? rawDistance : 0;
|
||||||
if (rawDistance < 0) return "射箭无效,靶纸错误";
|
const targetFlag = shootData.targetOk ?? shootData.target_ok;
|
||||||
if (rawDistance === 0) return "射箭无效,未识别到靶纸";
|
const targetDetected = finiteDistance !== 0;
|
||||||
if (rawDistance / 100 < 5) return "射箭无效,距离不足";
|
const targetOk = finiteDistance > 0 && targetFlag === true;
|
||||||
|
|
||||||
|
return {
|
||||||
|
rawDistance: finiteDistance,
|
||||||
|
distance: Math.max(0, finiteDistance / 100),
|
||||||
|
// 旧固件以负距离表示靶纸错误,此时只提示靶纸问题,不叠加距离不足。
|
||||||
|
distanceOk: finiteDistance < 0 || finiteDistance >= 500,
|
||||||
|
targetOk: targetDetected && targetOk,
|
||||||
|
targetDetected,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 测距阶段提示音:同时校验站距和靶纸,保留旧版本距离不足音频。
|
||||||
|
export const getDistanceCheckAudioKey = (shootData) => {
|
||||||
|
const result = getShootValidation(shootData);
|
||||||
|
if (!result.targetDetected) return "未发现靶纸,请瞄准靶纸射箭";
|
||||||
|
if (!result.distanceOk && !result.targetOk) {
|
||||||
|
return "射箭无效,距离不足且靶纸错误";
|
||||||
|
}
|
||||||
|
if (!result.targetOk) return "靶纸不符!请更换靶纸";
|
||||||
|
if (result.distanceOk) return "站距与靶纸合格";
|
||||||
|
return "距离不足";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDistanceCheckText = (shootData) => {
|
||||||
|
const result = getShootValidation(shootData);
|
||||||
|
if (!result.targetDetected) return "未识别到靶纸,请瞄准靶纸射箭";
|
||||||
|
if (result.rawDistance < 0) return "靶纸错误";
|
||||||
|
return `${result.distanceOk ? "站距合格" : "站距过近"},${
|
||||||
|
result.targetOk ? "靶纸正确" : "靶纸错误"
|
||||||
|
}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 正式射箭阶段的距离和靶纸异常类型选择对应语音。
|
||||||
|
export const getInvalidShotAudioKey = (shootData) => {
|
||||||
|
const result = getShootValidation(shootData);
|
||||||
|
if (!result.targetDetected) return "射箭无效,未识别到靶纸";
|
||||||
|
if (!result.distanceOk && !result.targetOk) {
|
||||||
|
return "射箭无效,距离不足且靶纸错误";
|
||||||
|
}
|
||||||
|
if (!result.targetOk) return "射箭无效,靶纸错误";
|
||||||
|
if (!result.distanceOk) return "射箭无效,距离不足";
|
||||||
return "射击无效";
|
return "射击无效";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getInvalidShotText = (shootData) =>
|
||||||
|
getInvalidShotAudioKey(shootData);
|
||||||
|
|
||||||
export const wxLogin = () => {
|
export const wxLogin = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
uni.login({
|
uni.login({
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -7,8 +7,8 @@ const { Reader, Writer } = protobuf;
|
|||||||
// 所以这里使用 minimal Reader/Writer 做静态字段解码和客户端消息编码。
|
// 所以这里使用 minimal Reader/Writer 做静态字段解码和客户端消息编码。
|
||||||
// <match-schema-generated>
|
// <match-schema-generated>
|
||||||
// 此区块由 scripts/generate-match-schema.mjs 自动生成,请勿手动修改。
|
// 此区块由 scripts/generate-match-schema.mjs 自动生成,请勿手动修改。
|
||||||
// 来源:src/utils/match.min.js(sha256: 150812589c2e6f7a)
|
// 来源:src/utils/match.min.js(sha256: a7ab92ae43e405e7)
|
||||||
// 协议命名空间:rpc;消息数:12;字段数:151
|
// 协议命名空间:rpc;消息数:12;字段数:153
|
||||||
|
|
||||||
export const ServerMessageType = {
|
export const ServerMessageType = {
|
||||||
SERVER_MSG_UNKNOWN: 0,
|
SERVER_MSG_UNKNOWN: 0,
|
||||||
@@ -51,6 +51,7 @@ const SCHEMAS = {
|
|||||||
8: { name: "distance", kind: "float" },
|
8: { name: "distance", kind: "float" },
|
||||||
9: { name: "three_consecutive_10_rings", kind: "bool" },
|
9: { name: "three_consecutive_10_rings", kind: "bool" },
|
||||||
10: { name: "ok", kind: "bool" },
|
10: { name: "ok", kind: "bool" },
|
||||||
|
11: { name: "target_ok", kind: "bool" },
|
||||||
},
|
},
|
||||||
MatchShootList: {
|
MatchShootList: {
|
||||||
1: { name: "items", kind: "message", type: "MatchShoot", repeated: true },
|
1: { name: "items", kind: "message", type: "MatchShoot", repeated: true },
|
||||||
@@ -139,6 +140,7 @@ const SCHEMAS = {
|
|||||||
7: { name: "device_id", kind: "string" },
|
7: { name: "device_id", kind: "string" },
|
||||||
8: { name: "shoot_id", kind: "string" },
|
8: { name: "shoot_id", kind: "string" },
|
||||||
9: { name: "three_consecutive_10_rings", kind: "bool" },
|
9: { name: "three_consecutive_10_rings", kind: "bool" },
|
||||||
|
10: { name: "target_ok", kind: "bool" },
|
||||||
},
|
},
|
||||||
PracticeInfo: {
|
PracticeInfo: {
|
||||||
1: { name: "id", kind: "int64" },
|
1: { name: "id", kind: "int64" },
|
||||||
|
|||||||
Reference in New Issue
Block a user