Milkcocoaを使ったインタラクティブサイト「DARTS MAP」の技術解説

Posted: / Tags: GoogleMaps_API



はじめまして。株式会社カヤックでフロントエンドエンジニアを務めております、田島真悟と申します。

Milkcocoaは約1年前から、プライベートでの制作や仕事でのモック作りなどを中心に、よく使わせていただいています。

今回はその中から、MilkcocoaGoogleMaps APIを組み合わせて作った、DARTS MAPというWebサイトの紹介と、その技術的な解説について書こうと思います。

DARTS MAPとは、どんなサイトか?

DARTS MAPには、下記のURLからアクセスすることができます。 スマートフォンとパソコンがあるだけで世界中を飛び回る体験ができるコンテンツです。

手元に2台ともある方は是非体験してみてください。(特にiPhoneのほうが安定して動作します。)

楽しみ方

  1. お手持ちのパソコンとスマートフォンをご用意ください。
  2. DARTS MAPにアクセスするとQRコードが表示されるので、スマートフォンのQRコードリーダーアプリでこれを読み込んでください。
  3. 読み込みが完了するとゲームが開始され、さらにスマートフォンがリモコンに早変わりします!
  4. パソコン画面に写っている少年が操作方法を説明してくれるので、アドバイスを見ながら遊んでみてください。
  5. スマートフォンを振る際は、思いっきり強めに振りましょう。ただし、放り投げないようにくれぐれもご注意ください。

使っているAPI

いかがだったでしょうか? スマートフォンを向けている方角を変えたり、強く振ったりすると、Google ストリートビューのアングルが変わり、まるでその場所にいるかのように 感じていただけたなら嬉しいです。

さて、今回のサイトで用いた技術は主に、MilkcocoaGoogleMaps APIの2つです。

GoogleMaps APIは、こちらのドキュメントに書かれているように、GoogleMapの配色を変えたり、ストリートビューをJavaScriptから操作したりと、自由度高くGoogleMapの機能を扱うことができます。

DARTS MAPでは、GoogleMaps APIの中から、

  • setPano : ストリートビューで表示する場所を指定する
  • setPov : ストリートビュー内で向いている方角を指定する

という2つのメソッドを、スマートフォンの加速度センサから操作できるように実装しています。

実装解説

それでは本題の、実装解説をさせていただきます。

Milkcocoaのセットアップ

まずはMilkcocoaのセットアップです。Milkcocoa本サイトのチュートリアルにあるように、jsファイルを読み込み、dataStoreを作りましょう。

<script src="http://cdn.mlkcca.com/v0.6.0/milkcocoa.js"></script>

<script>
  var milkcocoa = new MilkCocoa("自分のmilkcocoaID.mlkcca.com");
  var dartsDataStore = milkcocoa.dataStore("darts");
</script>

GoogleMaps APIのセットアップ

GoogleMaps APIの方もセットアップしましょう。下記のコードで初期化することができます。

PC側のJavaScript
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>

<script>
// "panorama"はストリートビューを表示する対象のDOM ID名
var panorama = new google.maps.StreetViewPanorama(document.getElementById("panorama"));
var sv = new google.maps.StreetViewService();
</script>

導入 : QRコード読み取り部分

セットアップが完了しました。

それでは、導入部分のQRコードをスマホで読み取らせる部分から解説します。ここで早速、Milkcocoaの機能を使っています。

QRコードを読み取り、そのURLにアクセスしたスマートフォンは、「サイトにアクセスした」という情報を、PCサイトに対して飛ばします。

スマホ側JavaScript
dartsDataStore.send({
  message: "init"
});

PCサイト側では、上記のスマホからのメッセージを待機させておき、受け取るとゲームを開始するようにします。

PC側JavaScript
dartsDataStore.on("send", function(e){
  if(e.value.message === "init"){
    gameStart(); // ゲーム開始
  }
});

ゲーム開始 : ダーツの矢を投げる部分

スマートフォンでは、addEventListenerの引数に"devicemotion"を指定することで、加速度センサを取得することができます。

下記のコードでは、加速度センサのうち、x軸、y軸、z軸のいずれかが閾値(= 10) を超えると、milkcocoaのsendメソッドでPCに対して「投げた!」ということを伝えるようにしています。

