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

    @@ -4,86 +4,61 @@ * @private */ javascript:(function(){ - if(document.getElementById('afk-rotate-btn')) return; + const id = 'afk-btn'; + if(document.getElementById(id)) return; - /* 1. ボタン作成(🌀マークのみの最小サイズ) */ - const btn = document.createElement('button'); - btn.id = 'afk-rotate-btn'; + /* 1. ゲームコンテナを取得(PCでの位置ずれ防止) */ + const container = document.getElementById('game-container') || document.body; + + const btn = document.createElement('div'); + btn.id = id; btn.innerHTML = '🌀'; Object.assign(btn.style, { - position: 'fixed', - top: '60px', /* 左上から少し下げた位置 */ + position: 'absolute', + top: '60px', left: '10px', zIndex: '10000', - width: '40px', - height: '40px', - lineHeight: '40px', + width: '36px', + height: '36px', + lineHeight: '36px', textAlign: 'center', - backgroundColor: 'rgba(0, 0, 0, 0.3)', /* 控えめな透過黒 */ - color: '#fff', - border: '1px solid rgba(255, 255, 255, 0.5)', + background: 'rgba(0,0,0,0.3)', borderRadius: '50%', - fontSize: '20px', - cursor: 'pointer', - padding: '0', - outline: 'none' + fontSize: '18px', + cursor: 'pointer' }); - document.body.appendChild(btn); + /* コンテナの中に入れることでゲーム画面と一緒に移動させる */ + container.appendChild(btn); + + let timer = null, step = 0; + const dirs = [{x:0,y:-1},{x:1,y:0},{x:0,y:1},{x:-1,y:0}]; - 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 stop = () => { + if (!timer) return; + clearInterval(timer); + timer = null; + btn.style.background = 'rgba(0,0,0,0.3)'; + if(window.inputState) { + inputState.dx = 0; inputState.dy = 0; inputState.drawing = false; + if(window.sendInput) 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; + btn.onclick = (e) => { + e.stopPropagation(); + if (timer) return stop(); + btn.style.background = 'rgba(255,0,0,0.6)'; + timer = setInterval(() => { + if (window.inputState && window.sendInput) { + 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.'); + /* 操作があったら停止(1つのリスナーで軽量化) */ + ['mousedown','touchstart','keydown'].forEach(ev => + window.addEventListener(ev, (e) => { if(e.target !== btn) stop(); }, {passive:true}) + ); })();
  • /*
     * @title 座標自動維持ボタン(離席用)
     * @description 押すとその場でグルグル回り続けるボタンが表示される
     * @private
     */
    javascript:(function(){
        const id = 'afk-btn';
        if(document.getElementById(id)) return;
    
        /* 1. ゲームコンテナを取得(PCでの位置ずれ防止) */
        const container = document.getElementById('game-container') || document.body;
    
        const btn = document.createElement('div');
        btn.id = id;
        btn.innerHTML = '🌀';
        Object.assign(btn.style, {
            position: 'absolute',
            top: '60px',
            left: '10px',
            zIndex: '10000',
            width: '36px',
            height: '36px',
            lineHeight: '36px',
            textAlign: 'center',
            background: 'rgba(0,0,0,0.3)',
            borderRadius: '50%',
            fontSize: '18px',
            cursor: 'pointer'
        });
        /* コンテナの中に入れることでゲーム画面と一緒に移動させる */
        container.appendChild(btn);
    
        let timer = null, step = 0;
        const dirs = [{x:0,y:-1},{x:1,y:0},{x:0,y:1},{x:-1,y:0}];
    
        const stop = () => {
            if (!timer) return;
            clearInterval(timer);
            timer = null;
            btn.style.background = 'rgba(0,0,0,0.3)';
            if(window.inputState) {
                inputState.dx = 0; inputState.dy = 0; inputState.drawing = false;
                if(window.sendInput) sendInput();
            }
        };
    
        btn.onclick = (e) => {
            e.stopPropagation();
            if (timer) return stop();
            btn.style.background = 'rgba(255,0,0,0.6)';
            timer = setInterval(() => {
                if (window.inputState && window.sendInput) {
                    const d = dirs[step++ % 4];
                    inputState.dx = d.x; inputState.dy = d.y; inputState.drawing = true;
                    sendInput();
                }
            }, 200);
        };
    
        /* 操作があったら停止(1つのリスナーで軽量化) */
        ['mousedown','touchstart','keydown'].forEach(ev => 
            window.addEventListener(ev, (e) => { if(e.target !== btn) stop(); }, {passive:true})
        );
    })();
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。