座標自動維持ボタン(離席用)
by
cutfloss
05/03 [2026/05/03 22:36:02]
押すとその場でグルグル回り続けるボタンが表示される
@@ -7,28 +7,39 @@
const id = 'afk-btn';
if(document.getElementById(id)) return;
- /* 1. ゲームコンテナを取得(PCでの位置ずれ防止) */
- const container = document.getElementById('game-container') || document.body;
-
+ /* 1. ボタン作成(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',
+ position: 'fixed',
+ zIndex: '100000', /* 最前面 */
+ width: '38px',
+ height: '38px',
+ lineHeight: '38px',
textAlign: 'center',
- background: 'rgba(0,0,0,0.3)',
+ background: 'rgba(0,0,0,0.4)',
borderRadius: '50%',
- fontSize: '18px',
- cursor: 'pointer'
+ fontSize: '20px',
+ cursor: 'pointer',
+ color: '#fff',
+ border: '1px solid rgba(255,255,255,0.3)',
+ transition: 'transform 0.1s'
});
- /* コンテナの中に入れることでゲーム画面と一緒に移動させる */
- container.appendChild(btn);
+ document.body.appendChild(btn);
+
+ /* 2. PC・スマホ両方の「ゲーム画面左上」を計算して配置する関数 */
+ const updatePos = () => {
+ const game = document.getElementById('game-container');
+ if (game) {
+ const rect = game.getBoundingClientRect();
+ /* ゲーム画面の左端から10px、上から60pxの位置に固定 */
+ btn.style.left = (rect.left + 10) + 'px';
+ btn.style.top = (rect.top + 60) + 'px';
+ }
+ };
+ window.addEventListener('resize', updatePos);
+ updatePos();
let timer = null, step = 0;
const dirs = [{x:0,y:-1},{x:1,y:0},{x:0,y:1},{x:-1,y:0}];
@@ -37,7 +48,8 @@
if (!timer) return;
clearInterval(timer);
timer = null;
- btn.style.background = 'rgba(0,0,0,0.3)';
+ btn.style.background = 'rgba(0,0,0,0.4)';
+ btn.style.transform = 'scale(1)';
if(window.inputState) {
inputState.dx = 0; inputState.dy = 0; inputState.drawing = false;
if(window.sendInput) sendInput();
@@ -45,9 +57,12 @@
};
btn.onclick = (e) => {
+ e.preventDefault();
e.stopPropagation();
if (timer) return stop();
+
btn.style.background = 'rgba(255,0,0,0.6)';
+ btn.style.transform = 'scale(1.1)';
timer = setInterval(() => {
if (window.inputState && window.sendInput) {
const d = dirs[step++ % 4];
@@ -57,8 +72,9 @@
}, 200);
};
- /* 操作があったら停止(1つのリスナーで軽量化) */
- ['mousedown','touchstart','keydown'].forEach(ev =>
- window.addEventListener(ev, (e) => { if(e.target !== btn) stop(); }, {passive:true})
- );
+ /* 3. 自動解除(ボタン自身以外の操作で停止) */
+ const handleReset = (e) => { if(timer && e.target !== btn) stop(); };
+ window.addEventListener('mousedown', handleReset, true);
+ window.addEventListener('touchstart', handleReset, true);
+ window.addEventListener('keydown', handleReset, true);
})();
/*
* @title 座標自動維持ボタン(離席用)
* @description 押すとその場でグルグル回り続けるボタンが表示される
* @private
*/
javascript:(function(){
const id = 'afk-btn';
if(document.getElementById(id)) return;
/* 1. ボタン作成(body直下に置いてクリック遮断を防ぐ) */
const btn = document.createElement('div');
btn.id = id;
btn.innerHTML = '🌀';
Object.assign(btn.style, {
position: 'fixed',
zIndex: '100000', /* 最前面 */
width: '38px',
height: '38px',
lineHeight: '38px',
textAlign: 'center',
background: 'rgba(0,0,0,0.4)',
borderRadius: '50%',
fontSize: '20px',
cursor: 'pointer',
color: '#fff',
border: '1px solid rgba(255,255,255,0.3)',
transition: 'transform 0.1s'
});
document.body.appendChild(btn);
/* 2. PC・スマホ両方の「ゲーム画面左上」を計算して配置する関数 */
const updatePos = () => {
const game = document.getElementById('game-container');
if (game) {
const rect = game.getBoundingClientRect();
/* ゲーム画面の左端から10px、上から60pxの位置に固定 */
btn.style.left = (rect.left + 10) + 'px';
btn.style.top = (rect.top + 60) + 'px';
}
};
window.addEventListener('resize', updatePos);
updatePos();
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.4)';
btn.style.transform = 'scale(1)';
if(window.inputState) {
inputState.dx = 0; inputState.dy = 0; inputState.drawing = false;
if(window.sendInput) sendInput();
}
};
btn.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
if (timer) return stop();
btn.style.background = 'rgba(255,0,0,0.6)';
btn.style.transform = 'scale(1.1)';
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);
};
/* 3. 自動解除(ボタン自身以外の操作で停止) */
const handleReset = (e) => { if(timer && e.target !== btn) stop(); };
window.addEventListener('mousedown', handleReset, true);
window.addEventListener('touchstart', handleReset, true);
window.addEventListener('keydown', handleReset, true);
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。