🎮✨ CDNFontsを活用した「フォントスロット」ゲームの作り方 - Webフォントの楽しい使い方

こんにちは😊
[株式会社プロドウガ](https://qiita.com/organizations/prodouga-com)の@YushiYamamotoです！
[らくらくサイト](https://rakuraku-site.prodouga.com/)の開発・運営を担当しながら、React.js・Next.js専門のフリーランスエンジニアとしても活動しています❗️

今回は、Webフォントを楽しく学べる「フォントスロット」というブラウザゲームの作り方をご紹介します。CDNFontsのディスプレイフォントを使って、スロットマシンのようにフォントが切り替わる面白いゲームを一緒に作っていきましょう！

<p class="codepen" data-height="603" data-slug-hash="YPzLoZV" data-pen-title="Untitled" data-editable="true" data-user="yamamotoyushi" style="height: 603px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yamamotoyushi/pen/YPzLoZV">
  Untitled</a> by Yushi Yamamoto (<a href="https://codepen.io/yamamotoyushi">@yamamotoyushi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>

## 🎯 今回作るもの

今回作成するのは、ボタンを押すとランダムにフォントが切り替わり、もう一度ボタンを押すと停止する「フォントスロット」ゲームです。

- CDNFontsのディスプレイフォントを使用
- スタート・ストップボタンでフォントの切り替えを制御
- 表示されるテキスト自体がそのフォントで表示される


## 🛠️ 開発環境

特別な開発環境は必要ありません。テキストエディタとブラウザがあれば作成できます。

## 📚 CDNFontsとは？

[CDNFonts](https://fonts.cdnfonts.com/)は、無料で使えるWebフォントを提供しているサービスです。Google Fontsと同様に、CDNを通じてフォントを簡単に利用できます。今回は特に[ディスプレイカテゴリ](https://fonts.cdnfonts.com/category/display)のフォントを使用します。このカテゴリには13,000種類以上の個性的なフォントが揃っています！

## 🚀 実装手順

### 1. HTMLの基本構造を作成

まずは、HTMLの基本構造を作成します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>フォントスロット</title>
    <!-- フォントのリンクはここに追加 -->
    <style>
        /* CSSスタイルはここに記述 */
    </style>
</head>
<body>
    <div class="container">
        <h1>フォントスロット</h1>
        
        <div class="link-section">
            フォントの詳細や追加のフォントは、以下のリンクから確認できます：<br>
            <a href="https://fonts.cdnfonts.com/category/display" target="_blank">https://fonts.cdnfonts.com/category/display</a>
        </div>
        
        <div id="font-display" class="font-display">フォントスロット</div>
        
        <div class="buttons">
            <button id="start-button">スタートボタン</button>
            <button id="stop-button" disabled>ストップボタン</button>
        </div>
    </div>

    <script>
        // JavaScriptコードはここに記述
    </script>
</body>
</html>
```


### 2. 使用するフォントを読み込む

CDNFontsから使用したいフォントを選び、`<head>`タグ内に読み込みコードを追加します。

```html
<head>
    <!-- 前略 -->
    <link href="https://fonts.cdnfonts.com/css/dasher" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/supernova" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/gemseatrial" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/wondrous" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/jumbotron" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/flavor-mellow" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/ovum" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/echelon" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/snowmas" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/bagel-fat-one" rel="stylesheet">
    <!-- 後略 -->
</head>
```

:::note info
フォントは[CDNFontsのディスプレイカテゴリ](https://fonts.cdnfonts.com/category/display)から好きなものを選べます。各フォントの詳細ページにリンクタグが表示されるので、それをコピーして使用します。
:::

### 3. CSSでスタイルを設定

見た目を整えるためのCSSを追加します。

```css
body {
    font-family: Arial, sans-serif;
    text-align: center;
    margin: 0;
    padding: 20px;
    background-color: #f5f5f5;
}
h1 {
    margin-bottom: 20px;
}
.container {
    max-width: 600px;
    margin: 0 auto;
    padding: 20px;
    background-color: white;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.font-display {
    height: 150px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    margin: 30px 0;
    padding: 20px;
    border: 2px solid #ddd;
    border-radius: 8px;
    background-color: #f9f9f9;
}
.buttons {
    margin-top: 20px;
}
button {
    padding: 10px 20px;
    margin: 0 10px;
    font-size: 16px;
    cursor: pointer;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
}
button:disabled {
    background-color: #cccccc;
    cursor: not-allowed;
}
.link-section {
    margin-top: 20px;
    font-size: 14px;
}
```


### 4. JavaScriptでスロット機能を実装

最後に、JavaScriptでスロット機能を実装します。

```javascript
const fonts = [
    'DASHER', 'Supernova', 'GEMSEAtrial', 'Wondrous', 'JUMBOTRON',
    'Flavor Mellow', 'Ovum', 'ECHELON', 'SNOWMAS', 'Bagel Fat One'
];

const fontDisplay = document.getElementById('font-display');
const startButton = document.getElementById('start-button');
const stopButton = document.getElementById('stop-button');

let slotInterval;
let isRunning = false;

startButton.addEventListener('click', () => {
    if (!isRunning) {
        startSlot();
    }
});

stopButton.addEventListener('click', () => {
    if (isRunning) {
        stopSlot();
    }
});

function startSlot() {
    isRunning = true;
    startButton.disabled = true;
    stopButton.disabled = false;
    
    slotInterval = setInterval(() => {
        const randomFont = fonts[Math.floor(Math.random() * fonts.length)];
        fontDisplay.style.fontFamily = randomFont;
        fontDisplay.textContent = randomFont;
    }, 100);
}

function stopSlot() {
    clearInterval(slotInterval);
    isRunning = false;
    startButton.disabled = false;
    stopButton.disabled = true;
}
```


## 🔍 コードの解説

### HTMLの構造

- `container`クラスで全体を囲み、中央に配置
- `font-display`要素がフォントを表示する部分
- スタートとストップの2つのボタンを配置


### CSSのポイント

- `font-display`クラスは高さを固定し、中央揃えにすることで、フォントが切り替わっても表示位置が安定
- ボタンは`disabled`状態のスタイルも設定し、使用できないときを視覚的に表現


### JavaScriptの仕組み

1. フォント名の配列を定義
2. スタートボタンクリック時に`setInterval`でフォントをランダムに切り替え
3. ストップボタンクリック時に`clearInterval`で停止
4. ボタンの有効/無効状態を適切に管理

## 🧩 フォントスロットの動作フロー

```mermaid
graph TD
    A[ページ読み込み] --> B[初期状態: スタートボタン有効]
    B --> C{スタートボタンクリック}
    C --> D[スタートボタン無効化]
    D --> E[ストップボタン有効化]
    E --> F[フォントランダム切り替え開始]
    F --> G{ストップボタンクリック}
    G --> H[フォント切り替え停止]
    H --> I[ストップボタン無効化]
    I --> J[スタートボタン有効化]
    J --> C
```


## 🔧 カスタマイズのアイデア

このフォントスロットは基本的な機能だけですが、以下のようにカスタマイズすることで、より楽しいゲームにできます：

### 1. フォントの追加

```javascript
// より多くのフォントを追加
const fonts = [
    'DASHER', 'Supernova', 'GEMSEAtrial', 'Wondrous', 'JUMBOTRON',
    'Flavor Mellow', 'Ovum', 'ECHELON', 'SNOWMAS', 'Bagel Fat One',
    // 追加フォント
    'Caveat', 'Pacifico', 'Lobster', 'Comic Neue', 'Dancing Script'
];
```

:::note info
追加するフォントは必ず`<head>`タグ内にもリンクを追加してください。
:::

### 2. 表示テキストのカスタマイズ

```javascript
// 表示するテキストをフォント名以外に変更
function startSlot() {
    // 前略
    slotInterval = setInterval(() => {
        const randomFont = fonts[Math.floor(Math.random() * fonts.length)];
        fontDisplay.style.fontFamily = randomFont;
        fontDisplay.textContent = "Hello World!"; // フォント名ではなく固定テキスト
    }, 100);
}
```


### 3. 速度調整機能の追加

```javascript
// スロットの回転速度を調整するスライダーを追加
const speedSlider = document.getElementById('speed-slider');
let speed = 100; // デフォルト速度

speedSlider.addEventListener('input', (e) => {
    speed = 200 - e.target.value; // 1-100のスライダー値を200-100の速度に変換
});

function startSlot() {
    // 前略
    slotInterval = setInterval(() => {
        // 中略
    }, speed);
}
```


### 4. 複数のスロットリールの実装

複数のテキスト要素を用意し、それぞれ独立してフォントが変わるようにすることで、本格的なスロットマシンのような体験ができます。

<details><summary>複数リール対応コード</summary>

```javascript
// 3つのリールを持つフォントスロット
const reels = document.querySelectorAll('.font-reel');
const startButton = document.getElementById('start-button');
const stopButton = document.getElementById('stop-button');

let reelIntervals = [];
let isRunning = false;

startButton.addEventListener('click', () => {
    if (!isRunning) {
        startAllReels();
    }
});

stopButton.addEventListener('click', () => {
    if (isRunning) {
        stopNextReel();
    }
});

function startAllReels() {
    isRunning = true;
    startButton.disabled = true;
    stopButton.disabled = false;
    
    reels.forEach((reel, index) => {
        reelIntervals[index] = setInterval(() => {
            const randomFont = fonts[Math.floor(Math.random() * fonts.length)];
            reel.style.fontFamily = randomFont;
            reel.textContent = randomFont;
        }, 100);
    });
}

let stoppedReels = 0;
function stopNextReel() {
    if (stoppedReels < reels.length) {
        clearInterval(reelIntervals[stoppedReels]);
        stoppedReels++;
        
        if (stoppedReels === reels.length) {
            isRunning = false;
            startButton.disabled = false;
            stopButton.disabled = true;
            stoppedReels = 0;
        }
    }
}
```

</details>

## 📝 完成したコード

<details><summary>完全なHTMLコード</summary>

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>フォントスロット</title>
    <link href="https://fonts.cdnfonts.com/css/dasher" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/supernova" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/gemseatrial" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/wondrous" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/jumbotron" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/flavor-mellow" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/ovum" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/echelon" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/snowmas" rel="stylesheet">
    <link href="https://fonts.cdnfonts.com/css/bagel-fat-one" rel="stylesheet">
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        h1 {
            margin-bottom: 20px;
        }
        .container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
        .font-display {
            height: 150px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 48px;
            margin: 30px 0;
            padding: 20px;
            border: 2px solid #ddd;
            border-radius: 8px;
            background-color: #f9f9f9;
        }
        .buttons {
            margin-top: 20px;
        }
        button {
            padding: 10px 20px;
            margin: 0 10px;
            font-size: 16px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .link-section {
            margin-top: 20px;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>フォントスロット</h1>
        
        <div class="link-section">
            フォントの詳細や追加のフォントは、以下のリンクから確認できます：<br>
            <a href="https://fonts.cdnfonts.com/category/display" target="_blank">https://fonts.cdnfonts.com/category/display</a>
        </div>
        
        <div id="font-display" class="font-display">フォントスロット</div>
        
        <div class="buttons">
            <button id="start-button">スタートボタン</button>
            <button id="stop-button" disabled>ストップボタン</button>
        </div>
    </div>

    <script>
        const fonts = [
            'DASHER', 'Supernova', 'GEMSEAtrial', 'Wondrous', 'JUMBOTRON',
            'Flavor Mellow', 'Ovum', 'ECHELON', 'SNOWMAS', 'Bagel Fat One'
        ];
        
        const fontDisplay = document.getElementById('font-display');
        const startButton = document.getElementById('start-button');
        const stopButton = document.getElementById('stop-button');
        
        let slotInterval;
        let isRunning = false;
        
        startButton.addEventListener('click', () => {
            if (!isRunning) {
                startSlot();
            }
        });
        
        stopButton.addEventListener('click', () => {
            if (isRunning) {
                stopSlot();
            }
        });
function startSlot() {
isRunning = true;
startButton.disabled = true;
stopButton.disabled = false;

            slotInterval = setInterval(() => {
                const randomFont = fonts[Math.floor(Math.random() * fonts.length)];
                fontDisplay.style.fontFamily = randomFont;
                fontDisplay.textContent = randomFont;
            }, 100);
        }
        
        function stopSlot() {
            clearInterval(slotInterval);
            isRunning = false;
            startButton.disabled = false;
            stopButton.disabled = true;
        }
    </script>
    </body>
</html>

```

</details>

## ✅ 技術的なポイント

フォントスロットの実装には、以下の技術的なポイントがあります：

1. **Webフォントの読み込み**：CDNFontsのCSSリンクを使用して、外部フォントを簡単に読み込めます

2. **setInterval/clearInterval**：JavaScriptのタイマー機能を使って、フォントの切り替えとその停止を制御

3. **DOM操作**：`style.fontFamily`プロパティを動的に変更することで、表示フォントをリアルタイムに切り替え

4. **イベントハンドリング**：ボタンクリックイベントを適切に処理し、ユーザー操作に応じた挙動を実現

5. **状態管理**：`isRunning`変数を使って、スロットの状態（回転中か停止中か）を管理

## 🎮 ゲーム開発の応用例

このフォントスロットの仕組みは、他のブラウザゲーム開発にも応用できます：

1. **カードゲーム**：カードをランダムに表示するスロット
2. **言語学習ゲーム**：単語や文字をランダムに表示して学習
3. **クイズゲーム**：問題をランダムに出題するシステム

## 🚀 発展的な機能

より高度なフォントスロットを作りたい場合は、以下の機能を追加することを検討してみてください：

1. **フォント情報の表示**：選ばれたフォントの詳細情報（作者、スタイルなど）を表示
2. **お気に入り機能**：気に入ったフォントをお気に入りに登録できる機能
3. **カテゴリ分け**：フォントをカテゴリ別に分けて、特定のカテゴリだけで回す機能
4. **アニメーション効果**：フォント切り替え時のトランジション効果の追加

:::note warn
2025年3月現在、CDNFontsには13,000種類以上のディスプレイフォントがありますが、すべてのフォントが常に利用可能とは限りません。使用前に各フォントの利用規約を確認することをお勧めします。
:::

## 📱 モバイル対応のポイント

モバイルデバイスでもスムーズに動作させるためには、以下の点に注意しましょう：

1. レスポンシブデザインの採用
2. タッチ操作に適したボタンサイズの設定
3. モバイルでのフォント読み込み時間を考慮した最適化

## 🔮 まとめ

今回は、CDNFontsのディスプレイフォントを活用した「フォントスロット」ゲームの作り方を紹介しました。シンプルなHTMLとCSS、JavaScriptだけで、楽しいインタラクティブなゲームが作れることがわかりました。

このようなミニゲームは、ウェブサイトのエンゲージメント向上や、フォント選びのインスピレーション源として活用できます。また、JavaScriptの基本的な概念（DOM操作、タイマー処理、イベントハンドリングなど）を学ぶ良い教材にもなります。

ぜひ自分なりにカスタマイズして、オリジナルのフォントスロットを作ってみてください！

# 最後に：業務委託のご相談を承ります
私は業務委託エンジニアとしてWEB制作やシステム開発を請け負っています。最新技術を活用したレスポンシブなWebサイト制作、インタラクティブなアプリケーション開発、API連携など幅広いご要望に対応可能です。

「課題解決に向けた即戦力が欲しい」「高品質なWeb制作を依頼したい」という方は、お気軽にご相談ください。一緒にビジネスの成長を目指しましょう！

👉 [ポートフォリオ](https://yushiyamamoto.vercel.app/)

🌳 [らくらくサイト](https://rakuraku-site.prodouga.com/)