※実際のコードでは、addEventListener内にスロットルを入れて処理を間引いたり、加速度の計測にローパスフィルターを加えてノイズ軽減を図ったりしていますが、下記では簡単のため省略してあります。

スマホ側JavaScript
var param = ["x", "y", "z"];
var TH = 10;

window.addEventListener("devicemotion", function(e) {
  for (var i=0; i<param.length; i++) {
    if (Math.abs(e.accelerationIncludingGravity[param[i]]) > TH) {
     // 投げた!
      dartsDataStore.send({
        message: "start"
      });
    }
  }
});

PC側のスクリプトは導入:QRコード読み取り部分と同様、message === "start"sendを受け取ると、キャラクタが矢を投げます。

そして、地図上に矢が当たった国へ、ストリートビューで飛んでいきます。

PC側JavaScript
dartsDataStore.on("send", function(e) {
  if (e.value.message === "start") {
    // 矢を投げるアニメーション
    throwArrow();
  }
});

ストリートビュー操作 : 向いている方角を変える

スマホの向きを変えると、ストリートビュー上で向いている方角もそれに追随して変化する実装です。

今度は、addEventListener"deviceorientation" という引数を指定します。こうすることで、スマホが向いている方角を取得することができます。

下記のコードでは、スマホの向いている方角が変わる度に、PC側へその向きの値を送るという実装になっています。

ゲーム開始 : ダーツの矢を投げる部分と同様、実際には100ms間隔のスロットルをかけることで処理を間引いています。

スマホ側JavaScript
window.addEventListener("deviceorientation", (function(e) {
  dartsDataStore.send({
    message: "rotate",
    heading: e.alpha
  });
});

それでは、PC側で実際にストリートビューの向いている方角を変更する部分のコードです。

PC側JavaScript
var last_heading = 0;

dartsDataStore.on("send", function(e) {
  if (e.value.message === "rotate") {
    panorama.setPov({
      heading: panorama.getPov().heading - (e.value.heading - last_heading),
      pitch: 0
    });
    last_heading = e.value.heading;
  }
});

GoogleMaps APIを使って、ストリートビューの向いている方角を変更するには、setPovメソッドを使います。

上記のコードでは、スマートフォンから現在向いている方角を逐一受け取り、直前の方角との差分だけ、ストリートビュー上の現在の方角から回転させるという処理を行っています。

ストリートビュー操作 : 歩く

最後に、歩く操作についてです。歩くときに腕を動かすように、スマホを強めに振ると、ストリートビュー内でも前に進むことができます。

スマホ側の実装は、ゲームスタート時と同じものです。x, y, z いずれかの加速度センサが閾値を超えると、スマホに強い動きが加えられたと判断し、キャラクターを歩かせます。

そして、PC側でのストリートビューの実装は、以下のようになっています。

PC側JavaScript
dartsDataStore.on("send", function(e){
  if (e.value.message === "walk") {

    // 現在向いている方角から、最も近い方角の道を探す
    heading = panoramaManager.get("pov").heading;
    nextLinks = panoramaManager.get("links");

    nearestDiff = 360;
    for (var i=0; i<nextLinks.length; i++) {
      if (Math.abs(heading - nextLinks[i].heading) < nearestDiff) {
        nearestDiff = Math.abs(heading - nextLinks[i].heading);
        nearestLink = nextLinks[i];
      }
    }
    ///////////////////////////////////////

    // 選ばれた最も近い道へ進む
    panorama.setPov({
      heading: nearestLink.heading,
      pitch: 0
    });

    sv.getPanoramaById(nearestLink.pano, function(data, status){
      panorama.setPano(data.location.pano);
      panorama.setPov({
        heading: nearestLink.heading,
        pitch: nearestLink.pitch
      });
    });
    ///////////////////////////////////////
  }
});

少し複雑ですが、

  1. 現在向いている方角から、最も近い方角の道を探す
  2. 選ばれた最も近い道へ進む

という処理を行っています。

おわりに

いかがだったでしょうか。

このように、普段パソコンで入力している操作を、スマートフォンの加速度センサなどに置き換えると新しい楽しみ方ができるんじゃないかと思います。

スマートフォンだけでなく、Arduino等のデバイスを使えば、温度や照度といった様々なセンサを入力として、見慣れたWebサービスやアプリなどを操作させる、と使い方もできて面白そうですね。