您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
双人手动计分器,移动端虚拟按键
// ==UserScript== // @name PCOL-ASSIST // @author 葉月Hikaru // @match http://www.heyzxz.me/pcol/* // @version 7.6 // @namespace https://greasyfork.org/users/your-id // @description 双人手动计分器,移动端虚拟按键 // ==/UserScript== (function() { 'use strict'; const keysConfig = [ { key: '+', text: '-', top: 30, left: 40 }, { key: 'w', text: 'W', top: 30, left: 50 }, { key: '-', text: '+', top: 30, left: 60 }, { key: 'space', text: 'SPACE', top: 30, left: 70 }, { key: 'x', text: 'X', top: 30, left: 80 }, { key: 'c', text: 'C', top: 30, left: 90 }, { key: 'p', text: 'P', top: 120, left: 90 }, { key: 'a', text: 'A', top: 120, left: 30 }, { key: 's', text: 'S', top: 120, left: 50 }, { key: 'd', text: 'D', top: 120, left: 70 }, { key: 'meta', text: 'Cmd', top: 120, left: 80 } ]; const originalButtons = []; let areButtonsVisible = true; let isScoreboardVisible = true; let scores = { player1: 0, player2: 0 }; let buttonCooldowns = {}; let minusCooldowns = {}; let longPressTimer = null; const LONG_PRESS_DELAY = 500; const scoreColors = { 1: 'rgba(255, 0, 0, 0.6)', 2: 'rgba(255, 255, 0, 0.6)', 3: 'rgba(0, 255, 0, 0.6)', 4: 'rgba(139, 69, 19, 0.6)', 5: 'rgba(0, 0, 255, 0.6)', 6: 'rgba(255, 192, 203, 0.6)', 7: 'rgba(0, 0, 0, 0.6)' }; let currentPlayer = 'player1'; function createVirtualKey(keyConfig) { const btn = document.createElement('button'); btn.id = `pcol-assist-${keyConfig.key}-btn`; btn.textContent = keyConfig.text; btn.style.cssText = ` position: fixed; top: ${keyConfig.top}px; left: ${keyConfig.left}%; transform: ${keyConfig.left === 50 ? 'translateX(-50%)' : 'translateX(0)'}; width: 60px; height: 60px; font-size: ${keyConfig.text === 'SPACE' ? '16px' : '28px'}; background-color: rgba(255, 165, 0, 0.9); color: white; border: 2px solid white; border-radius: 50%; cursor: pointer; z-index: 9999; transition: all 0.1s ease; `; function setPressedState(isPressed) { if (isPressed) { btn.style.backgroundColor = 'rgba(255, 140, 0, 0.7)'; btn.style.transform = `${keyConfig.left === 50 ? 'translateX(-50%)' : 'translateX(0)'} scale(0.9)`; btn.style.borderColor = '#ffd700'; } else { btn.style.backgroundColor = 'rgba(255, 165, 0, 0.9)'; btn.style.transform = `${keyConfig.left === 50 ? 'translateX(-50%)' : 'translateX(0)'}`; btn.style.borderColor = 'white'; } } function triggerEvent(type, keyInfo = {}) { if (keyConfig.key === '+' || keyConfig.key === '-') { const wheelEvent = new WheelEvent('wheel', { deltaY: keyConfig.key === '+' ? -300 : 300, bubbles: true, cancelable: true }); document.querySelector('canvas')?.dispatchEvent(wheelEvent) || document.dispatchEvent(wheelEvent); } else { const eventKey = keyInfo.key || ( keyConfig.key === 'space' ? ' ' : keyConfig.key === 'meta' ? 'Meta' : keyConfig.key ); const eventCode = keyInfo.code || ( keyConfig.key === 'space' ? 'Space' : keyConfig.key === 'meta' ? 'MetaLeft' : `Key${keyConfig.key.toUpperCase()}` ); const eventKeyCode = keyInfo.keyCode || ( keyConfig.key === 'w' ? 87 : keyConfig.key === 'a' ? 65 : keyConfig.key === 's' ? 83 : keyConfig.key === 'd' ? 68 : keyConfig.key === 'x' ? 88 : keyConfig.key === 'c' ? 67 : keyConfig.key === 'p' ? 80 : keyConfig.key === 'meta' ? 91 : 32 ); const event = new KeyboardEvent(type, { key: eventKey === ' ' ? 'Spacebar' : eventKey, code: eventCode, keyCode: eventKeyCode, metaKey: keyConfig.key === 'meta' && type === 'keydown', bubbles: true, cancelable: true }); document.querySelector('canvas')?.dispatchEvent(event) || document.dispatchEvent(event); } } ['touchstart', 'mousedown'].forEach(e => btn.addEventListener(e, e => { e.preventDefault(); setPressedState(true); triggerEvent('keydown'); })); ['touchend', 'mouseup', 'mouseleave', 'touchcancel'].forEach(e => btn.addEventListener(e, e => { e.preventDefault(); setPressedState(false); triggerEvent('keyup'); })); document.body.appendChild(btn); originalButtons.push(btn); } function createVisibilityToggle() { const toggle = document.createElement('button'); toggle.id = 'pcol-assist-visibility-toggle'; toggle.textContent = '按钮: 显示'; toggle.style.cssText = ` position: fixed; top: 60px; left: 20px; width: 100px; height: 40px; font-size: 16px; background-color: rgba(0, 128, 0, 0.9); color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 9999; `; toggle.addEventListener('click', () => { areButtonsVisible = !areButtonsVisible; originalButtons.forEach(btn => { btn.style.display = areButtonsVisible ? 'block' : 'none'; }); if (areButtonsVisible) { toggle.textContent = '按钮: 显示'; toggle.style.backgroundColor = 'rgba(0, 128, 0, 0.9)'; } else { toggle.textContent = '按钮: 隐藏'; toggle.style.backgroundColor = 'rgba(128, 128, 128, 0.9)'; } }); document.body.appendChild(toggle); } function createScoreboardToggle() { const toggle = document.createElement('button'); toggle.id = 'pcol-assist-scoreboard-toggle'; toggle.textContent = '记分板: 显示'; toggle.style.cssText = ` position: fixed; top: 60px; left: 140px; width: 100px; height: 40px; font-size: 16px; background-color: rgba(0, 128, 0, 0.9); color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 9999; `; toggle.addEventListener('click', () => { isScoreboardVisible = !isScoreboardVisible; const scoreboard = document.getElementById('pcol-assist-scoreboard'); scoreboard.style.display = isScoreboardVisible ? 'flex' : 'none'; if (isScoreboardVisible) { toggle.textContent = '记分板: 显示'; toggle.style.backgroundColor = 'rgba(0, 128, 0, 0.9)'; } else { toggle.textContent = '记分板: 隐藏'; toggle.style.backgroundColor = 'rgba(128, 128, 128, 0.9)'; } }); document.body.appendChild(toggle); } function createFullscreenToggle() { const toggle = document.createElement('button'); toggle.id = 'pcol-assist-fullscreen-toggle'; toggle.textContent = '全屏'; toggle.style.cssText = ` position: fixed; top: 60px; left: 260px; width: 80px; height: 40px; font-size: 16px; background-color: rgba(70, 130, 180, 0.9); color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 9999; `; toggle.addEventListener('click', () => { const docEl = document.documentElement; const isFullscreen = document.webkitIsFullScreen || document.fullscreenElement; if (!isFullscreen) { if (docEl.webkitRequestFullscreen) { docEl.webkitRequestFullscreen(); } else if (docEl.requestFullscreen) { docEl.requestFullscreen(); } toggle.textContent = '退出全屏'; } else { if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.exitFullscreen) { document.exitFullscreen(); } toggle.textContent = '全屏'; } }); document.body.appendChild(toggle); } function updatePlayerSelection() { const player1Container = document.getElementById('pcol-player-container-player1'); const player2Container = document.getElementById('pcol-player-container-player2'); player1Container.style.border = 'none'; player2Container.style.border = 'none'; if (currentPlayer === 'player1') { player1Container.style.border = '3px solid #4CAF50'; } else { player2Container.style.border = '3px solid #4CAF50'; } } function createScoreboard() { const scoreboard = document.createElement('div'); scoreboard.id = 'pcol-assist-scoreboard'; scoreboard.style.cssText = ` position: fixed; top: 100px; left: 10px; display: flex; gap: 20px; z-index: 9998; `; function createPlayerScore(playerId, name) { const container = document.createElement('div'); container.id = `pcol-player-container-${playerId}`; container.style.cssText = ` display: flex; flex-direction: column; align-items: center; background-color: rgba(0, 0, 0, 0.7); padding: 10px; border-radius: 8px; cursor: pointer; `; container.addEventListener('click', () => { currentPlayer = playerId; updatePlayerSelection(); }); const nameEl = document.createElement('div'); nameEl.textContent = name; nameEl.style.cssText = ` color: white; font-size: 20px; font-weight: bold; margin-bottom: 5px; `; const scoreEl = document.createElement('div'); scoreEl.id = `pcol-score-${playerId}`; scoreEl.textContent = '0'; scoreEl.style.cssText = ` color: white; font-size: 36px; width: 80px; text-align: center; margin-bottom: 10px; border: 2px solid white; border-radius: 4px; padding: 5px 0; `; const buttonsContainer = document.createElement('div'); buttonsContainer.style.cssText = ` display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px; `; for (let i = 1; i <= 7; i++) { const btn = document.createElement('button'); btn.id = `pcol-add-${playerId}-${i}`; btn.textContent = `+${i}`; btn.style.cssText = ` width: 40px; height: 40px; font-size: 18px; background-color: ${scoreColors[i]}; color: white; border: none; border-radius: 4px; cursor: pointer; `; btn.addEventListener('click', (e) => { e.stopPropagation(); const btnId = btn.id; if (buttonCooldowns[btnId]) return; scores[playerId] += i; scoreEl.textContent = scores[playerId]; buttonCooldowns[btnId] = true; btn.style.backgroundColor = scoreColors[i].replace('0.6', '0.3'); setTimeout(() => { buttonCooldowns[btnId] = false; btn.style.backgroundColor = scoreColors[i]; }, 1000); }); buttonsContainer.appendChild(btn); } const minusBtn = document.createElement('button'); minusBtn.id = `pcol-minus-${playerId}-1`; minusBtn.textContent = '-1'; minusBtn.style.cssText = ` width: 40px; height: 40px; font-size: 18px; background-color: rgba(178, 34, 34, 0.6); color: white; border: none; border-radius: 4px; cursor: pointer; `; minusBtn.addEventListener('mousedown', (e) => { e.stopPropagation(); longPressTimer = setTimeout(() => { scores[playerId] = 0; scoreEl.textContent = '0'; }, LONG_PRESS_DELAY); }); minusBtn.addEventListener('mouseup', (e) => { e.stopPropagation(); if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; const btnId = minusBtn.id; if (minusCooldowns[btnId]) return; if (scores[playerId] > 0) { scores[playerId] -= 1; scoreEl.textContent = scores[playerId]; minusCooldowns[btnId] = true; minusBtn.style.backgroundColor = 'rgba(139, 0, 0, 0.3)'; setTimeout(() => { minusCooldowns[btnId] = false; minusBtn.style.backgroundColor = 'rgba(178, 34, 34, 0.6)'; }, 200); } } }); minusBtn.addEventListener('touchstart', (e) => { e.stopPropagation(); longPressTimer = setTimeout(() => { scores[playerId] = 0; scoreEl.textContent = '0'; }, LONG_PRESS_DELAY); }); minusBtn.addEventListener('touchend', (e) => { e.stopPropagation(); if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; const btnId = minusBtn.id; if (minusCooldowns[btnId]) return; if (scores[playerId] > 0) { scores[playerId] -= 1; scoreEl.textContent = scores[playerId]; minusCooldowns[btnId] = true; minusBtn.style.backgroundColor = 'rgba(139, 0, 0, 0.3)'; setTimeout(() => { minusCooldowns[btnId] = false; minusBtn.style.backgroundColor = 'rgba(178, 34, 34, 0.6)'; }, 200); } } }); minusBtn.addEventListener('mouseleave', () => { if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); buttonsContainer.appendChild(minusBtn); container.appendChild(nameEl); container.appendChild(scoreEl); container.appendChild(buttonsContainer); return container; } scoreboard.appendChild(createPlayerScore('player1', 'P1')); scoreboard.appendChild(createPlayerScore('player2', 'P2')); document.body.appendChild(scoreboard); updatePlayerSelection(); } keysConfig.forEach(createVirtualKey); createVisibilityToggle(); createScoreboardToggle(); createFullscreenToggle(); createScoreboard(); })();