M5StackでPCの中のキャラクター（ユニティちゃん）を走らせた


今回は、9月19日・20日の[M5Stackハッカソン]( https://mashupawards.connpass.com/event/188452/)で作ったものの作り方を書きます。

![0437082cb1c2c55124054d3bb3c3b90e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/50271bec-7137-2ae0-4737-44aabab96a13.png)


## 作ったもの

###作品名
バーチャル・ランニング
https://protopedia.net/prototype/07a9d3fed4c5ea6b17e80258dee231fa

###動画

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【一週一創】先日の <a href="https://twitter.com/hashtag/m5stack?src=hash&amp;ref_src=twsrc%5Etfw">#m5stack</a> ハッカソンで作ったものの作り方を公開します。 <a href="https://twitter.com/hashtag/UnityChan?src=hash&amp;ref_src=twsrc%5Etfw">#UnityChan</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/%E3%83%92%E3%83%BC%E3%83%AD%E3%83%BC%E3%82%BA%E3%83%AA%E3%83%BC%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#ヒーローズリーグ</a> <a href="https://twitter.com/hashtag/%E4%B8%80%E9%80%B1%E4%B8%80%E5%89%B5?src=hash&amp;ref_src=twsrc%5Etfw">#一週一創</a><a href="https://t.co/NT4jInmgqI">https://t.co/NT4jInmgqI</a> <a href="https://t.co/6oDnRVgDIZ">pic.twitter.com/6oDnRVgDIZ</a></p>&mdash; たつや @9/18 cluster広島LT大会 (@tatsuya1970) <a href="https://twitter.com/tatsuya1970/status/1308768970036535297?ref_src=twsrc%5Etfw">September 23, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<br>
M5Stackをポケットに忍ばせ、ランニングすると、M5Stackの加速度センサーがある閾値をこえると、PCの中のキャラクター（ユニティちゃん）が走ります。
ちょっとでもサボると、ユニティちゃんも止まります。


##システム

###環境
- Windows 10
- Unity 2017 4.28f1
- Ruby on Rails

###使ったもの
- [M5Stack Gray](https://www.switch-science.com/catalog/3648/)

###Unityアセット 
- HQ Fighting Animation FREE
- JsonObject

###構成図
![2020-09-22 22.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/72da1ea1-0853-98a1-df77-97fe468c5cc4.png)

M5Stackの加速度センサーがある閾値を超えると「走ってるフラグ１」、止まったら「走ってるフラグゼロ」をRuby on Railsで構築したデータベースMySQLへPOST通信し保存します。

PC上のUnityはフレーム毎にMySQLにGET通信し、今の状態を確認、走ってるフラグが１ならユニティちゃんを走らせ、フラグがゼロならユニティちゃんを止まらせます。

###言い訳
おそらく、こんな非効率なやり方よりももっと良いやり方があるはずだと思います。
走ってるか走ってないかを確認するだけのために、１フレーム毎にGET通信したり、走った走らないでデータベースにPOST書き込みなんて、すぐにHerokuのリクエスト制限超過になります。

しかしながら、私にはあまり通信やデータベースに知識がなく、ハッカソンという限られた時間の範囲内では、このような非効率だけど自分の知識を総動員して一応動くことができるものを作ることを優先にしました。
3年前に自分が構築したRuby on Rails + MySQL のデータベースがHeroku上に生きていたので、その生きているRuby on Railsのプログラムに、ルーティングを付け加えました。

ということで、これはハッカソン用の暫定措置のシステムですので、もっと良い方法がありましたら、ヒントだけでもいただければ幸いです。


##コード
###M5Stack側

ポイントはHttpRequest
注意ポイントを別途こちらに書いてます。

<B>M5Stack UIFlowでHTTP(POST)通信</B>
https://qiita.com/tatsuya1970/items/737b9af78191846d4556

[![Image from Gyazo](https://i.gyazo.com/72d632bfd1aeba193bf0f80d94b655fd.png)](https://gyazo.com/72d632bfd1aeba193bf0f80d94b655fd)

###サーバー側

Ruby on Rails　＋　mySQLをHeroku内に構築しています。（詳細は割愛）

ちょっと古いですが、3年前に私が書いたブログが参考になると思います。
（多分今でも大丈夫だと思います・・・）

- [【Ruby on Rails 備忘録】 WEBサービスを作ろうと思った時、最初にすること](http://tatsuya1970.com/?p=8588)
- [【Ruby on Rails 備忘録】Herokuを使ってWEBに公開する](http://tatsuya1970.com/?p=8667)


<br>

ルーティング

```ruby:routes.rb
Rails.application.routes.draw do

  post '/m5hack/' => 'uchiwas#m5hack_post'
  get '/m5hack/' => 'uchiwas#m5hack_get'

end
```

HTTPリクエストに対する処理

```ruby:MfivesController.rb

class MfivesController < ApplicationController

  require 'net/http'
  require 'uri'
  require 'json'

  def m5hack_post
    # mySQlにMfiveというデータベース、idが500（500という数字に今はない）のところにrunningFlagというカラムを設定している
    message =params[:runningFlag] 
    mfive = Mfive.find_by(id:500)
    mfive.runningFlag = message
    mfive.save
  end

  def m5hack_get
    mfive = Mfive.find_by(id:500)
    render :json => mfive
  end

end
```

###Unity側
ポイントはHTTP通信です。
こちらに記事を書いてます。
<B>UnityでHTTP(GET)通信によるJSONデータ取得</B>
https://qiita.com/tatsuya1970/items/afa299a260d09c4672aa

ユニティちゃんの格闘モーションのアセット
<B>HQ Fighting Animation FREE</B>
についているプログラムにHTTP通信のプログラムを入れただけです。

```csharp:IdleChanger.cs
using UnityEngine;
using System.Collections;

using System.Collections.Generic;

//
// アニメーション簡易プレビュースクリプト
// 2015/4/25 quad arrow
//

// Require these components when using this script
[RequireComponent(typeof(Animator))]

public class IdleChanger : MonoBehaviour
{

    private Animator anim;                      // Animatorへの参照
    private AnimatorStateInfo currentState;     // 現在のステート状態を保存する参照
    private AnimatorStateInfo previousState;    // ひとつ前のステート状態を保存する参照


    // Use this for initialization
    void Start()
    {
        // 各参照の初期化
        anim = GetComponent<Animator>();
        currentState = anim.GetCurrentAnimatorStateInfo(0);
        previousState = currentState;

    }

    void Update()
    {

       StartCoroutine(connect("URL"));       
    }

    IEnumerator connect(string url)
    {
        WWW www = new WWW(url);
        yield return www;
        JSONObject json = new JSONObject(www.text);
        JSONObject runningFlag = json.GetField("runningFlag");

        if (runningFlag.n > 1)
        {
            anim.SetBool("Run", true);
          
        }
        else
        {
            anim.SetBool("Run", false);
        }
    }
}

```