google music temp file

本文介绍了Google Chrome浏览器中缓存文件的默认存储路径。此路径位于用户的本地设置文件夹内,具体为C盘下Documents and Settings目录中的Default文件夹。对于理解Chrome如何管理和存储网页缓存数据具有一定参考价值。
C:\Documents and Settings\default Name\Local Settings\Application Data\Google\Chrome\User Data\Default\Cache
import datetime import cv2 import numpy as np import random from collections import deque import mediapipe as mp import json import os import platform import time import threading from queue import Queue from PIL import Image, ImageDraw, ImageFont import pygame.mixer # ------------------------------ # 全局队列与事件 # ------------------------------ frame_queue = Queue(maxsize=1) result_queue = Queue(maxsize=1) stop_event = threading.Event() # ------------------------------ # 动态背景视频支持(优化版) # ------------------------------ BG_VIDEO_PATH = "menu_bg.mp4" bg_frames = [] # 预加载的帧列表 bg_lock = threading.Lock() # 帧访问锁 bg_stop_event = threading.Event() # 控制后台线程退出 # ------------------------------ # 初始化 Mediapipe Hands # ------------------------------ mp_hands = mp.solutions.hands mp_draw = mp.solutions.drawing_utils hands = mp_hands.Hands( static_image_mode=False, max_num_hands=2, min_detection_confidence=0.7, min_tracking_confidence=0.5 ) # ------------------------------ # 中文字体加载 # ------------------------------ def get_chinese_font(): system = platform.system() font_paths = { "Windows": ["C:/Windows/Fonts/simhei.ttf", "C:/Windows/Fonts/msyh.ttc"], "Darwin": ["/System/Library/Fonts/PingFang.ttc"], "Linux": [ "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc" ] } for path in font_paths.get(system, []): if os.path.exists(path): try: return ImageFont.truetype(path, 32) except Exception as e: print(f"⚠️ 字体加载失败: {path}, 错误: {e}") return None try: CHINESE_FONT = get_chinese_font() except ImportError: print("警告: 未安装Pillow,中文可能无法正常显示。请运行: pip install pillow") CHINESE_FONT = None def put_chinese_text(image, text, position=None, color=(255, 255, 255), font_size=30, center_region=None): if CHINESE_FONT is None: if position: cv2.putText(image, text, position, cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2) return image try: pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_img) try: if hasattr(CHINESE_FONT, 'path'): font = ImageFont.truetype(CHINESE_FONT.path, font_size) else: font = ImageFont.load_default() except: font = ImageFont.load_default() bbox = draw.textbbox((0, 0), text, font=font) tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] if center_region: x1, y1, x2, y2 = center_region fx = x1 + (x2 - x1 - tw) // 2 fy = y1 + (y2 - y1 - th) // 2 elif position: fx, fy = position else: fx = fy = 0 draw.text((fx, fy), text, fill=tuple(color), font=font) return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) except Exception as e: print("中文绘制失败:", e) if position: cv2.putText(image, text, position, cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2) return image # ------------------------------ # 音频系统(pygame.mixer) # ------------------------------ pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=512) _sound_cache = {} _volume = 0.5 _muted = False def _load_sound(file): if file in _sound_cache: return _sound_cache[file] if os.path.exists(file): try: sound = pygame.mixer.Sound(file) sound.set_volume(_volume) _sound_cache[file] = sound return sound except Exception as e: print(f"❌ 加载音效失败: {file}, 错误: {e}") else: print(f"⚠️ 音效文件未找到: {file}") return None def play_sound(sound_file): if not _muted: sound = _load_sound(sound_file) if sound: sound.play() def play_bgm(bgm_file, loop=-1): if _muted or not os.path.exists(bgm_file): return try: pygame.mixer.music.load(bgm_file) pygame.mixer.music.set_volume(_volume) pygame.mixer.music.play(loop) except Exception as e: print(f"❌ 播放 BGM 失败: {e}") def stop_bgm(): pygame.mixer.music.stop() def toggle_mute(): global _muted _muted = not _muted vol = 0.0 if _muted else _volume pygame.mixer.music.set_volume(vol) for s in _sound_cache.values(): if s: s.set_volume(vol) return _muted # ------------------------------ # 排行榜管理 # ------------------------------ RANKING_FILE = "snake_ranking.json" MAX_RECORDS = 100 def load_ranking(): if not os.path.exists(RANKING_FILE): return [] try: with open(RANKING_FILE, 'r', encoding='utf-8') as f: data = json.load(f) seen = set() unique_data = [] for item in data: key = (item.get('score', 0), item.get('timestamp', '')) if key not in seen: seen.add(key) unique_data.append(item) return sorted(unique_data, key=lambda x: x['score'], reverse=True)[:MAX_RECORDS] except Exception as e: print("加载排行榜失败:", e) return [] def save_best_score(score, mode="single"): ranking = load_ranking() current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") ranking.append({"score": score, "timestamp": current_time, "mode": mode}) seen = set() unique_ranking = [] for r in ranking: key = (r['score'], r['timestamp']) if key not in seen: seen.add(key) unique_ranking.append(r) unique_ranking = sorted(unique_ranking, key=lambda x: x['score'], reverse=True)[:MAX_RECORDS] try: with open(RANKING_FILE, 'w', encoding='utf-8') as f: json.dump(unique_ranking, f, indent=2, ensure_ascii=False) except Exception as e: print("保存失败:", e) def show_ranking(): ranking = load_ranking() frame = np.zeros((720, 1280, 3), dtype=np.uint8) h, w = frame.shape[:2] for y in range(h): c = 30 + y // 20 frame[y, :] = [c // 2, c // 3, c] frame = put_chinese_text(frame, "🏆 历史排行榜 🏆", center_region=(0, 40, w, 120), color=(255, 255, 100), font_size=60) frame = put_chinese_text(frame, "按任意键返回主菜单", center_region=(0, h - 80, w, h), color=(200, 200, 255), font_size=30) if not ranking: frame = put_chinese_text(frame, "暂无记录", center_region=(0, h // 2 - 20, w, h // 2 + 20), color=(150, 150, 150), font_size=40) else: start_y = 140 for i, record in enumerate(ranking[:50]): score = record['score'] timestamp = record['timestamp'] mode = record.get('mode', 'unknown') mode_text = "单人" if mode == "single" else "双人" if mode == "dual" else "未知" text = f"{i + 1:2d}. {score:4d} 分 — {timestamp} [{mode_text}]" color = (255, 255, 255) if i % 2 == 0 else (220, 220, 220) frame = put_chinese_text(frame, text, (w // 2 - 480, start_y + i * 32), color=color, font_size=28) cv2.imshow("Hand-Controlled Snake Game", frame) cv2.waitKey(0) def clear_ranking(): frame = np.zeros((720, 1280, 3), dtype=np.uint8) h, w = frame.shape[:2] for y in range(h): frame[y, :] = [20 + y // 20, (20 + y // 20) // 2, 60] frame = put_chinese_text(frame, "⚠️ 清空所有记录?", center_region=(0, h // 2 - 100, w, h // 2 - 40), color=(0, 0, 255), font_size=48) frame = put_chinese_text(frame, "确定要清空吗?(Y=是, N=否)", center_region=(0, h // 2 - 20, w, h // 2 + 20), color=(255, 255, 255), font_size=36) frame = put_chinese_text(frame, "此操作不可撤销!", center_region=(0, h // 2 + 40, w, h // 2 + 80), color=(150, 150, 150), font_size=32) cv2.imshow("Hand-Controlled Snake Game", frame) while True: key = cv2.waitKey(1) & 0xFF if key in (ord('y'), ord('Y')): try: os.remove(RANKING_FILE) except: pass return True elif key in (ord('n'), ord('N'), 27): return False # ------------------------------ # 动态背景视频相关函数(✅ 终极流畅版) # ------------------------------ def load_background_video(): """启动后台线程预加载并循环读取视频帧""" global bg_frames if not os.path.exists(BG_VIDEO_PATH): print(f"❌ 背景视频未找到: {BG_VIDEO_PATH}") return def preload_and_cache(): cap = cv2.VideoCapture(BG_VIDEO_PATH) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) cap.set(cv2.CAP_PROP_FPS, 30) if hasattr(cv2, 'CAP_PROP_HW_ACCELERATION'): try: cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY) except: pass frame_cache = [] # 🔁 尽可能多地预加载帧(最多300帧 ≈ 10秒) while len(frame_cache) < 300: ret, frame = cap.read() if not ret: break resized = cv2.resize(frame, (1280, 720), interpolation=cv2.INTER_AREA) frame_cache.append(resized) if not frame_cache: print("❌ 无法解码任何背景帧") return print(f"✅ 成功预加载 {len(frame_cache)} 帧背景画面") # 🔁 后台无限循环更新全局帧 while not bg_stop_event.is_set(): for frame in frame_cache: with bg_lock: if len(bg_frames) > 0: bg_frames[0] = frame.copy() # 更新第一帧 else: bg_frames.append(frame.copy()) time.sleep(1 / 30) # 模拟 ~30 FPS 输出节奏 if bg_stop_event.is_set(): break cap.release() # 🧵 启动预加载线程 thread = threading.Thread(target=preload_and_cache, daemon=True) thread.start() def get_background_frame(): """从内存中快速获取当前背景帧""" with bg_lock: if bg_frames: return bg_frames[0].copy() # 返回副本避免绘图冲突 return None # 降级为纯色背景 # ------------------------------ # 主菜单界面(带动态视频背景) # ------------------------------ def show_main_menu(): global bg_frames if len(bg_frames) == 0: load_background_video() play_bgm("bgm.mp3") ranking = load_ranking() best_score = ranking[0]['score'] if ranking else 0 width, height = 1280, 720 btn_w, btn_h = 300, 80 cx = width // 2 btn_y_start = 220 spacing = 80 while True: bg_frame = get_background_frame() if bg_frame is not None: frame = bg_frame.copy() frame = cv2.GaussianBlur(frame, (5, 5), 0) frame = cv2.addWeighted(frame, 0.7, np.zeros_like(frame), 0, 30) else: frame = np.zeros((height, width, 3), dtype=np.uint8) for y in range(height): c = 20 + y // 20 frame[y, :] = [c, c // 2, 60] frame = put_chinese_text(frame, "🐍 手势贪吃蛇游戏 🐍", center_region=(0, 0, width, 120), color=(255, 255, 100), font_size=60) buttons = [ ("👤 单人模式", btn_y_start, (100, 0, 200), (140, 0, 240)), ("👥 双人对战", btn_y_start + spacing, (180, 0, 180), (220, 0, 220)), ("📊 查看排行榜", btn_y_start + 2 * spacing, (0, 100, 200), (0, 180, 255)), ("🗑️ 清空记录", btn_y_start + 3 * spacing, (60, 60, 60), (150, 150, 150)), ] for label, y, bg_color, border_color in buttons: left = cx - btn_w // 2 right = cx + btn_w // 2 top = y bottom = y + btn_h cv2.rectangle(frame, (left, top), (right, bottom), bg_color, -1) cv2.rectangle(frame, (left, top), (right, bottom), border_color, 5) frame = put_chinese_text(frame, label, center_region=(left, top, right, bottom), color=(255, 255, 255), font_size=36) tip_text = f"🏆 最高分: {best_score}|1=单人 2=双人 3=退出 4=清空 5=排行 M=静音" frame = put_chinese_text(frame, tip_text, center_region=(0, 600, width, 640), color=(200, 255, 255), font_size=24) cv2.imshow("Hand-Controlled Snake Game", frame) start_t = time.time() while time.time() - start_t < 0.1: key = cv2.waitKey(1) & 0xFF if key == ord('1'): return "single" elif key == ord('2'): return "dual" elif key == ord('3'): return "quit" elif key == ord('4'): clear_ranking() break elif key == ord('5'): show_ranking() break elif key == ord('m'): is_muted = toggle_mute() status = "🔇 已静音" if is_muted else "🔊 音效开启" help_frame = frame.copy() help_frame = put_chinese_text(help_frame, status, center_region=(0, 650, width, 690), color=(255, 255, 0), font_size=24) cv2.imshow("Hand-Controlled Snake Game", help_frame) cv2.waitKey(800) break elif key != 255: help_frame = frame.copy() help_frame = put_chinese_text(help_frame, "💡 提示: 1=单人 2=双人 3=退出 4=清空 5=排行 M=静音", center_region=(0, 650, width, 690), color=(255, 255, 0), font_size=24) cv2.imshow("Hand-Controlled Snake Game", help_frame) cv2.waitKey(1500) break # ------------------------------ # 摄像头读取线程 # ------------------------------ def capture_thread(): cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) while not stop_event.is_set(): ret, frame = cap.read() if ret: frame = cv2.flip(frame, 1) if not frame_queue.empty(): try: frame_queue.get_nowait() except: pass frame_queue.put(frame) else: time.sleep(0.01) cap.release() # ------------------------------ # 手势识别线程 # ------------------------------ def hand_thread(): while not stop_event.is_set(): if not frame_queue.empty(): frame = frame_queue.get() rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(rgb_frame) if not result_queue.empty(): try: result_queue.get_nowait() except: pass result_queue.put((frame.copy(), results)) else: time.sleep(0.01) # ------------------------------ # 启动后台线程 # ------------------------------ capture_t = threading.Thread(target=capture_thread, daemon=True) hand_t = threading.Thread(target=hand_thread, daemon=True) capture_t.start() hand_t.start() # ------------------------------ # 游戏参数 # ------------------------------ width, height = 1280, 720 snake_speed = 8 food_radius = 15 food_color = (0, 255, 0) # ------------------------------ # 安全工具函数 # ------------------------------ def is_point_in_wall(x, y, walls): return any(wx <= x <= wx + ww and wy <= y <= wy + wh for (wx, wy, ww, wh) in walls) def check_wall_collision(head, walls): hx, hy = head return any(wx <= hx <= wx + ww and wy <= hy <= wy + wh for (wx, wy, ww, wh) in walls) def generate_safe_food_position(snake_bodies, walls, retries=100): all_segments = [] for body in (snake_bodies if isinstance(snake_bodies, list) else [snake_bodies]): all_segments.extend(list(body)) for _ in range(retries): x = random.randint(50, width - 50) y = random.randint(50, height - 50) pos = np.array([x, y]) if is_point_in_wall(x, y, walls): continue too_close = False for seg in all_segments: if np.linalg.norm(pos - np.array(seg)) < 30: too_close = True break if too_close: continue return [int(x), int(y)] fallback_positions = [(width - 60, height - 60), (60, height - 60), (width - 60, 60), (60, 60)] for fx, fy in fallback_positions: pos = np.array([fx, fy]) if not is_point_in_wall(fx, fy, walls): safe = True for seg in all_segments: if np.linalg.norm(pos - np.array(seg)) < 30: safe = False break if safe: return [fx, fy] return [width // 2, height // 2] def add_wall_safely(walls_list, snake_bodies, food_pos): if len(walls_list) >= 5: return walls_list all_snakes = [] for body in (snake_bodies if isinstance(snake_bodies, list) else [snake_bodies]): all_snakes.extend(list(body)) for _ in range(30): ww, wh = random.randint(40, 150), random.randint(40, 150) wx, wy = random.randint(50, width - ww - 50), random.randint(50, height - wh - 50) new_wall = (wx, wy, ww, wh) temp_walls = walls_list + [new_wall] if not is_point_in_wall(all_snakes[0][0], all_snakes[0][1], temp_walls) and \ not is_point_in_wall(food_pos[0], food_pos[1], temp_walls): walls_list.append(new_wall) break return walls_list # ------------------------------ # 绘图封装 # ------------------------------ def draw_game_elements(frame, snakes, food, walls, scores, game_over, right_hand_pos=None, left_hand_pos=None): try: for wall in walls: wx, wy, ww, wh = map(int, wall) cv2.rectangle(frame, (wx, wy), (wx + ww, wy + wh), (255, 255, 0), -1) cv2.rectangle(frame, (wx, wy), (wx + ww, wy + wh), (0, 0, 0), 3) fx, fy = map(int, food) if 0 <= fx < width and 0 <= fy < height: cv2.circle(frame, (fx, fy), food_radius, food_color, -1) s1, s2 = snakes sc1, sc2 = scores for i in range(1, len(s1)): p1, p2 = s1[i - 1], s1[i] if all(0 <= v < 10000 for v in (*p1, *p2)): cv2.line(frame, p1, p2, (0, 0, 200), 8) cv2.circle(frame, s1[0], 10, (255, 255, 255), -1) cv2.circle(frame, s1[0], 8, (0, 0, 255), -1) if len(s2) > 0: for i in range(1, len(s2)): p1, p2 = s2[i - 1], s2[i] if all(0 <= v < 10000 for v in (*p1, *p2)): cv2.line(frame, p1, p2, (200, 0, 0), 8) cv2.circle(frame, s2[0], 10, (255, 255, 255), -1) cv2.circle(frame, s2[0], 8, (255, 0, 0), -1) frame = put_chinese_text(frame, f"🔴红蛇得分: {sc1}", (20, 15), (255, 255, 255), 40) if sc2 > 0: frame = put_chinese_text(frame, f"🔵蓝蛇得分: {sc2}", (20, 60), (255, 255, 255), 40) if right_hand_pos and all(0 <= v < width for v in right_hand_pos): cv2.circle(frame, tuple(map(int, right_hand_pos)), 12, (0, 0, 255), -1) cv2.putText(frame, "R", (right_hand_pos[0] - 10, right_hand_pos[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2) if left_hand_pos and all(0 <= v < width for v in left_hand_pos): cv2.circle(frame, tuple(map(int, left_hand_pos)), 12, (255, 0, 0), -1) cv2.putText(frame, "L", (left_hand_pos[0] - 10, left_hand_pos[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) except Exception as e: print("绘图异常:", e) def show_game_over_screen_dual(score1, score2): overlay = np.zeros((height, width, 3), dtype=np.uint8) cv2.rectangle(overlay, (width // 4, height // 4), (3 * width // 4, 3 * height // 4), (0, 0, 0), -1) overlay = put_chinese_text(overlay, "游戏结束", center_region=(0, height // 2 - 80, width, height // 2 - 20), color=(0, 0, 255), font_size=60) overlay = put_chinese_text(overlay, f"红蛇得分: {score1}", center_region=(0, height // 2, width, height // 2 + 40), color=(0, 0, 255), font_size=32) overlay = put_chinese_text(overlay, f"蓝蛇得分: {score2}", center_region=(0, height // 2 + 40, width, height // 2 + 80), color=(255, 0, 0), font_size=32) cv2.imshow("Hand-Controlled Snake Game", overlay) play_sound("game_over.wav") save_best_score(max(score1, score2), mode="dual") cv2.waitKey(800) def show_game_over_screen_single(score): overlay = np.zeros((height, width, 3), dtype=np.uint8) cv2.rectangle(overlay, (width // 4, height // 4), (3 * width // 4, 3 * height // 4), (0, 0, 0), -1) overlay = put_chinese_text(overlay, "游戏结束", center_region=(0, height // 2 - 60, width, height // 2 - 20), color=(0, 255, 0), font_size=60) overlay = put_chinese_text(overlay, f"你的得分: {score}", center_region=(0, height // 2, width, height // 2 + 40), color=(255, 255, 255), font_size=40) cv2.imshow("Hand-Controlled Snake Game", overlay) play_sound("game_over.wav") save_best_score(score, mode="single") cv2.waitKey(800) # ------------------------------ # 单人游戏循环 # ------------------------------ def run_single_player(): snake = deque([(width // 2, height // 2)]) direction = np.array([1.0, 0.0]) base_length = 3 score = 0 walls = [] food = generate_safe_food_position(snake, walls) target_pos = None game_over = False while not game_over: if not result_queue.empty(): frame, results = result_queue.get() key = cv2.waitKey(1) & 0xFF curr_target = None try: if results.multi_hand_landmarks and results.multi_handedness: for idx, hand_landmarks in enumerate(results.multi_hand_landmarks): label = results.multi_handedness[idx].classification[0].label if label == "Right": x = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * width) y = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * height) curr_target = (x, y) mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS) if curr_target: target_pos = curr_target if target_pos is None else ( int(0.3 * curr_target[0] + 0.7 * target_pos[0]), int(0.3 * curr_target[1] + 0.7 * target_pos[1]) ) if target_pos: head = np.array(snake[0]) to_target = np.array(target_pos) - head dist = np.linalg.norm(to_target) if dist > 30: desired_dir = to_target / (dist + 1e-8) current_dir = direction / (np.linalg.norm(direction) + 1e-8) dot = np.clip(np.dot(current_dir, desired_dir), -1, 1) angle = np.arccos(dot) if angle > 0.25: w1, w2 = np.sin(angle - 0.25), np.sin(0.25) blended = (w1 * current_dir + w2 * desired_dir) / (np.sin(angle) + 1e-8) direction = blended / (np.linalg.norm(blended) + 1e-8) else: direction = desired_dir new_head = head + direction * snake_speed snake.appendleft(tuple(np.round(new_head).astype(int))) h = np.array(snake[0]) if h[0] <= 0 or h[0] >= width or h[1] <= 0 or h[1] >= height or check_wall_collision(h, walls): game_over = True for i in range(4, len(snake)): if np.linalg.norm(h - np.array(snake[i])) < 15: game_over = True break if np.linalg.norm(h - np.array(food)) < (food_radius + 10): score += 1 food = generate_safe_food_position(snake, walls) play_sound("eat.wav") if score % 5 == 0: walls = add_wall_safely(walls, snake, food) target_len = base_length + score while len(snake) > target_len: snake.pop() draw_game_elements(frame, [snake, deque()], food, walls, (score, 0), game_over, right_hand_pos=target_pos, left_hand_pos=None) cv2.imshow("Hand-Controlled Snake Game", frame) if game_over: show_game_over_screen_single(score) break if key == 27: break except Exception as e: print("单人模式异常:", e) time.sleep(0.1) else: time.sleep(0.01) # ------------------------------ # 主游戏循环 # ------------------------------ while True: action = show_main_menu() if action == "quit": break elif action == "single": run_single_player() elif action == "dual": snake1 = deque([(width // 3, height // 2)]) dir1 = np.array([1.0, 0.0]) len1 = 3 snake2 = deque([(2 * width // 3, height // 2)]) dir2 = np.array([-1.0, 0.0]) len2 = 3 score1, score2 = 0, 0 walls = [] food = generate_safe_food_position([*snake1, *snake2], walls) game_over = False target_right = None target_left = None while not game_over: if not result_queue.empty(): frame, results = result_queue.get() key = cv2.waitKey(1) & 0xFF curr_right = None curr_left = None try: if results and results.multi_hand_landmarks and results.multi_handedness: hands_info = [] for idx, hand_landmarks in enumerate(results.multi_hand_landmarks): wrist_x = hand_landmarks.landmark[mp_hands.HandLandmark.WRIST].x x = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * width) y = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * height) hands_info.append((wrist_x, x, y, hand_landmarks)) hands_info.sort(key=lambda x: x[0], reverse=True) for i, (_, x, y, landmarks) in enumerate(hands_info): mp_draw.draw_landmarks(frame, landmarks, mp_hands.HAND_CONNECTIONS) if i == 0: curr_right = (x, y) if i == 1: curr_left = (x, y) if curr_right: target_right = curr_right if target_right is None else ( int(0.3 * curr_right[0] + 0.7 * target_right[0]), int(0.3 * curr_right[1] + 0.7 * target_right[1])) if curr_left: target_left = curr_left if target_left is None else ( int(0.3 * curr_left[0] + 0.7 * target_left[0]), int(0.3 * curr_left[1] + 0.7 * target_left[1])) if target_right: head1 = np.array(snake1[0]) to_t = np.array(target_right) - head1 dist = np.linalg.norm(to_t) if dist > 30: desired = to_t / (dist + 1e-8) curr_dir = dir1 / (np.linalg.norm(dir1) + 1e-8) dot = np.clip(np.dot(curr_dir, desired), -1, 1) angle = np.arccos(dot) if angle > 0.25: w1, w2 = np.sin(angle - 0.25), np.sin(0.25) blended = (w1 * curr_dir + w2 * desired) / (np.sin(angle) + 1e-8) dir1 = blended / (np.linalg.norm(blended) + 1e-8) else: dir1 = desired new_head1 = head1 + dir1 * snake_speed snake1.appendleft(tuple(np.round(new_head1).astype(int))) if target_left: head2 = np.array(snake2[0]) to_t = np.array(target_left) - head2 dist = np.linalg.norm(to_t) if dist > 30: desired = to_t / (dist + 1e-8) curr_dir = dir2 / (np.linalg.norm(dir2) + 1e-8) dot = np.clip(np.dot(curr_dir, desired), -1, 1) angle = np.arccos(dot) if angle > 0.25: w1, w2 = np.sin(angle - 0.25), np.sin(0.25) blended = (w1 * curr_dir + w2 * desired) / (np.sin(angle) + 1e-8) dir2 = blended / (np.linalg.norm(blended) + 1e-8) else: dir2 = desired new_head2 = head2 + dir2 * snake_speed snake2.appendleft(tuple(np.round(new_head2).astype(int))) h1, h2 = np.array(snake1[0]), np.array(snake2[0]) if (h1[0] <= 0 or h1[0] >= width or h1[1] <= 0 or h1[1] >= height or check_wall_collision(h1, walls)): game_over = True for i in range(4, len(snake1)): if np.linalg.norm(h1 - np.array(snake1[i])) < 15: game_over = True break if (h2[0] <= 0 or h2[0] >= width or h2[1] <= 0 or h2[1] >= height or check_wall_collision(h2, walls)): game_over = True for i in range(4, len(snake2)): if np.linalg.norm(h2 - np.array(snake2[i])) < 15: game_over = True break eaten = False if np.linalg.norm(h1 - np.array(food)) < (food_radius + 10): score1 += 1 eaten = True if np.linalg.norm(h2 - np.array(food)) < (food_radius + 10): score2 += 1 eaten = True if eaten: play_sound("eat.wav") food = generate_safe_food_position([*snake1, *snake2], walls) if score1 % 5 == 0 or score2 % 5 == 0: walls = add_wall_safely(walls, [*snake1, *snake2], food) while len(snake1) > len1 + score1: snake1.pop() while len(snake2) > len2 + score2: snake2.pop() draw_game_elements(frame, [snake1, snake2], food, walls, (score1, score2), game_over, right_hand_pos=target_right, left_hand_pos=target_left) cv2.imshow("Hand-Controlled Snake Game", frame) if game_over: show_game_over_screen_dual(score1, score2) break if key == 27: break except Exception as e: print("双人模式异常:", e) time.sleep(0.1) else: time.sleep(0.01) # ------------------------------ # 释放资源 # ------------------------------ stop_event.set() bg_stop_event.set() # 停止背景线程 time.sleep(0.5) cv2.destroyAllWindows() hands.close() stop_bgm() pygame.mixer.quit()
最新发布
11-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值