ハテナブロック
2025年6月5日
みなさんこんにちは。
ケミストのWeb担当みやのです。
今回は「押すと音が鳴るボタン」を作っていたはずが、気づいたらスー〇ーマ〇オのハテナブロックを作っていました。
な…何を言っているのか わからねーと思うが(ry
このページでは音が鳴りますが、以前の 記事と違ってマナーモードにしていたら音は鳴りません。
用意するもの
まずは音源を用意します。
フリー音源サイト等で探してきましょう。



あとはGoogle FontsのPress Start 2Pというフォントを入手しておきます。
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
ブロックとコイン
ではブロックとコインを作っていきます。
HTMLはこんな感じです。
<div class="d-flex justify-content-center align-items-center">
<div class="block-container">
<div class="block" id="questionBlock" tabindex="-1">?</div>
</div>
</div>
うまく中央揃えにならなかったので適当にいろいろ足したらうまくいきました。
CSSは以下の通りです。
html {
touch-action: manipulation;
}
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
}
.block-container {
width: 100%;
max-width: 200px;
aspect-ratio: 1 / 1;
position: relative;
}
.block {
width: 100%;
height: 100%;
background: orange;
border: 7px solid brown;
box-shadow: 7px 7px black;
display: flex;
justify-content: center;
align-items: center;
font-size: 150px;
font-family: "Press Start 2P", serif;
color: brown;
text-shadow: 7px 7px black;
cursor: pointer;
user-select: none;
position: absolute;
top: 0;
left: 0;
}
.coin {
width: 60%;
height: 90%;
font-family: 'Press Start 2P', serif;
font-size: 90%;
color: gold;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%);
opacity: 0;
text-shadow: 2px 2px brown;
}
@keyframes coinAnimation {
0% {
transform: translate(-50%, -10px) rotateY(0deg) scaleX(1);
opacity: 1;
}
25% {
transform: translate(-50%, -100px) rotateY(90deg) scaleX(0.5);
opacity: 1;
}
50% {
transform: translate(-50%, -200px) rotateY(180deg) scaleX(1);
opacity: 1;
}
75% {
transform: translate(-50%, -100px) rotateY(270deg) scaleX(0.5);
opacity: 0.5;
}
100% {
transform: translate(-50%, -10px) rotateY(360deg) scaleX(1);
opacity: 0;
}
}
@keyframes blockAnimation {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0);
}
}
iPhoneだとダブルタップで拡大されちゃったり長押しで文字が選択されてメニューが出てきたりしちゃうのでそれらを禁止しておきます。
コインは、Press Start 2Pフォントの「数字の0」を使ってドット風にしてみようと思います(JavaScriptで追加します)
音を鳴らそう
ではブロックをクリックすると音が鳴るようにしていきましょう。
スマホだとどうしても、タッチしてから音が鳴るまでに遅延が発生して爽快感がなかったのでもうこの企画自体やめようかなとも思いましたがHowler.jsというライブラリを利用することで解決しました。
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js"></script>
ヘッダー内でHowler.jsを読み込んでおきます。
スクリプトを記述します。
const coinSound = new Howl({
src: ["coin.wav"],
preload: true,
volume: 1.0
});
document.getElementById("questionBlock").addEventListener("click", function() {
const block = this;
block.style.animation = "none";
requestAnimationFrame(() => {
block.style.animation = "blockAnimation 0.3s ease";
});
const coin = document.createElement("div");
coin.classList.add("coin");
coin.innerText = "0";
this.appendChild(coin);
coinSound.play();
coin.style.opacity = "1";
coin.style.display = "block";
coin.style.animation = "coinAnimation 0.5s ease-out forwards";
coin.addEventListener("animationend", () => coin.remove());
});
document.getElementById("questionBlock").addEventListener("dblclick", function(event) {
event.preventDefault();
});
requestAnimationFrameというのを使うと、高〇名人ばりに鬼連打してもちゃんとアニメーションしてくれるようになります。
一定回数鳴らすと...?
20回クリックするごとに別の音を追加で鳴らすようにしてみます。
最初100回に1回にしていましたが、指が疲れたので20回にしました。
const coinSound = new Howl({
src: ["coin.mp3"],
preload: true,
volume: 1.0
});
const oneUpSound = new Howl({
src: ["oneup.mp3"],
preload: true,
volume: 1.0
});
let clickCount = 0;
document.getElementById("questionBlock").addEventListener("click", function() {
const block = this;
block.style.animation = "none";
requestAnimationFrame(() => {
block.style.animation = "blockAnimation 0.3s ease";
});
const coin = document.createElement("div");
coin.classList.add("coin");
coin.innerText = "0";
this.appendChild(coin);
coinSound.play();
coin.style.opacity = "1";
coin.style.display = "block";
coin.style.animation = "coinAnimation 0.5s ease-out forwards";
coin.addEventListener("animationend", () => coin.remove());
clickCount++;
if (clickCount % 20 === 0) {
oneUpSound.play();
}
});
document.getElementById("questionBlock").addEventListener("dblclick", function(event) {
event.preventDefault();
});
今後の課題
・コインをもっとコインっぽくしたい
・コインのアニメーションをもっと本家に近づけたい
・ブロックをもっとドット風にしたい
・たまにスー〇ーキ〇コが出てきてパワーアップしたい