toio宝探しゲームを作ってみた

# はじめに
この記事は[toio advent calender 2019](https://qiita.com/advent-calendar/2019/toiotomo) 14日目の記事です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/b60ea3ba-48f5-62a5-5772-8376454d5322.png)


toioはロボットトイですが、技術仕様が公開されており、いろいろハックして遊べます。
詳しくはこちらの記事をご参照ください。

[toioの開発環境・情報まとめ（公式&非公式） - 放課後のtoioあそび](https://qiita.com/akichika/items/4e15d3df4fd3793c2c4c)

今まで私もM5Stackでtoioを動かすなど、いくつかtoioを使って遊んでいましたが、以前から「ロボットトイなので子供と遊べるゲームを作りたい」と思っていました。
なので今回は簡単ではありますがゲームを作ってみました。

作ったゲームは**宝探しゲーム**です。
家の中に隠されたtoioのカードを見つけて、それをtoioで読み込むことで次なるヒントが得られたり、toioの失われた移動能力を取り戻すことができます。
最後に洞窟から宝箱をゲットする！という流れになっています。

まずは動画をご覧ください。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">toio宝探しゲームを作ってみました！カードを家の中で探してみつけるとヒントが出たり、toioの移動能力が解放されます。最後にコースを走って宝箱をゲット！ <a href="https://t.co/53Q4DCWVSc">pic.twitter.com/53Q4DCWVSc</a></p>&mdash; Katsu Shun (@katsushun89) <a href="https://twitter.com/katsushun89/status/1205504515056660481?ref_src=twsrc%5Etfw">December 13, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# ゲーム作りの制約
toioでゲームを作るにあたって、折角toioを使うのでその特徴を活かすために以下の2つの条件を設けました。

- 移動する能力が必要なものにする
- カードとマットの読み取りセンサーを使う

# ゲームの流れ

最初は回転・移動できないようになっています。（キーボタン押してもtoioは動きません。）
その後カードを読み取りセンサーで読むと能力が解放されて、回転・移動できるようになります。
また、一つヒントをこなすごとに次のヒントが表示されるようにしています。

<img width="300" alt="80410785_598521054244640_3683139008432439296_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/740d7471-7051-9394-8bf4-4f520c426fbe.jpeg">

最初のヒント0「レゴの2x3ブロックが入っているケースの中」にカードがあります。
それを探して読み取ると次のヒントが表示されます。

<img width="300" alt="78957022_1276911709178354_5367183070875090944_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/1be700f6-b264-0acc-5125-a1f6c48a1136.jpeg">
<img width="300" alt="78639609_452503052355967_812629871355232256_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/75f7906d-33a7-46e0-9c0b-bff3f0a1c2b0.jpeg">

カード発見！

<img width="300" alt="79341880_485802372290578_2063955622243598336_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/852f6468-b8e6-cf44-fd54-c9657665428f.jpeg">
<img width="300" alt="79693065_479043812728880_3700862577526439936_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/1cb71cc9-9376-19d7-edba-97f73567a0cd.jpeg">

回転できるようになりました。
次のミッション「マットの上でtoioを時計回りに1回,反時計回りに2回回転させろ」を実行すると、次のヒントが出ます。（こちらは冒頭の動画参照）

<img width="300" alt="78814725_474416473190333_1568507591049347072_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/e6804ea9-1164-f0bd-7fa5-1e8bda870161.jpeg">

次のヒント「ドラゴンボール34巻に挟まれている」のとおり、家から34巻を探します！（34巻に特に強い意味はないです）
<img width="300" alt="78676811_419675115582106_2661518021318672384_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/d9a4f770-ad76-ffbf-1ae8-429b9e44f2e4.jpeg">

カード発見！
最初のヒント同様にカードを読むと移動能力をゲット！
最後に宝箱があるコースを移動して宝箱をゲットします！（これも動画の通りです）

<img width="300" alt="79796697_1085551318443297_6100917506854092800_n.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302503/759ed12c-7b7d-8306-3e21-1c6f50fa2ab1.jpeg">


# ゲーム機能の開発
子供が遊べるように操作はスマホでやりたかったので、この記事をそのまま参考にさせてもらい、jsで制御することにしました。（この記事javascript素人の私にとって、とても助かりました！）

[toio.jsをブラウザで動かしてみた](https://qiita.com/shinsuke-noguchi/items/037d729327232b6c0d33)

作成したものはgithub-pagesで公開しています。
https://katsushun89.github.io/toio-treasure-hunt/dist/

正直jsは全く触ったことがなかったのですが、いくつかの機能について説明します。

## カード読み取りによるヒント表示
ヒントの文言はMapで持たせました。

```main.js
const hint_text = new Map([['hint1', 'マットの上でtoioを時計回りに1回,反時計回りに2回回転させろ'],
                           ['hint2', 'ドラゴンボール34巻に挟まれている'],
                           ['hint3', '前に進めるようになったtoioでゴールを目指せ']]);
let got_hint = new Map();

```

カードを読むとそのstandard-idの値が取得できます。
それに応じてgot_hintにヒントの文言を入れます。
```got_hint.has('hint1')```でゲット済みか判断しています。

```if(got_hint.has('hint1')) hint1_content = got_hint.get('hint1');```
の箇所でhtml側に表示する文字列を変更しています。

```main.js
  cube.on('id:standard-id', info => {
    //document.getElementById('standard-id').innerHTML = JSON.stringify(info);
    var id = info.standardId;

    if(id == '3670054' && !got_hint.has('hint1')){
      got_hint.set('hint1', hint_text.get('hint1'));
      //play sound
      cube.playPresetSound('3');
      ability.enableRotate();
    }

    if(id == '3670022' && got_hint.has('hint2') && !got_hint.has('hint3')){
      got_hint.set('hint3', hint_text.get('hint3'));
      //play sound
      cube.playPresetSound('3');
      ability.enableMove();
    }

    let hint1_content = '';
    let hint3_content = '';
    if(got_hint.has('hint1')) hint1_content = got_hint.get('hint1');
    if(got_hint.has('hint3')) hint3_content = got_hint.get('hint3');

    document.getElementById('hint1').innerHTML = hint1_content;
    document.getElementById('hint3').innerHTML = hint3_content;

  });
 
```

## 移動能力の解放
移動能力を管理するclass Abilityを用意しました。

```main.js
class Ability {
  constructor() {
    this.move = false;
    this.rotate = false;
  }
  canMove() {return this.move;}
  canRotate() {return this.rotate;}
  enableMove() {
    this.move = true;
    document.getElementById('ability-move').style.color = 'blue';
  }
  enableRotate() {
    this.rotate = true;
    document.getElementById('ability-rotate').style.color = 'blue';
  }
};

const ability = new Ability();

const moveFoward   = () => { if(ability.canMove()) cube.move(30, 30, 0)};
const moveBackward = () => { if(ability.canMove()) cube.move(-30, -30, 0)};
const rotateCW     = () => { if(ability.canRotate()) cube.move(30, -30, 0)};
const rotateCCW    = () => { if(ability.canRotate()) cube.move(-30, 30, 0)};

```

カード読み込み時などに```enableRotate()```を呼ぶことで、rotate,move可能としています。

ソースコードはこちらにあります。
https://github.com/Katsushun89/toio-treasure-hunt

# さいごに
toioで宝探しゲームを作ってみました。
以前、息子と家の中でかくれんぼして遊んだりしたことがありましたが、人が隠れるのは家の中でなかなか難しいので、こういう小さいカードを隠して遊ぶのはアリかなと思って作ってみました。

文言や条件を変えるだけでいろいろルール追加・変更できますので、是非独自のゲームを作って遊んでみてください！