【NEMTUSハッカソン2022】ブロックチェーンを組み合わせたタイピングゲームを作ってみた

# はじめに
- ブロックチェーン×ゲームがテーマのプログラミングハッカソンが開催されたので、今回思い切ってエントリーしてみました。（[NEMTUS Hackathon HACK+ 2022](https://hackathon-2022.nemtus.com/)）
- ずっと「ブロックチェーンを開発で触ってみたい」と思いながら、なかなか一歩が踏み出せなかったのですが、今回挑戦してみて色々な学びがありました。この記事が、私と同じように「ブロックチェーンを触ってみたい」と思っている皆さんの背中を押すきっかけになれば幸いです。

# 自己紹介
- C#とPythonを多少使える程度で、Webの開発やゲーム作り、ましてやブロックチェーンを使った開発経験は完全にゼロです。ハッカソンも今回初参加。仕事も普通の一般企業に務めてます。平凡な社内SEです。そんな自分でもここまで作れたので、この記事を見て「自分にも出来るかも」と思ってもらえたら嬉しいです。

# 作ったもの：タイピングゲーム
いきなり結論ですが、今回のハッカソンでは**ブロックチェーンを組み込んだタイピングゲーム**を作りました。実際に公開してるのでぜひプレイしてみてください。「なんでタイピングゲーム？」「どこにブロックチェーンが？？」と思いますよね。それぞれ順番に解説していきます！！

※プレイ時にSymbolのウォレットアドレスが必要になりますが、「Trial Mode」を選べばアドレス不要で遊ぶことができます。

[Symbol Typing Quest](https://kurikou02.github.io/symboltyping/)
![thumbnail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285378/29c94b5b-a663-7d1b-32a0-869716cfc337.png)


# 開発環境・使ったブロックチェーンなど
- ブロックチェーン：[Symbol](https://docs.symbol.dev/index.html)（[symbol-sdk-1.0.3.js](https://symbol.github.io/symbol-sdk-typescript-javascript/1.0.3/)）
    - ※今回はSymbolのテストネットを使っています。
- ゲームライブラリ：[Phina.js](https://phinajs.com/)
- 開発環境：[Runstant](http://runstant.com/)

私のようなエンジョイ勢のプログラマが、今回ブロックチェーンゲームを完成できたのは、間違いなくこの**Symbol**の性能のおかげです。エンジニアフレンドリーかつ高性能、最高のチェーンだと思います。

# ブロックチェーン活用ポイント
主に以下の4つのポイントでブロックチェーンを活用しています。それぞれ具体的なコードの例も交えて紹介していきましょう。

1) ユーザ認証（ユーザ管理）
2) ゲーム内アイテム（独自トークン）
3) ゲームクリアトークン（賞金）
4) スコアリスト(DBレス）

### １．ユーザ認証（ユーザ管理）

今回のゲームでは、ユーザマスタやユーザリストといった、ユーザ管理用のDBは一切使っていません。SymbolブロックチェーンのウォレットアドレスをユーザIDとして入力し、有効なアドレスと確認出来たら「ログインOK」とする仕様にしています。

ウォレットアドレスを投げて対象のアカウント情報を取得する処理については、SDKで用意されています。公式ドキュメントにある下記のサンプルを応用することで比較的すぐ実装出来ました。

```typescript
// replace with address
const rawAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const address = Address.createFromRawAddress(rawAddress);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const accountHttp = repositoryFactory.createAccountRepository();

accountHttp.getAccountInfo(address).subscribe(
  (accountInfo) => console.log(accountInfo),
  (err) => console.error(err),
);
```

:::note warn
課題
「ウォレットアドレスが確認できたらログインOK」とする上記の仕様ですが、お気づきの通り厳密には認証になっていません。これだと他人のアドレスでプレイすることが出来てしまいます。本当はユーザの秘密鍵による署名まで行うべきですが、今回は時間の都合で簡易的な処理に留めています。
:::

### ２．ゲーム内アイテム（独自トークン）

Symbolのユニークな機能の一つに、リボーカブルモザイク（回収可能トークン）というものがあります。これを使えば、トークンの発行者は、任意のタイミングで保有者からトークンを回収（没収）することが出来ます。期間限定の会員権のような使い方がイメージしやすいかもしれません。
[参考：Symbolのリボーカブルモザイク](https://qiita.com/planethouki/items/6d98e85df7f30250e58d)

また、Symbolは**独自トークンの発行がめちゃくちゃ手軽にできる**点も大きな特徴です。Symbolのコミュニティでは、ユーザが自分たちで独自のトークンを発行して流通させることで、コミュニティを中心とした独自の経済圏が形成されつつあります。これめちゃくちゃ面白いです。
[参考：Symbol(NEM)なら誰でも簡単にGUIでトークンが発行できる](https://medium.com/opening-line/symbol-nem-%E3%81%AA%E3%82%89%E8%AA%B0%E3%81%A7%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%ABgui%E3%81%A7%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%8C%E7%99%BA%E8%A1%8C%E3%81%A7%E3%81%8D%E3%82%8B-254324bf05)
[参考：Arcanaでgiveaway用絵付きモザイク（トークン）を作ろう](https://nemlog.nem.social/blog/75382)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">わ、わ、わ～～～👀‼️<br>初めて <a href="https://twitter.com/hashtag/Arcana?src=hash&amp;ref_src=twsrc%5Etfw">#Arcana</a> から通知が😳✨✨なんだろうと思ってみたら、サンキューモザイクが届いた通知でした🙌💖わ～～～い🥳✨<br>まめしば昨日と今日でおニュー✨🆕✨のモザイクいっぱい貰えた🤤✨皆さん本当にありがとうございます🙇‍♀️💖<a href="https://twitter.com/hashtag/%E3%83%A2%E3%82%B6%E3%82%A4%E3%82%AF%E7%A5%AD?src=hash&amp;ref_src=twsrc%5Etfw">#モザイク祭</a> <a href="https://twitter.com/hashtag/Symbol?src=hash&amp;ref_src=twsrc%5Etfw">#Symbol</a> <a href="https://t.co/UM7tgLIVdX">pic.twitter.com/UM7tgLIVdX</a></p>&mdash; まめしば⚔️Symbol海賊応援団見習い🏴‍☠️ (@maromaro1989) <a href="https://twitter.com/maromaro1989/status/1484900626215895041?ref_src=twsrc%5Etfw">January 22, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

今回のゲームでは、シューティングゲームの「ボム」アイテム風に、独自トークンを活用しています。具体的には以下のような感じです。

まず、「**bomb_mosaic**」という独自トークンをSymbolチェーン上で発行します。（手順は、上記リンクの独自モザイク発行の記事を参照ください）実際に発行した独自トークンの情報をウォレットで表示すると以下のようなイメージになります。今回はハッカソン用なので有効期間を限定的にしてます。

![qiita_20220417_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285378/69548a45-cbc1-7e37-36c4-677335bad758.png)

ゲーム内では、一度ゲームオーバーになると「お助けアイテムとしてボムトークンを使いますか？」とユーザに問う仕様にしています。ボムトークンを付与する（対象のウォレットアドレスに送付する）部分の処理は以下の通り。これはゲーム内の実コードです。

```typescript
  // BOMBモザイク送信！
  sendBombMosaic: function( trgetAddress, amount, msg ){

    console.log('---- send Bomb Mosaic -----');
    // トランザクション作成
    const account = this.xym.Account.createFromPrivateKey(this.privateKey, this.xym.NetworkType.TEST_NET);
    const transferTransaction = this.xym.TransferTransaction.create(
      this.xym.Deadline.create(this.epochAdjustment),
      this.xym.Address.createFromRawAddress(trgetAddress), 
      [new this.xym.Mosaic (new this.xym.MosaicId(this.bombMosaicId),this.xym.UInt64.fromUint(amount))],
      this.xym.PlainMessage.create(msg),
      this.xym.NetworkType.TEST_NET,
      this.xym.UInt64.fromUint(100000)
    );
    // 署名
    const networkGenerationHash =
      '7FCCD304802016BEBBCD342A332F91FF1F3BB5E902988B352697BE245F48E836';
    const signedTransaction = account.sign(
      transferTransaction,
      networkGenerationHash);
    
    // 発行
    this.announce(signedTransaction);
  },
```

そしてゲーム内でプレイヤーがボムを発動すると、ただちにボムトークンの回収処理が走ります。回収のコードも先程のトークン付与のコードとほぼ同じ要領です。詳細は[こちらの記事](https://qiita.com/planethouki/items/6d98e85df7f30250e58d)を参考ください。

:::note warn
課題
リボーカブルモザイク（回収可能トークン）は非常に便利な機能ですが、トークン付与 or 回収には若干のタイムラグ（トランザクションが確定するまでのリードタイム）がありますので注意が必要です。私はややリアルタイムな使い方をしてしまっていますが、厳密にはトランザクション発行～確定までボムの使用を制限する…などの処理が必要になるかと思います。
:::


### ３．ゲームクリアトークン（賞金）

タイピングゲームをクリアした人には、お祝いのメッセージを添えてささやかな賞金を付与する仕様にしています。※本当の仮想通貨トークン（XYM）を付与するのはリスクがあるかなと思ったので、今回は無価値なテストネット上のXYMを投げるようにしています。

百聞は一見にしかず、実際にゲームクリア時にユーザにXYMが付与されているトランザクションが[こちら](https://testnet.symbol.fyi/transactions/0FA589448F3EF1EEBACAC4F3345BFBC3000530D0A5391FB1299E2A0E1C2878F4)になります。（[Symbol Testnet Explorer](https://testnet.symbol.fyi/transactions/0FA589448F3EF1EEBACAC4F3345BFBC3000530D0A5391FB1299E2A0E1C2878F4)）インターネットさえ繋がっていれば、ゲームクリアの状況やスコアを世界中の誰でも自由に確認することが出来ます。ブロックチェーンの透明性を実感出来ますね。

XYMを発行する部分のコードは以下の通り。オーソドックスなトランザクション発行処理です。msg部分にはお祝いのメッセージと、スコア情報をJSON形式で埋め込んでいます。

```typescript
  // XYM送金！
  sendXym: function( trgetAddress, amount, msg ){

    console.log('---- send Xym -----');
    
    // トランザクション作成
    const account = this.xym.Account.createFromPrivateKey(this.privateKey, this.xym.NetworkType.TEST_NET);
    const transferTransaction = this.xym.TransferTransaction.create(
      this.xym.Deadline.create(this.epochAdjustment),
      this.xym.Address.createFromRawAddress(trgetAddress), 
      [new this.xym.Mosaic (new this.xym.MosaicId('3A8416DB2D53B6C8'),this.xym.UInt64.fromUint(amount * Math.pow(10, 6)))],
      this.xym.PlainMessage.create(msg),
      this.xym.NetworkType.TEST_NET,
      this.xym.UInt64.fromUint(100000)
    );
    // 署名
    const networkGenerationHash =
      '7FCCD304802016BEBBCD342A332F91FF1F3BB5E902988B352697BE245F48E836';
    const signedTransaction = account.sign(
      transferTransaction,
      networkGenerationHash);
    
    // 発行
    this.announce(signedTransaction);
    
  },
```

今回はSymbolの仮想通貨である「XYM（のテスト用トークン）」を付与していますが、これは自前で発行した独自トークンとかを使っても面白いと思います。自分の作ったゲーム上でだけ使えるオリジナルのトークンを発行して、将来的にそのトークンに価値がついたり…取引所に上場したとしたら…？これは夢が広がりますね。

:::note warn
課題
今回はテストネット環境（＆時間がなかった）ということで、ゲームの賞金を発行するアドレスの秘密鍵をプログラム中にダイレクトに書き込んでしまっていますが、当然これはNGです汗 秘密鍵は隠蔽するか、送金プログラムだけはクローズドな環境に分離しましょう。
:::

### ４．スコアリスト(DBレス）

Symbolを使ったゲーム開発をしてみて、今回一番面白いと思ったのは、DBやローカルの設定ファイル等を全く使わずにゲームが作れてしまったことです。

例えば今回のタイピングゲームでは、「クリアした人のスコアでランキングを出したいな…」とか思い浮かぶんですが、ブロックチェーン上のトランザクション履歴をトレースすることで自然とスコアリストを算出したり、ユーザ一覧なども出すことが出来ます。（今回の提出物ではそこまで実装間に合いませんでしたが…）
[参考：SymbolTypingQuestのトランザクション一覧](https://testnet.symbol.fyi/accounts/TDEAUFR5ED25QUUGPO7M6SXVSD6OSUEDFPAAL5A)

ネットワークに刻まれたトランザクションのデータは、特定のサービスやプラットフォームに依存することなく、インターネットを通じて世界の誰でも参照可能です。おまけに改ざん困難、常時1300台以上のノードで世界中で分散されています。もちろんその分、データを刻むための手数料（XYM）が発生するので、そこは注意が必要です。

今回はテストネット環境だったので手数料分や報酬で配るXYMの量を気にせず作っていますが、メインネット（本番環境）で稼働させる場合は、プレイヤー側からプレイ料金としてXYMをもらう、寄付を募る、ハーベスティング（ビットコインでいうマイニング的な仕組み）でXYMを収穫する…などの施策を組み合わせる必要があります。その辺の設計を考えるのもまた面白いですね。

# Ice breaking：なんでタイピングゲーム？

ブロックチェーンの技術的な部分に触れたところで、タイピングゲームをテーマに選んだ理由ですが、至極単純で「絵が描けないから」でした。ゲームと言えばみんなグラフィカルでデザインの格好いいものを作ってくるに違いない…と思ったんですが、私は絵が描けないのでテキストベースで勝負しよう！と思いました。あとタイピングゲームって老若男女みんな楽しめていいかなと。

ただのタイピングゲームにしても面白くないので、Symbolのコアデベロッパーをボスキャラに見立てて倒していくRPG風味にしてみようとか、ボムトークンを入れてみようとか、ブロックチェーンに関するキーワードを打ち込むことで勉強にもなるように…とか色々考えてゲーム性が出るように工夫はしてみました。

### Symbolのデザイン/世界観がめちゃクール

テキストベースで勝負しよう！とか書いたくせに、ゲームのビジュアルがめちゃ凝ってるのには理由がありまして、今回のゲームで使っているイラストなどの素材はすべてSymbolブロックチェーンの公式素材をそのまま使っています。

Symbolは「Reflections of Space Pirates」というVisionを掲げており、紫を基調としたサイバーパンクなデザイン・キャラクターで独自の世界観を構築しています。（[Vision: Symbol²](https://docs.symbol.dev/ja/handbook/vision.html)）

そして、なんとそれらの[イラストやアート素材、キャラクターのアバターデータなどが、CC0(パブリックドメイン）として公開されている](https://drive.google.com/drive/folders/1XA40rl4WyMXk1FJYQsjpABcjVcCSNmNA)のです！

ブロックチェーンとしての開発しやすさもさることながら、デザイン・世界観などの素材（しかもハイクオリティ！）までも提供されているのは非常に嬉しいなと思いました。Symbolコミュニティでは、実際にこれらのデザインを自分たちでグッズにしたり、リアルコインを作って楽しんでいる人もいるようですよ。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Symbol?src=hash&amp;ref_src=twsrc%5Etfw">#Symbol</a> 勢のみなさま、CBD JAPAN MARKET きりんやブースに立ち寄っていただきありがとうございます🙏❤️‍🔥<br>おかげさまで、予想以上に <a href="https://twitter.com/hashtag/Symbol%E6%B1%BA%E6%B8%88?src=hash&amp;ref_src=twsrc%5Etfw">#Symbol決済</a> 限定Tシャツが捌けるのが速いですｗ<br>残り3着ですよー！！お待ちしておりまーすー🦊✨ <a href="https://t.co/HAuxQ12dv7">pic.twitter.com/HAuxQ12dv7</a></p>&mdash; nemicon🦊@4/17 CBD JAPAN MARKETでSymbol決済 (@_nemicon_) <a href="https://twitter.com/_nemicon_/status/1515560539472084992?ref_src=twsrc%5Etfw">April 17, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">新NEM/Symbolプロジェクトの制作状況まとめました！<br><br>⚡️ “Official Logo!! New Symbol / NEM Project” by <a href="https://twitter.com/sakamotometal?ref_src=twsrc%5Etfw">@sakamotometal</a> <a href="https://t.co/SdJxMbnE3Q">https://t.co/SdJxMbnE3Q</a></p>&mdash; SAKAMOTO 🪙 Custom Medal, Coin, Badge オリジナルコイン 社章 (@sakamotometal) <a href="https://twitter.com/sakamotometal/status/1515505812243836930?ref_src=twsrc%5Etfw">April 17, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# まとめ

皆様長文お付き合い頂きまことにありがとうございました。色々書きましたが、

***ブロックチェーンを活用して何か作ってみたい人は、とにかくSymbolを触ってみて！！***

というのが全体の結論でございます。私に出来たのでみんなも出来ます。百聞は一見にしかずです。コピペでもいいので、とりあえずサンプルコードを動かしてみる。実際にトランザクションが刻まれ、自分のウォレットに通知が届く。Explorerでトランザクションの履歴が見れる。やってみてわかること、感動することたくさんあります。

何より、楽しいです。Webの解説や参考記事を読んで学んだ知識が、実際に自分で動かして体験してみることでより深く実感することができます。「あれはこういうことだったのか！」という感覚がたまりません。Qiitaにも入門から応用まで様々なSymbolの開発記事が存在します。まずはコピペでも全然構いませんので、ぜひチャレンジしてみてください。

#### Symbol開発の参考記事
- [ノンプログラマーがSymbolブロックチェーンでゲームを作ってみた](https://qiita.com/nembear/items/4b84506ff4a62f3f1ce1)
- [ Symbol Pythonでxymを送金する](https://qiita.com/nobu_kyutech/items/049971f8b82cc9a055e8)
- [PythonでSymbolブロックチェーンの送金プログラムを書いてみる。](https://qiita.com/nem_takanobu/items/f3c02caa17ad385b6155)
- [Hello Symbol Blockchain! 2022年4月時点での開発関連情報まとめ](https://qiita.com/nem_takanobu/items/4f50e5740318d92d7dcb)

ちなみに今回作ったタイピングゲームは、残念ながらハッカソンの入賞には至りませんでしたが、せっかくなのでメインネットに乗せてリリース出来るように今後も少しづつ開発していく予定です。いつになるかわかりませんが、リリース後は遊んでいただけると幸いです。

# (参考)公開中のSymbolブロックチェーンゲーム一覧

https://hackathon-2022.nemtus.com/works/

Symbolブロックチェーンゲームのハッカソンはすでに終了していますが、提出されたゲームはすべて公開中です。

もはやハッカソンの枠を超えてそのまま事業化できそうなレベルのものから、フルオンチェーンNFTを組み込んだもの、ゲームのコードが全てオンチェーン上に刻まれている「フルオンチェーンテトリス」などなど、時代の先を行き過ぎているゲームが多数あります。

ちなみのSymbolのフルオンチェーンNFTは驚異の性能ですので、気になる方はぜひそちらも調べて見てください。凄すぎて世間の理解が追いついていない感すらあります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ついに720p 30fps 1min　2万3千トランザクションのオンチェーンNFTデータを完成させる。<br>これは実験であるがSymbolブロックチェーンの脅威のテクノロジーが伝わるだろうか？<a href="https://twitter.com/hashtag/symbol?src=hash&amp;ref_src=twsrc%5Etfw">#symbol</a> <a href="https://twitter.com/hashtag/nem?src=hash&amp;ref_src=twsrc%5Etfw">#nem</a> <a href="https://t.co/Kx50ge5xCD">pic.twitter.com/Kx50ge5xCD</a></p>&mdash; ボー太郎博士（NCYRHFYAW7W6MNOPNUC3B2BBCXP3KHO3TPTONCA） (@EUFjZEyIuzS9rIi) <a href="https://twitter.com/EUFjZEyIuzS9rIi/status/1395010551420362752?ref_src=twsrc%5Etfw">May 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>