はじめに
私の趣味の一つに、トレーディングカードゲーム(TCG)があります。
昨今の外出自粛要請による影響は、TCG 界隈においても例外に漏れず、対面で TCG を遊ぶ機会のほとんどがなくなってしまいました。
この記事では、少しでも TCG 界隈の停滞感をなくすために開発した Web アプリの紹介と開発手順のメモ書きを~~まとめています。~~鋭意作成中です。
対象読者
- IT 分野以外の趣味で IT を活用したい人
- Twitter アカウントによる認証を用いた Web アプリをつくりたい人
- WebRTC(ビデオ通話など)を活用した Web アプリをつくりたい人
- Nuxt.js/TypeScript の開発に興味がある人
モチベーション
TCG は大前提として対面で遊ぶことを想定したアナログゲームですが、学生以下をメインターゲット層としたものも多く、歳を重ねるにつれて身の周りから TCG を一緒に遊ぶ友達がだんだんと減っていくものです(悲しい)。
他方、TCG を専門に取り扱うカードショップなどでは、店舗大会や公認自主イベントと呼ばれるような、誰でも気軽に参加できるイベントが定期的に開催され、友達や知り合いがいなくても TCG を楽しめる環境が整っていました。
しかしながら、昨今の外出自粛要請により、カードショップでのイベントは全面的に中止に。
このような状況を受けてか、TCG 界隈では、知り合い同士で Skype や Discord などのビデオ通話アプリを用いたリモートカードゲームの環境を積極的に取り入れつつあります。
私自身、今回の騒動以前から何度かリモートカードゲームを遊んだことがありますが、以下のような課題があると感じています。
- 知り合いの中に、都合のつく人がなかなか見つからない
- とはいえ、事前に日程調整しておく(待ち合わせ時間を決めておく)のは面倒
- かといって、知り合い以外の募集に自分から声をかける勇気もない
- 相手が見つかったとて、Skype やら Discord やらを使い分け、都度連絡先を登録するのも面倒
ただの面倒くさがりやんけ。
まあ、とにかくそのような課題の解決を目指す気持ち半分、「転活のポートフォリオがわりに使えねえかなぁ」の気持ち半分で開発した Web アプリがこの**『PTCGrand』**です。
【ゆる宣伝】#リモートポケカ を気軽に遊べるランダムマッチアプリ「PTCGrand」を開発中です🙌
— てぃら (@tilanosaur) May 3, 2020
SkypeやDiscordの連絡先交換いらずで、TwitterアカウントがあればOK🙆♀️
まだ開発途上なのでちょいちょい不具合もありますが、ひとまず動かせるようになったので公開しちゃいます↓https://t.co/tUvD7lSmf9 pic.twitter.com/YWhnuVIwWm
基本アイディアとして、対戦型オンラインゲームでは一般的なランダムマッチング機能を実装しました。
そのため、たとえ知り合いがいなくても、リアルタイムに対戦相手を募集している人同士でリモートカードゲームを遊ぶことができます。
- 知り合いの中に、都合のつく人がなかなか見つからない
- とはいえ、事前に日程調整しておく(待ち合わせ時間を決めておく)のは面倒
- かといって、知り合い以外の募集に自分から声をかける勇気もない
さらに、ビデオ通話機能を Web 上で完結させることで、Skype や Discord の連絡先交換は言わずもがな、アプリのインストールすら不要にしました。
また、この Web アプリを利用するのに複雑な手順があるとかえって面倒になってしまうため、Twitter アカウントとの連携による認証を導入し、設定手順も最小化しています。
- 相手が見つかったとて、Skype やら Discord やらを使い分け、都度連絡先を登録するのも面倒
特定 TCG プレイヤー向けの紹介記事 は(別名義で)note に投稿済みなので、興味ある方はそちらも併せてご覧ください。
フレームワーク と アーキテクチャ
開発した Web アプリの大まかな構成と動作は、以下の通りです。
Nuxt.js/Typescript
- SPA (Single Page Application) の生成
- Bootstrap4 (BootstrapVue) によるデザインレイアウト
Firebase
- Nuxt.js で生成した SPA のホスティング (Firebase Hosting)
- Twitter 連携によるユーザー認証 (Firebase Authentication)
- データベース機能の提供(Peer 情報と対戦希望の管理) (Firebase Cloud Firestore)
SkyWay
- ユーザー間のビデオ通話・データ通信の確立
開発手順
重要そうなところやハマったところを中心に、メモ書きを残しています。
用意が面倒なのでスクリーンショットなどを掲載していないため、詳しく知りたい方は、適宜、記事末尾にある参考記事をご覧いただければと思います。
バージョン
$ node -v
v12.16.2
$ npm -v
6.14.4
Nuxt.js プロジェクトの作成
Nuxt.js 公式サイトに書かれているとおり、create-nuxt-app
コマンドでプロジェクトを作成します。
開発言語に TypeScript、UI フレームワークに BootstrapVue を選択していますが、このあたりは好みかと思います。
Nuxt.js プロジェクトにおける TypeScript 記法は、公式の Nuxt TypeScript ガイドが参考になります。
$ npx create-nuxt-app <project-name>
create-nuxt-app v2.15.0
✨ Generating Nuxt.js project in <project-name>
? Project name <project-name>
? Project description <project-description>
? Author name @blachocolat
? Choose programming language TypeScript
? Choose the package manager Npm
? Choose UI framework Bootstrap Vue
? Choose custom server framework None (Recommended)
? Choose the runtime for TypeScript Default
? Choose Nuxt.js modules Progressive Web App (PWA) Support
? Choose linting tools ESLint, Prettier
? Choose test framework Jest
? Choose rendering mode Single Page App
? Choose development tools jsconfig.json (Recommended for VS Code)
Bootstrap テーマ と Web フォントの導入
Nuxt.js プロジェクトの UI フレームワークに Bootstrap を採用する強みの一つは、過去のプロジェクトのテーマを使い回せることかもしれません1。
今回は、以前「所有しているボードゲームの管理サイト」を開発した際に使用した Bootswatch の Lumen テーマを導入することにしました。
/assets
以下に scss/bootswatch.scss
を作成し、Global に読み込む設定を nuxt.config.js
に追加します。
アプリのテーマ色を設定するため、元の設定値が書かれた _variables.scss
を @import
するよりも前に変数 $primary
を定義することで、実質的に変数を書き換えています2。
CSS セレクタによる Style の適用は、より後に書かれたものが優先されるため、@import
の後に記述します。
また、同様に SCSS の変数を書き換える形で、Google Fonts で公開されている Web フォントを適用しています。
$primary: #d44050;
$font-family-sans-serif: 'M PLUS 1p', sans-serif;
$font-family-monospace: 'M PLUS 1p', monospace;
@import '~/node_modules/bootswatch/dist/lumen/_variables';
// $primary: $blue !default;
@import '~/node_modules/bootstrap/scss/bootstrap';
@import '~/node_modules/bootswatch/dist/lumen/_bootswatch';
.b-avatar {
&.badge-secondary {
color: $gray-500;
}
}
...
export default {
head: {
...
link: [
...
+ { rel: 'stylesheet', type: 'text/css', href: 'https://fonts.googleapis.com/css?family=M+PLUS+1p' }
]
},
...
css: [
...
+ '~/assets/scss/bootswatch.scss'
],
...
}
Firebase Hosting へのデプロイ
Firebase CLI (firebase-tools
) をインストールしていなければ、npm
経由でインストールします。
インストール完了後、firebase login
コマンドを実行し、Web ブラウザ経由で Google アカウントを紐づけます。
$ npm install -g firebase-tools
$ firebase login
作成した Nuxt.js プロジェクトに移動し、Firebase プロジェクトとしての初期設定を行います。
Firebase 公式ドキュメントを参考に、あらかじめ Web ブラウザから Firebase プロジェクトを作成しておくとよいでしょう。
ここでは、? Which Firebase CLI features...
の設問に対して Firebase Hosting のみを選択しています。
$ cd /path-to/<project-name>
$ firebase init
...
? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Ente
r to confirm your choices. Hosting: Configure and deploy Firebase Hosting sites
...
=== Project Setup
? Please select an option: Use an existing project
? Select a default Firebase project for this directory: <project-name> (<project-name>)
i Using project <project-name> (<project-name>)
...
=== Hosting Setup
? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
...
Firebase Hosting の公開ディレクトリに /public
を指定したため、それに合わせるように nuxt.config.js
の出力ディレクトリを変更します。
export default {
...
+ generate: {
+ dir: 'public'
+ },
...
以上で、準備が整いました。
下記コマンドで SPA を生成し、Firebase Hosting にデプロイします。
$ npm run generate
$ firebase deploy
なお、一度公開した SPA を非公開にしたい場合、下記コマンドを実行します。
$ firebase hosting:disable
参考記事
- Nuxt.js + Firebase Authentication + FireStoreでwebアプリケーションハンズオン (@ririli)
- Nuxt.js + Vuex + Firebase(Authentication, Cloud Firestore)でTwitterユーザー向けの伝言板を作る (@ysd_marrrr)
- はじめてのvue-property-decorator (nuxtにも対応) (@simochee)
- vuex + typescriptをvuex-module-decoratorsで無敵になる (@tsrnk)
- Nuxt.js + Typescript + Vuexする現時点のベストと思う方法 (@suzukenz)
- 0から始める Firestore + Firebase Authentication (@karayok)
- Nuxt(SPA)+Firebaseでログイン処理を実装する (@pochopocho13)
- Nuxt.jsのプロジェクトでnuxt-i18nを使ってi18n(国際化)対応する方法 (@munieru_jp)
- nuxt-i18nでNuxt.jsの国際化して、英語版と日本語版を用意する (くらげになりたい。)
おわりに
せっかくそれなりの形になった Web アプリを開発したので、開発手順のメモ書きをまとめ~~ました。~~たかったのですが途中で力尽きてしまいました。
アプリについては、公開から数日経ったものの肝心のユーザー数はまだまだ少なく、なかなかランダムマッチングが成立していない状況です。
その結果、半ば “待ち合わせ時間を決めておく” のが必要になっており、上であげた課題そのものにぶち当たっています(悲しい)。
~~開発モチベーションの半分が半分なのであれですが、~~個人開発だからこそ、機能をゴリゴリ実装するだけでなく、必要な人のもとに届くための施策を考えていきたいですね。