功能:記分板語音改為報比分、發球區、賽末點與獲勝隊伍
摘要: - 得分播報改為「比分(發球方先報)+ 發球者左右發球區」 - 發球方到賽末點(再得 1 分即獲勝)時,比分後加唸「賽末點」 - 賽末點得分獲勝時,整段改播「<獲勝隊伍> 贏得比賽」 - 發球區左右一律用實際球場方向,取消上方隊伍鏡像;畫面「發球區」顯示同步改為不鏡像,與語音一致 根本原因: - 現場記分需要即時聽到比分與發球位置,原本只唸「誰得分、誰發球」較不直覺 - 先前發球區對上方隊伍做鏡像,導致語音與實際球場方向相反 影響: - src/App.tsx:recordPoint 計算發球方比分、發球區、賽末點與獲勝隊伍,重整 voiceAnnouncement 欄位 - src/pages/ScoreboardPage.tsx:語音組字改為「X比Y(賽末點)」「OO左/右邊發球」、獲勝改播「贏得比賽」;發球區顯示移除鏡像;語音設定「播報誰得分」更名「播報比分」 修法: - 發球方分數先報;賽末點僅在發球方再得 1 分就獲勝時觸發;發球區統一用 getServiceCourt 實際方向 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+12
-5
@@ -89,6 +89,7 @@ type VoiceAnnouncement = {
|
|||||||
opponentScore: number
|
opponentScore: number
|
||||||
serverName: string
|
serverName: string
|
||||||
serverCourt: 'left' | 'right'
|
serverCourt: 'left' | 'right'
|
||||||
|
matchPoint: boolean
|
||||||
winnerTeamName: string | null
|
winnerTeamName: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,13 +774,18 @@ function App() {
|
|||||||
: getTeamDisplayName(rightTeam)
|
: getTeamDisplayName(rightTeam)
|
||||||
: null
|
: null
|
||||||
|
|
||||||
// 得分方接著發球,報分以發球方分數為先;左側隊伍的發球區需鏡像對應畫面。
|
// 得分方接著發球,報分以發球方分數為先;發球區一律用實際球場左右,不做鏡像。
|
||||||
const servingScore = side === 'left' ? nextScoreState.scoreLeft : nextScoreState.scoreRight
|
const servingScore = side === 'left' ? nextScoreState.scoreLeft : nextScoreState.scoreRight
|
||||||
const opponentScore = side === 'left' ? nextScoreState.scoreRight : nextScoreState.scoreLeft
|
const opponentScore = side === 'left' ? nextScoreState.scoreRight : nextScoreState.scoreLeft
|
||||||
const serverCourt =
|
const serverCourt = getServiceCourt(servingScore)
|
||||||
side === 'left'
|
// 只有發球方(剛得分那隊)再得 1 分就能贏,才算賽末點。
|
||||||
? getMirroredCourt(getServiceCourt(servingScore))
|
const matchPoint =
|
||||||
: getServiceCourt(servingScore)
|
!reachedTarget &&
|
||||||
|
hasWonGame(
|
||||||
|
side === 'left'
|
||||||
|
? { ...nextScoreState, scoreLeft: nextScoreState.scoreLeft + 1 }
|
||||||
|
: { ...nextScoreState, scoreRight: nextScoreState.scoreRight + 1 },
|
||||||
|
)
|
||||||
|
|
||||||
setScoreHistory((current) => [...current, { pointLog, scoreState }])
|
setScoreHistory((current) => [...current, { pointLog, scoreState }])
|
||||||
setPointLog(nextPointLog)
|
setPointLog(nextPointLog)
|
||||||
@@ -790,6 +796,7 @@ function App() {
|
|||||||
opponentScore,
|
opponentScore,
|
||||||
serverName: getNextServerName(nextScoreState, leftTeam, rightTeam, side),
|
serverName: getNextServerName(nextScoreState, leftTeam, rightTeam, side),
|
||||||
serverCourt,
|
serverCourt,
|
||||||
|
matchPoint,
|
||||||
winnerTeamName,
|
winnerTeamName,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
getCourtAssignments,
|
getCourtAssignments,
|
||||||
getMirroredCourt,
|
|
||||||
getReceivingPlayer,
|
getReceivingPlayer,
|
||||||
getServiceCourt,
|
getServiceCourt,
|
||||||
getServingPlayer,
|
getServingPlayer,
|
||||||
@@ -64,6 +63,7 @@ type ScoreboardPageProps = {
|
|||||||
opponentScore: number
|
opponentScore: number
|
||||||
serverName: string
|
serverName: string
|
||||||
serverCourt: 'left' | 'right'
|
serverCourt: 'left' | 'right'
|
||||||
|
matchPoint: boolean
|
||||||
winnerTeamName: string | null
|
winnerTeamName: string | null
|
||||||
} | null
|
} | null
|
||||||
targetDate: string
|
targetDate: string
|
||||||
@@ -260,7 +260,11 @@ export function ScoreboardPage({
|
|||||||
const parts: string[] = []
|
const parts: string[] = []
|
||||||
|
|
||||||
if (voiceSettings.announceScore) {
|
if (voiceSettings.announceScore) {
|
||||||
parts.push(`${voiceAnnouncement.servingScore}比${voiceAnnouncement.opponentScore}`)
|
parts.push(
|
||||||
|
`${voiceAnnouncement.servingScore}比${voiceAnnouncement.opponentScore}${
|
||||||
|
voiceAnnouncement.matchPoint ? ' 賽末點' : ''
|
||||||
|
}`,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (voiceSettings.announceServer && voiceAnnouncement.serverName) {
|
if (voiceSettings.announceServer && voiceAnnouncement.serverName) {
|
||||||
@@ -484,11 +488,7 @@ export function ScoreboardPage({
|
|||||||
onSwapPlayers={() => onSwapTeamPlayers('left')}
|
onSwapPlayers={() => onSwapTeamPlayers('left')}
|
||||||
onSwapTeams={onSwapMatchup}
|
onSwapTeams={onSwapMatchup}
|
||||||
score={scoreState.scoreLeft}
|
score={scoreState.scoreLeft}
|
||||||
serviceCourt={
|
serviceCourt={scoreState.serving === 'left' ? servingCourt : null}
|
||||||
scoreState.serving === 'left' && servingCourt
|
|
||||||
? getMirroredCourt(servingCourt)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
showServingPrompt={scoreState.serving === null}
|
showServingPrompt={scoreState.serving === null}
|
||||||
team={leftTeam}
|
team={leftTeam}
|
||||||
teamSlot="top"
|
teamSlot="top"
|
||||||
|
|||||||
Reference in New Issue
Block a user