Java
HTML
JavaScript
乃木坂46

乃木坂46のメンバーからドラクエ風のパーティを作るWebサービスを作ってみた

タイトルのとおりです。名前を入れるだけで遊べるWebアプリを作ってみました。
https://www.rpgparty.sakamichi46.com/

ツイート結果はこんな感じ。


乃木坂ファンをターゲットにしてますが、乃木坂のメンバーを知らない方にも遊んでもらいたいです。そして、パーティを組んだメンバーのことを知って欲しいです!

開発のきっかけ

ちなみに乃木坂46には「きっかけ」というタイトルの曲があって、ミスチルの桜井さんがカバーするほど素晴らしい曲です。ご興味あるかたは是非聴いてみてください!

サービスの構成と利用した技術

構成はシンプルです。静的なHTMLはNetlifyに置いてます。バックエンドのアプリはSpring Bootで開発してHerokuのHobbyプランで動かしてます。生成した画像はCloudinaryというメディア管理のサービスを利用しました。

Untitled (52).png

フロントエンド

最初はVue.js使ってあれこれしようとか思っていたのですが、まずはシンプルなhtmlで作りました。

メッセージがゲームっぽく流れていますが、これはiTyped.jsというJavaScriptライブラリで実現しています。

itypedmessage.gif

タイプライター風にメッセージを表示できるライブラリです。ライブラリのページが機能のすべてを物語ってる気がw
ityped.gif

コードもシンプルで、こんな感じに書けます。タイプのスピードや消すスピード、ループするかなど細かく設定可能。

<script>
    ityped.init(document.querySelector('#message'), {
        strings: [
            'あなたが勇者となって乃木坂46メンバーとパーティを組んで旅に出る…。',
            '1期生,2期生,3期生…そして伝説の卒業生たちも…'],
        typeSpeed: 150,
        backSpeed: 0,
        loop: false,
        disableBackTyping: true,
        cursorChar: ""
    })
</script>

ゲーム風のフォントは「PixelMplus(ピクセル・エムプラス)」というフリーフォントです。カタカナや漢字も使えるのが素晴らしいです。

バックエンド

バックエンドに利用したWebフレームワークはSpring Boot 2.0.3.RELEASEです。今のところ全く活用できていないですがWebFluxを使っています。将来的にはノンブロッキングで色々やりたい…。ビューのテンプレートはThymeleafです。

コントローラはGETリクエストで入力された名前を受けるだけ。Spring BootのScopeはデフォルトでSingletonとのことで、今回はリクエストごとに単発の処理をしたくprotptypeスコープを使いました。この辺はまだあまり理解しきれていない気も…。(Java EEでいうApplicationScopeとRequestScopeのイメージであってるのかな)

@Controller
@Scope("prototype")
public class NogizakaController {

    @Autowired
    private NogizakaGenerator nogiGenerator;

    @GetMapping("/generate/nogizaka46")
    public String generateNogizaka46(@RequestParam(name = "name") String name, Model model) {
        String imageUrl = nogiGenerator.generate(name);
        model.addAttribute("name", name);
        model.addAttribute("imageUrl", imageUrl);
        return "index";
    }
}

Javaで画像を加工する処理を書くのは初めてだったのですが、わりと簡単にできるんですね。

BufferedImage bufferedImage = new BufferedImage(600, 314, BufferedImage.TYPE_INT_RGB);
Graphics graphics = bufferedImage.getGraphics();
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, 600, 314);
graphics.setColor(Color.WHITE);
...

当初は生成した画像データをBase64でエンコードした文字列をHTMLのimgタグのsrcに指定していました。

ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", os);
url = "data:image/png;base64," + Base64.getEncoder().encodeToString(os.toByteArray());

ただ、これだとツイートの際、Twitter Cardで画像が表示されません。調べてみると、画像表示するには静的なURLが必要なようです。

AWSのS3使うかなぁ…と思いながら何か良いサービスがないか探していたところ、Cloudinaryの存在を知りました。
2018-07-06_00h52_05.png

Web APIで簡単にファイルアップロードできます。一番の売りはURLを使って画像の加工ができるところのようです。サイトのトップページにある以下の例がわかりやすいですね。

2018-07-06_00h56_31.png

各種言語のSDKも揃っていて、もちろんJavaもあります。Mavenだと以下の定義です。

<dependency>
    <groupId>com.cloudinary</groupId>
    <artifactId>cloudinary-http44</artifactId>
    <version>1.18.0</version>
</dependency>

アップロード処理はこんな感じ。cloud_nameやapi_key、api_secretはCloudinaryのダッシュボードから取得できます。アップロードするメソッドの戻り値でURLなど様々なデータが取得できます。

File outputfile = new File(name + ".jpg");
ImageIO.write(bufferedImage, "jpg", outputfile);
Cloudinary cloudinary = new Cloudinary(ObjectUtils.asMap(
    "cloud_name", "xxxxx",
    "api_key", "yyyyy",
    "api_secret", "zzzzz")
);

Map upload = cloudinary.uploader().upload(outputfile,
    ObjectUtils.asMap(
        "public_id", name,
        "folder", "フォルダ名"));
String url = (String) upload.get("url");

アップロードされたファイルはダッシュボードで確認できます。便利!
2018-07-06_01h32_01.png

ロジック

脳内メーカーみたいに入力された文字が同じであれば同じ結果を返す、という処理をどう実装するかなぁ…と最初は悩みました。入力文字列は様々なものになりますが、なるべく統一的に処理したい、という。

最終的にはパスワードのハッシュ化などで使うSHA-256を使うことにしました。これを使えば入力文字列の長さに関係なく、256bit(32byte)のデータが生成できます。

パーティに割り当てられる人数は4人にして、64bit(8byte)ずつを割り当てました。あとはその割り当てられたbitを使って、一定のルールを決めました。ルールに基づいて抽出した数値をRandomのシードに指定して、名前が同じであれば同じ結果となることを実現させました。

ドット絵

地味に一番頑張ったは、プログラミングよりもドット絵な気がします(^^;

こちらは乃木坂ちゃん1stシングル「ぐるぐるカーテン」の衣装をイメージしたビット絵です。

ドット絵はスマホアプリの dotpict! を使いました。ネ申アプリ!

https://dotpicko.net/
2018-07-06_01h14_02.png

スマホのエディタ画面はこちらです。直感的なUIで使いやすかったです。

作成したドット絵を公開する投稿機能があって、SNSのように「フォロー」や「いいね」の機能まであります。これで無償アプリとか信じられない…。お金を払うと広告が消せるようですが、広告も邪魔にならないのであまり消す気にはならないっていうw ただ、作者様への感謝の意を込めて払いたいと思います。

こだわった点

色々ありますが、メンバーには卒業生を入れることにはこだわりました。橋本奈々未さんや深川麻衣さん、そして生駒里奈さんなど人気絶頂の中、卒業したメンバーは今もファンの間で根強い人気があります。そういったファンの想いも考慮して入れました。現役メンバーと同じ確率で選ばれるのも微妙なので、重みづけをしてレアキャラ感を出しています。

さいごに

現在は乃木坂46だけなのですが、今後は欅坂46、けやき坂46(ひらがなけやき)の提供をしていく予定ですので、坂道ファンの皆さんも、そうではない皆さんも是非遊んでいただければと思います。

リリースした後、アクセスが思っていたより多く、既にCloudinaryの無料プラン枠を超えそうなのが現在一番の懸念です(^^;とても良いサービスなのでお金を払うことに抵抗はないのですが、Freeの1つ上のPlusプランだと月$89と個人開発で使うにはお高め><;

2018-07-06_01h29_55.png