diff --git a/game/石头剪刀布/game.html b/game/石头剪刀布/game.html
index ef722c6..146de16 100644
--- a/game/石头剪刀布/game.html
+++ b/game/石头剪刀布/game.html
@@ -137,6 +137,36 @@
z-index: 3;
}
+ /* --- Start: Countdown specific styles --- */
+ .countdown-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.85); /* Slightly darker for better contrast */
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 8rem; /* Large font for countdown */
+ font-weight: bold;
+ color: #00d4ff;
+ text-shadow: 0 0 30px rgba(0, 212, 255, 0.8);
+ z-index: 5; /* Above video/canvas but below status bar if needed, adjusted based on existing z-index structure */
+ border-radius: 15px;
+ opacity: 0;
+ transition: opacity 0.3s ease-in-out;
+ pointer-events: none; /* Allow interaction with elements behind it when not visible */
+ }
+
+ .countdown-overlay.show {
+ opacity: 1;
+ /* When visible, it takes pointer events to block interaction with video elements */
+ pointer-events: auto;
+ }
+ /* --- End: Countdown specific styles --- */
+
+
/* Control Panel */
.control-panel {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
@@ -354,6 +384,9 @@
@@ -422,6 +455,9 @@
const resetBtn = document.getElementById('resetBtn');
const importModelBtn = document.getElementById('importModelBtn');
const fileImporter = document.getElementById('fileImporter');
+ // START: Add Countdown Overlay Element
+ const countdownOverlay = document.getElementById('countdownOverlay');
+ // END: Add Countdown Overlay Element
let detector;
let classifier;
@@ -433,6 +469,9 @@
let currentRound = 0;
let lastPrediction = null;
let predictionCooldown = false;
+ // START: Add countdown state variable
+ let isCountingDown = false;
+ // END: Add countdown state variable
// 手势映射
const gestureMap = {
@@ -575,7 +614,10 @@
if (hands && hands.length > 0) {
drawHand(hands[0]);
- if (isModelLoaded && isPlaying && !predictionCooldown) {
+ // START: Modify prediction condition to include isCountingDown
+ // Only make predictions if game is playing AND not in cooldown AND NOT counting down
+ if (isModelLoaded && isPlaying && !predictionCooldown && !isCountingDown) {
+ // END: Modify prediction condition to include isCountingDown
const handTensor = flattenHand(hands[0]);
if (classifier.getNumClasses() > 0) {
@@ -587,12 +629,12 @@
const predictedGesture = gestureMap[prediction.label];
if (predictedGesture && prediction.label !== lastPrediction) {
lastPrediction = prediction.label;
- playRound(predictedGesture);
+ // ORIGINAL playRound call
+ playRound(predictedGesture);
predictionCooldown = true;
- setTimeout(() => {
- predictionCooldown = false;
- lastPrediction = null;
- }, 2000);
+ // START: Initiate countdown AFTER a round is played
+ startCountdownForNextRound();
+ // END: Initiate countdown AFTER a round is played
}
}
} else {
@@ -653,8 +695,8 @@
// 游戏逻辑
function playRound(userGesture) {
- currentRound++;
-
+ currentRound++; // IMPORTANT: Restore this line
+
// AI 随机选择
const aiOptions = Object.values(gestureMap);
const aiGesture = aiOptions[Math.floor(Math.random() * aiOptions.length)];
@@ -692,21 +734,69 @@
resultDisplay.innerHTML = `${result}
`;
}
- // 开始游戏
+ // START: New function for countdown before next round
+ function startCountdownForNextRound() {
+ if (!isPlaying) return; // Only run if game is active
+
+ isCountingDown = true; // Disable hand detection during countdown
+ countdownOverlay.textContent = ''; // Clear previous text
+ countdownOverlay.classList.add('show');
+ updateStatus('下一回合准备中...');
+
+ let count = 3;
+ const countdownInterval = setInterval(() => {
+ if (count > 0) {
+ countdownOverlay.textContent = count;
+ count--;
+ } else {
+ clearInterval(countdownInterval);
+ countdownOverlay.classList.remove('show');
+ countdownOverlay.textContent = ''; // Clear "GO!" text immediately
+ isCountingDown = false; // Enable hand detection again
+ predictionCooldown = false; // Allow new predictions
+ lastPrediction = null; // Reset last prediction to allow new gesture
+ updateStatus('游戏进行中 - 请做出手势');
+
+ // Clear previous choices and results for the new round
+ userChoiceDisplay.textContent = '-';
+ aiChoiceDisplay.textContent = '-';
+ resultDisplay.innerHTML = '';
+ choicesDisplay.style.display = 'flex'; // Ensure choices are visible for new round
+ }
+ }, 1000);
+ }
+ // END: New function for countdown
+
+ // 开始游戏 (Modified to initiate first round countdown)
function startGame() {
isPlaying = true;
- currentRound = 0;
- roundInfo.textContent = '游戏进行中...';
- choicesDisplay.style.display = 'none';
+ currentRound = 0; // Initialize to 0, playRound will increment it to 1 for the first round.
+
+ // Clear choices and results display immediately when game starts
+ userChoiceDisplay.textContent = '-';
+ aiChoiceDisplay.textContent = '-';
resultDisplay.innerHTML = '';
+ choicesDisplay.style.display = 'flex'; // Ensure choices are visible when game starts
+
startBtn.textContent = '游戏中...';
startBtn.disabled = true;
- updateStatus('游戏进行中 - 请做出手势');
+ resetBtn.disabled = false; // Enable reset once game starts
+ importModelBtn.disabled = true; // Disable import once game starts
+
+ // Start the very first countdown for the first round
+ startCountdownForNextRound();
+ // Note: statusDisplay will be updated by startCountdownForNextRound
}
- // 重置游戏
+ // 重置游戏 (Modified to handle countdown state cleanup)
function resetGame() {
isPlaying = false;
+ // START: Clean up countdown state on reset
+ isCountingDown = false;
+ countdownOverlay.classList.remove('show');
+ countdownOverlay.textContent = '';
+ // END: Clean up countdown state on reset
+
scores = { user: 0, ai: 0 };
currentRound = 0;
userScoreDisplay.textContent = '0';
@@ -716,6 +806,8 @@
resultDisplay.innerHTML = '';
startBtn.textContent = '开始游戏';
startBtn.disabled = !isModelLoaded;
+ resetBtn.disabled = false; // Already enabled, just ensuring
+ importModelBtn.disabled = false; // Enable import button again
predictionCooldown = false;
lastPrediction = null;
updateStatus(isModelLoaded ? '准备就绪' : '请导入模型');
@@ -765,4 +857,4 @@
});