非公開 座標自動維持ボタン(離席用)

    @@ -6,68 +6,84 @@ javascript:(function(){ if(document.getElementById('afk-rotate-btn')) return; - /* 1. ボタン作成(誤タップ防止のため画面上部中央) */ + /* 1. ボタン作成(🌀マークのみの最小サイズ) */ const btn = document.createElement('button'); btn.id = 'afk-rotate-btn'; - btn.innerHTML = '🌀 ぐるぐる OFF'; + btn.innerHTML = '🌀'; Object.assign(btn.style, { position: 'fixed', - top: '15px', - left: '50%', - transform: 'translateX(-50%)', + top: '60px', /* 左上から少し下げた位置 */ + left: '10px', zIndex: '10000', - padding: '10px 20px', - backgroundColor: 'rgba(15, 23, 42, 0.9)', + width: '40px', + height: '40px', + lineHeight: '40px', + textAlign: 'center', + backgroundColor: 'rgba(0, 0, 0, 0.3)', /* 控えめな透過黒 */ color: '#fff', - border: '2px solid #334155', - borderRadius: '25px', - fontSize: '14px', - fontWeight: 'bold', + border: '1px solid rgba(255, 255, 255, 0.5)', + borderRadius: '50%', + fontSize: '20px', cursor: 'pointer', - boxShadow: '0 4px 15px rgba(0,0,0,0.5)' + padding: '0', + outline: 'none' }); document.body.appendChild(btn); let rotateInterval = null; let step = 0; - /* 上・右・下・左 の方向ベクトル */ - const dirs = [ - {x: 0, y: -1}, {x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0} - ]; + const dirs = [{x: 0, y: -1}, {x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}]; - const toggle = () => { + /* 停止・解除関数 */ + const stopRotate = () => { + if (!rotateInterval) return; + clearInterval(rotateInterval); + rotateInterval = null; + btn.style.backgroundColor = 'rgba(0, 0, 0, 0.3)'; + btn.style.borderColor = 'rgba(255, 255, 255, 0.5)'; + + if(typeof inputState !== 'undefined') { + inputState.dx = 0; + inputState.dy = 0; + inputState.drawing = false; + if(typeof sendInput === 'function') sendInput(); + } + }; + + /* 開始関数 */ + const startRotate = (e) => { + if (e) e.stopPropagation(); if (rotateInterval) { - clearInterval(rotateInterval); - rotateInterval = null; - btn.innerHTML = '🌀 ぐるぐる OFF'; - btn.style.borderColor = '#334155'; - /* 停止時は入力をリセット */ - if(typeof inputState !== 'undefined') { - inputState.dx = 0; - inputState.dy = 0; - inputState.drawing = false; - if(typeof sendInput === 'function') sendInput(); - } - } else { - btn.innerHTML = '🌀 ぐるぐる稼働中!'; - btn.style.borderColor = '#22c55e'; /* 稼働中は緑に */ - rotateInterval = setInterval(() => { - if (typeof inputState !== 'undefined' && typeof sendInput === 'function') { - const d = dirs[step % 4]; - /* 1. 入力値を書き換え */ - inputState.dx = d.x; - inputState.dy = d.y; - inputState.drawing = true; - - /* 2. ゲーム側の送信ロジックを発火させる */ - sendInput(); - - step++; - } - }, 200); /* 0.2秒刻み */ + stopRotate(); + return; } + btn.style.backgroundColor = 'rgba(255, 0, 0, 0.6)'; /* 稼働中は赤く光る */ + btn.style.borderColor = '#fff'; + rotateInterval = setInterval(() => { + if (typeof inputState !== 'undefined' && typeof sendInput === 'function') { + const d = dirs[step % 4]; + inputState.dx = d.x; + inputState.dy = d.y; + inputState.drawing = true; + sendInput(); + step++; + } + }, 200); }; - btn.onclick = toggle; - console.log('Rotate Script Active: Logic sync with client-game.js'); + btn.onclick = startRotate; + + /* 2. 操作介入による自動解除のリスナー */ + /* タッチ・マウス・キーボードのいずれかがあったら停止 */ + const inputEvents = ['touchstart', 'mousedown', 'keydown']; + inputEvents.forEach(eventType => { + window.addEventListener(eventType, (e) => { + /* ぐるぐるボタン自体へのクリックは無視して、それ以外の操作で停止 */ + if (e.target !== btn && rotateInterval) { + stopRotate(); + } + }, { capture: true, passive: true }); + }); + + console.log('🌀 Minimal Auto-Rotate: Input-interruption mode active.'); })();
  • /*
     * @title 座標自動維持ボタン(離席用)
     * @description 押すとその場でグルグル回り続けるボタンが表示される
     * @private
     */
    javascript:(function(){
        if(document.getElementById('afk-rotate-btn')) return;
    
        /* 1. ボタン作成(🌀マークのみの最小サイズ) */
        const btn = document.createElement('button');
        btn.id = 'afk-rotate-btn';
        btn.innerHTML = '🌀';
        Object.assign(btn.style, {
            position: 'fixed',
            top: '60px', /* 左上から少し下げた位置 */
            left: '10px',
            zIndex: '10000',
            width: '40px',
            height: '40px',
            lineHeight: '40px',
            textAlign: 'center',
            backgroundColor: 'rgba(0, 0, 0, 0.3)', /* 控えめな透過黒 */
            color: '#fff',
            border: '1px solid rgba(255, 255, 255, 0.5)',
            borderRadius: '50%',
            fontSize: '20px',
            cursor: 'pointer',
            padding: '0',
            outline: 'none'
        });
        document.body.appendChild(btn);
    
        let rotateInterval = null;
        let step = 0;
        const dirs = [{x: 0, y: -1}, {x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}];
    
        /* 停止・解除関数 */
        const stopRotate = () => {
            if (!rotateInterval) return;
            clearInterval(rotateInterval);
            rotateInterval = null;
            btn.style.backgroundColor = 'rgba(0, 0, 0, 0.3)';
            btn.style.borderColor = 'rgba(255, 255, 255, 0.5)';
            
            if(typeof inputState !== 'undefined') {
                inputState.dx = 0;
                inputState.dy = 0;
                inputState.drawing = false;
                if(typeof sendInput === 'function') sendInput();
            }
        };
    
        /* 開始関数 */
        const startRotate = (e) => {
            if (e) e.stopPropagation();
            if (rotateInterval) {
                stopRotate();
                return;
            }
            btn.style.backgroundColor = 'rgba(255, 0, 0, 0.6)'; /* 稼働中は赤く光る */
            btn.style.borderColor = '#fff';
            rotateInterval = setInterval(() => {
                if (typeof inputState !== 'undefined' && typeof sendInput === 'function') {
                    const d = dirs[step % 4];
                    inputState.dx = d.x;
                    inputState.dy = d.y;
                    inputState.drawing = true;
                    sendInput();
                    step++;
                }
            }, 200);
        };
    
        btn.onclick = startRotate;
    
        /* 2. 操作介入による自動解除のリスナー */
        /* タッチ・マウス・キーボードのいずれかがあったら停止 */
        const inputEvents = ['touchstart', 'mousedown', 'keydown'];
        inputEvents.forEach(eventType => {
            window.addEventListener(eventType, (e) => {
                /* ぐるぐるボタン自体へのクリックは無視して、それ以外の操作で停止 */
                if (e.target !== btn && rotateInterval) {
                    stopRotate();
                }
            }, { capture: true, passive: true });
        });
    
        console.log('🌀 Minimal Auto-Rotate: Input-interruption mode active.');
    })();
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。