自爆ボタン
delaunay-triangulation
view source
JavaScript
document.title = '自爆ボタン';
//delaunay-triangulation
let { canvas, ctx, cx, cy, w, h, min, demo } = readyCanvas();
document.body.style.overflow = 'hidden';
let isPressed = false;
function drawStripe(){
var diag = Math.sqrt(w * w + h * h); // 対角線の長さ(キャンバスを斜めにカバー)
const stripeWidth = min/12; // 縞の幅
const stripeCount = Math.ceil(diag / stripeWidth) * 2;
ctx.save();
// 原点をキャンバスの中央に移動し、45度回転
ctx.translate(w / 2, h / 2);
ctx.rotate(Math.PI / 4); // 45度 = π/4 ラジアン
// 左上隅に戻ってから塗り始める
ctx.translate(-diag / 2, -diag / 2);
for (let i = 0; i < stripeCount; i++) {
ctx.fillStyle = (i % 2 === 0) ? 'black' : 'yellow';
ctx.fillRect(i * stripeWidth, 0, stripeWidth, diag);
}
ctx.restore();
}
function drawBlackSquare() {
const size = min * 5/6;
const x = (w - size) / 2;
const y = (h - size) / 2;
ctx.fillStyle = 'black';
ctx.fillRect(x, y, size, size);
}
function drawCircle() {
const outerRadius = Math.min(w, h) / 4;
const middleRadius = outerRadius * 0.9;
// 外円:左上から右下への線形グラデーション(光が左上から)
let gradOuter = ctx.createLinearGradient(cx - outerRadius, cy - outerRadius, cx + outerRadius, cy + outerRadius);
gradOuter.addColorStop(0, '#ffffff'); // 光が当たる部分(左上)
gradOuter.addColorStop(1, '#aaaaaa'); // 影になる部分(右下)
ctx.beginPath();
ctx.arc(cx, cy, outerRadius, 0, Math.PI * 2);
ctx.fillStyle = gradOuter;
ctx.fill();
// 中円:逆方向のグラデーション(右下が明るい)
let gradInner = ctx.createLinearGradient(cx + middleRadius, cy + middleRadius, cx - middleRadius, cy - middleRadius);
gradInner.addColorStop(0, '#eeeeee'); // 右下が明るく
gradInner.addColorStop(0.8, '#aaaaaa'); // 左上が暗く
gradInner.addColorStop(1, '#888888'); // 左上が暗く
ctx.beginPath();
ctx.arc(cx, cy, middleRadius, 0, Math.PI * 2);
ctx.fillStyle = gradInner;
ctx.fill();
}
function drawButton() {
const outerRadius = Math.min(w, h) / 4;
const innerRadius = isPressed ? outerRadius * 0.65 : outerRadius * 0.7;
const offset = isPressed ? 4 : 0;
// 内円(赤いボタン)
ctx.beginPath();
ctx.arc(cx, cy + offset, innerRadius, 0, Math.PI * 2);
const gradient = ctx.createRadialGradient(cx, cy + offset, innerRadius * 0.2, cx, cy + offset, innerRadius);
gradient.addColorStop(0, '#ff6666');
gradient.addColorStop(1, '#990000');
ctx.fillStyle = gradient;
ctx.fill();
}
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let audioBuffer = null;
let sourceNode = null;
let isPlaying = false;
let playInterval = null;
fetch('buzzer.mp3?t=1')
.then(res => res.arrayBuffer())
.then(data => audioCtx.decodeAudioData(data))
.then(buffer => {
audioBuffer = buffer;
});
function startBuzz() {
if (!audioBuffer || isPlaying) return;
isPlaying = true;
const duration = audioBuffer.duration;
const half = duration / 2;
const fadeTime = 0.3;
function playInstance(startTime) {
let source = audioCtx.createBufferSource();
let gain = audioCtx.createGain();
source.buffer = audioBuffer;
source.connect(gain).connect(audioCtx.destination);
// フェードイン
gain.gain.setValueAtTime(0, startTime);
gain.gain.linearRampToValueAtTime(1, startTime + fadeTime);
// フェードアウト
gain.gain.setValueAtTime(1, startTime + duration - fadeTime);
gain.gain.linearRampToValueAtTime(0, startTime + duration);
source.start(startTime);
// 最初の音源だけ記録しておく(即停止用)
if (!sourceNode) {
sourceNode = source;
}
}
const now = audioCtx.currentTime;
playInstance(now); // 最初の再生
playInstance(now + half); // 半分経過で次の再生
// 以降も定期的に繰り返す
playInterval = setInterval(() => {
if (sourceNode) {
const now = audioCtx.currentTime;
playInstance(now);
}
}, half * 1000);
}
function stopBuzz() {
if (playInterval) {
clearInterval(playInterval);
playInterval = null;
}
if (sourceNode) {
try {
sourceNode.stop();
} catch (e) {
// 既に停止している場合の安全処理
}
sourceNode.disconnect();
sourceNode = null;
}
isPlaying = false;
}
function redraw() {
ctx.clearRect(0, 0, w, h);
drawStripe();
drawBlackSquare();
drawCircle();
drawButton();
}
redraw();
canvas.addEventListener('mousedown', function(e) {
isPressed = true;
startBuzz();
redraw();
});
canvas.addEventListener('mouseup', function(e) {
isPressed = false;
stopBuzz();
redraw();
});
window.addEventListener('resize', function(e) {
redraw();
});
CSS
HTML
ページのソースを表示 : Ctrl+U , DevTools : F12
view-source:https://hi0a.com/game/btn-danger/
ABOUT
hi0a.com 「ひまあそび」は無料で遊べるミニゲームや便利ツールを公開しています。
プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。
必要な機能の関数をコピペ利用したり勉強に活用できます。
プログラムの動作サンプル結果は画面上部に出力表示されています。
環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。
画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。
仕様変更、API廃止等、実験途中で動かないページもあります。