<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>HTML5 Japan Cup 特集 &#8211; HTML5Experts.jp</title>
	<atom:link href="/series/5jcup-2/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>HTML5の技術だけで実装！「YouTubeみたいなWebGLプレーヤー」とは？</title>
		<link>/mitsuhide/10115/</link>
		<pubDate>Tue, 09 Sep 2014 23:50:15 +0000</pubDate>
		<dc:creator><![CDATA[松田光秀]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[FullScreen API]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[jThree]]></category>

		<guid isPermaLink="false">/?p=10115</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (7)この記事では、HTML5 Japan Cup 2014で優秀賞を頂いた「YouTubeみたいなWebGLプレーヤー」で利用されている技術を解説します。 はじめに 「Yo...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (7)</div><p>この記事では、<a href="https://5jcup.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Japan Cup 2014</a>で優秀賞を頂いた「YouTubeみたいなWebGLプレーヤー」で利用されている技術を解説します。</p>

<h2>はじめに</h2>

<p>「<a href="http://jthree.jp/" title="jThree公式サイトで見る" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">YouTubeみたいなWebGLプレーヤー</a>」はコンテンツそのものとは分離された、オープンソースJavaScriptライブラリ「jThree」のプラグインです。オープンソースとして公開していますので、誰でも自身の作品に差し替えてブログなどに掲載することができます。WebGLの描画部分は全てjThreeで管理しています。この記事では、プレーヤーで採用している2つのHTML5 APIとjThreeの概要をご紹介します。</p>

<h2>プレーヤーの機能</h2>

<p>このプレーヤーは、まるで動画のごとくWebGLコンテンツを楽曲付きで再生できます。動画との違いはコンテンツ内のオブジェクトを自由に操作できることです。私が作ったものはカメラのアングルを操作するだけですがJavaScriptでできることなら実装可能です。
Oculus Rift表示に切り替えるボタンが標準搭載されておりVR体験を楽しむこともできます。</p>

<h2>SVGで作成した再生ボタン</h2>

<p>プレーヤーの中央に表示される赤い再生ボタンは、インラインSVGで描画しています。CSSを合わせても600バイト以下で画像よりデータ量を抑えられたのがポイントでした。WebGLに対応しているブラウザは、全てSVGをサポートしているので惜しみなく使うことができます。</p>

<p><a href="http://jthree.jp/" title="jThree公式サイトで見る" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/1.png" alt="1" width="567" height="374" class="alignnone size-full wp-image-10116" srcset="/wp-content/uploads/2014/08/1.png 567w, /wp-content/uploads/2014/08/1-300x197.png 300w, /wp-content/uploads/2014/08/1-207x136.png 207w" sizes="(max-width: 567px) 100vw, 567px" /></a></p>

<p>再生ボタンのHTMLは以下の通りです。</p>

<p></p><pre class="crayon-plain-tag">&lt;svg viewBox="0 0 77 54"&gt;
	&lt;rect fill="#1f1f1f" width="77" height="54" ry="15" /&gt;
	&lt;polygon fill="#fff" points="30.3,39.4 30.3,15.75 53,27.6"/&gt;
&lt;/svg&gt;</pre><p></p>

<h2>Fullscreen APIで全画面表示機能を実現</h2>

<p>プレーヤー右下の全画面表示ボタンを押すと、Fullscreen APIによってブラウザの枠も越えて、PC画面いっぱいにコンテンツが表示されます。プレーヤーはVRデバイスのOculus Riftにも対応しているため、より高い没入感を得るために必須の機能です。</p>

<p><a href="http://jthree.jp/" title="jThree公式サイトで見る" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/2.png" alt="2" width="567" height="319" class="alignnone size-full wp-image-10117" srcset="/wp-content/uploads/2014/08/2.png 567w, /wp-content/uploads/2014/08/2-300x168.png 300w, /wp-content/uploads/2014/08/2-207x116.png 207w" sizes="(max-width: 567px) 100vw, 567px" /></a></p>

<p>全画面表示を切り替えるJavaScriptのコードは以下のとおりです。</p>

<p></p><pre class="crayon-plain-tag">function requestFullscreen( target ) {

	if (target.webkitRequestFullscreen) {
		target.webkitRequestFullscreen(); //Chrome15+, Safari5.1+, Opera15+
	} else if (target.mozRequestFullScreen) {
		target.mozRequestFullScreen(); //FF10+
	} else if (target.msRequestFullscreen) {
		target.msRequestFullscreen(); //IE11+
	} else if (target.requestFullscreen) {
		target.requestFullscreen(); // HTML5 Fullscreen API仕様
	} else {
		alert("ご利用のブラウザはフルスクリーン操作に対応していません");
		return;
	}

}</pre><p></p>

<p></p><pre class="crayon-plain-tag">function exitFullscreen() {

	if ( document.exitFullscreen ) {
		document.exitFullscreen(); //HTML5 Fullscreen API仕様
	} else if ( document.cancelFullScreen ) {
		document.cancelFullScreen(); //Gecko:FullScreenAPI仕様
	} else if ( document.webkitCancelFullScreen ) {
		document.webkitCancelFullScreen(); //Chrome, Safari, Opera
	} else if ( document.mozCancelFullScreen ) {
		document.mozCancelFullScreen(); //Firefox
	} else {
		document.msExitFullscreen();
	}

}</pre><p></p>

<h2>オープンソースJavaScriptライブラリ「jThree」</h2>

<p>今回の作品のベースとなっているオープンソースJavaScriptライブラリ「jThree」についてご紹介します。今回紹介したプレーヤーとそれで再生するコンテンツ（WebGL）は「jThree」を使うことで、jQueryによく似た記法で操作・作成することができます。</p>

<p>「jThree」は8/31に「jThree v2」をリリースしました。これまで外部XMLファイルに記述していたWebGL描画タグをHTMLに埋め込めるようになりました。つまり、jThree v2は「インラインWebGL」を実現したのです。外部ファイルに頼らずHTMLファイル1つだけで描画することが可能で、当然アニメーションさせる前段階の静的な描画処理にはJavaScriptを一行も書く必要がありません。</p>

<p>jQuery関数の代わりにjThree関数を使ってDOMを操作することにより、動的な描画処理ができる点は従来通りです。さらに、これまでjThreeはMMD（.pmx/.vmd）のデータにしか対応していませんでしたが、v2からはプラグインによってあらゆるファイル形式を読み込めるようにもなりました。</p>

<p>jThree v2公開と同時にthree.js用JSON（.json/.js）・DirectX（.x）・Collada（.dae）・STL（.stl）の各ファイルに対応したプラグインを公式で用意しています。OBJ（.obj）とMTL（.mtl）ファイルにも順次対応予定です。</p>

<p></p><pre class="crayon-plain-tag">&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;style&gt;
body {
	position: fixed;
	width: 100%;
	height: 100%;
	margin: 0;
}
&lt;/style&gt;
&lt;script type="text/goml"&gt;
&lt;goml&gt;
	&lt;head&gt;
		&lt;rdr /&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;scene&gt;
			&lt;camera style="camera-far: 8000; position: 0 20 30; lookAt:0 15 0;" /&gt;
			&lt;light type="Amb" /&gt;
			&lt;light type="Dir" style="light-color: #bfbfbf; position:-14 28 60;" /&gt;
			&lt;obj model="town/ゲキド街Ver2.x" style="scale: 10;" /&gt;
		&lt;/scene&gt;
	&lt;/body&gt;
&lt;/goml&gt;
&lt;/script&gt;
&lt;script src="jQuery.js"&gt;&lt;/script&gt;
&lt;script src="jThree.js"&gt;&lt;/script&gt;
&lt;script src="jThree.XFile.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;&lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p><a href="http://jthree.jp/" target="_brank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/39ca614fcbd978cb3b908958ac5476ff.png" alt="街" width="600" height="426" class="alignnone size-full wp-image-10454" srcset="/wp-content/uploads/2014/08/39ca614fcbd978cb3b908958ac5476ff.png 600w, /wp-content/uploads/2014/08/39ca614fcbd978cb3b908958ac5476ff-300x213.png 300w, /wp-content/uploads/2014/08/39ca614fcbd978cb3b908958ac5476ff-207x146.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>

<p>詳しい「jThree」の解説は、私が執筆した<a href="http://codezine.jp/article/corner/522" title="Codezineで解説を見る" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Codezineさんの記事</a>をご覧ください。</p>

<p>※ jThree v2に対応したプレーヤーはありません。公式サイトでの配布も終了するのでプレーヤーを使ってみたい方はCodezineさんの第6回記事からサンプルファイルをDLしてお使いください。
<a href="http://codezine.jp/article/detail/7865" target="_brank" data-wpel-link="external" rel="follow external noopener noreferrer">jThreeプレーヤープラグインの使い方</a></p>

<h2>最後に</h2>

<p>今回は、「jThree」のプラグインとして開発した「YouTubeみたいなWebGLプレーヤー」の要素技術について解説しましたしました。最優秀賞を獲れなかったことは非常に残念ですが、誰もがこのプレーヤーのように手軽にWebで3DCGを楽しめる世界を実現することを目指し、開発を続けていきます。</p>

<p><a href="http://jthree.jp/" title="jThree公式サイトで見る" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/3.png" alt="3" width="567" height="319" class="alignnone size-full wp-image-10118" srcset="/wp-content/uploads/2014/08/3.png 567w, /wp-content/uploads/2014/08/3-300x168.png 300w, /wp-content/uploads/2014/08/3-207x116.png 207w" sizes="(max-width: 567px) 100vw, 567px" /></a></p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編）</title>
		<link>/knockknockjp/10481/</link>
		<pubDate>Tue, 02 Sep 2014 00:00:00 +0000</pubDate>
		<dc:creator><![CDATA[西田慎吾]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[WebSocket]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=10481</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (6)WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編） 前回に引き続きHTML5 Japan Cup 2014にてWebG...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (6)</div><p>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編）</p>

<p><a href="https://html5experts.jp/knockknockjp/10226/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">前回</a>に引き続き<a href="https://5jcup.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">HTML5 Japan Cup 2014</a>にて<strong>WebGL賞</strong>と<strong>優秀賞</strong>をいただいたオンラインレースゲーム、<a href="http://js-racing.knockknock.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">JS-Racing</a>の技術解説をさせていただきます。</p>

<p><img src="/wp-content/uploads/2014/08/img14.jpg" alt="img14" width="630" height="484" class="alignnone size-full wp-image-10498" srcset="/wp-content/uploads/2014/08/img14.jpg 630w, /wp-content/uploads/2014/08/img14-300x230.jpg 300w, /wp-content/uploads/2014/08/img14-207x159.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>サーバサイドの使用技術</h2>

<p>サーバサイドの技術として<a href="http://nodejs.jp/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Node.js</a>を使用しています。Node.jsはサーバーサイドで動作するJavaScriptで、<strong>ノンブロッキングI/Oというモデルを採用しています。非同期処理でデータベースへのアクセスとWebページの表示を別々に行ってくれる</strong>ので、ストレスなく大量のページの表示が出来ます。また、Socket.ioというライブラリを扱うことで、WebSocketを使用したリアルタイム通信を実現するができます。</p>

<p>Node.jsでWebアプリケーションを構築する場合、実験的にローカルのみの開発の場合は問題ありませんが、公開するとなると、Node.jsをインストールして実行できるサーバが必要になります。そのためには共有サーバのレンタルではなく、<strong>管理者権限 (root) が付与される専用サーバや、仮想専用サーバ（VPS）のレンタルが必要</strong>になると思います。管理者権限のため自由に環境をセットアップする事ができるために、そのWebアプリケーションに合わせた環境構築が可能になります。</p>

<h3>ExpressによるWebアプリケーションフレームワークの利用</h3>

<p>Node.jsで作成したWebアプリケーションの場合、リクエストURIの解析からファイルの配信など、HTTPサーバの機能を実装しなくてはいけません。これらの<strong>基本機能が備わったWebアプリケーションフレームワークを利用することで、非常に手軽にWebアプリケーションを作成</strong>できます。今回は、多数開発されているWebフレームワークのなかでも、有名で多く利用されている<a href="http://expressjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Express</a>を利用しました。</p>

<p></p><pre class="crayon-plain-tag">var express = require("express");
var app = express();
// HTMLエンジンとしてjadeを使用
app.set("view engine", "jade");
app.set("views", __dirname + "/views");
app.use(express.static(__dirname + "/public"));
// js-racing.knockknock.jp/にアクセスがあった場合、
// /views/index.jadeに「title=JS Racing」と「version=ver1.2」の値を渡して、HTMLを表示
app.get("/", function(req, res) {
    res.render("index", {
        title: "JS Racing",
        version: "ver1.2"
    });
});
// js-racing.knockknock.jp/controller.htmlにアクセスがあった場合、
// /views/controller.jadeに「title=JS Racing」と「version=ver1.2」と「id=URLパラメータのidの値」の値を渡して、HTMLを表示
app.get("/controller.html", function(req, res) {
    res.render("controller", {
        title: "JS Racing",
        version: "ver1.2",
        id: req.query.id
    });
});
app.set("port", process.env.PORT || 3000);
var server = require("http").createServer(app);
server.listen(app.get("port"), function(){
    console.log("Express server listening on port " + app.get("port"));
});</pre><p></p>

<p>22行目の<code>req.query.id</code>は<code>http://js-racing.knockknock.jp:3000/controller.html?id=000000</code>として渡された、URLパラメータのidの値が参照できます。この値は、ソケット通信時に発行されたソケットIDの値で、PCから発行されたスマフォ用のURL（QRコードか短縮URL）にURLパラメータとして付加されたもので、この値を元にPCとスマートフォンとのペアリングを行います。</p>

<p><strong>ExpressはHTMLのテンプレートエンジンとして<a href="http://jade-lang.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Jade</a>か、<a href="http://embeddedjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ejs</a>を選択</strong>することができます。Jadeはインデントが必須です。閉じタグを省略できる代わりに、DOMの入れ子構造に沿って適切にインデントを使用する必要があります。基本的な記法がHTMLとは違うために、HTMLに親しんだマークアップエンジニアからすれば、慣れるまで違和感があるものだと思います。ejsはJadeとは違い、基本的な記法はHTMLをベースにしていますので、ローカルでくみ上げたHTMLをejsに組み込むことが容易です。今回はより楽にコード量を少なくHTMLを構築したいという点で、閉じたタグなしで記述できるJadeを選択しています。</p>

<p></p><pre class="crayon-plain-tag">// オープニングタイトル表示部分
section#sceneOpening.scene-opening(style="display: none;")
    div.scene-opening__inner
        div.scene-opening__box5
            h1.scene-opening__ttl
                // expressから受け取ったパラメータ、titleの値を挿入
                span.scene-opening__ttl__txt #{title}
                    br
                // expressから受け取ったパラメータ、versionの値を挿入
                span.scene-opening__ttl__txt2 &amp;nbsp;#{version}</pre><p></p>

<p>Jadeはこのようにインデントによって、要素の入れ子構造を定義しています。そのため閉じタグが不要で、<strong>HTMLを非常に簡略化</strong>して記述することが可能になります。HTMLを簡略化できるだけがJadeの特徴ではありません。<strong>HTMLをコンポーネント化して再利用</strong>したり、条件分岐をさせたり、繰り返し処理をさせたり、これまでサーバサイドで行っていたようなことがNode.jsで可能になります。ちなみにCSSはSass（Compass）を使い、記法にはBEMという命名規則を採用しています。</p>

<h3>Socket.ioによるリアルタイム通信</h3>

<p>車の同時走行と、スマートフォンからの車の操作を実現するためには、ブラウザとサーバ双方から、任意のタイミングでデータを送受信する必要があります。このリアルタイム通信を実現するために、<a href="http://socket.io/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Socket.io</a>を利用しています。Socket.ioは<strong>WebSocketなどのリアルタイム通信技術をラップして、シンプルなAPIを提供しているため、通信部分の煩雑さを意識することなく、リアルタイム通信を簡単に構築</strong>することができます。</p>

<p>スマートフォンからの車の操作を実現するために、接続時に発行されたソケットIDを共有することで、スマートフォンとPCをペアリングして相互通信しています。サーバを介しての通信なので、若干のタイムラグが発生する懸念もあったのですが、現状ではタイムラグを感じることはありませんでした。環境に依存することですので、あくまで今回の場合はということですが。</p>

<p></p><pre class="crayon-plain-tag">var socketArr = [];
io.sockets.on("connection", function(socket){
    // Socket.IDをPCに送信
    socket.emit("emit_id_form_server", socket.id);
    // PCから車の状態を受信
    socket.on("emit_carcondition_form_client", function(data){
        // 受信した車の状態
        var info = {
            id: socket.id,
            name: data.name,
            x: data.x,
            y: data.y,
            bodyAngle: data.bodyAngle,
            wheelAngle: data.wheelAngle,
            speed: data.speed,
            colorBody: data.colorBody,
            colorWing: data.colorWing,
            colorDriver: data.colorDriver
        };
        // 接続しているクライアントごとの情報を更新
        var flg = true;
        var i = 0, max;
        for (i = 0, max = socketArr.length; i &lt; max; i = i + 1) {
            if (socketArr[i].id == info.id) {
                socketArr[i] = info;
                flg = false;
            }
        }
        if (flg) {
            socketArr.push(info);
        }
    });
    // スマートフォンからの操作情報を受信
    socket.on("emit_controller_data_form_client", function(data){
        var id = data.id;
        var event = data.event;
        var value = data.value;
        var flg = false;
        var sockets = io.sockets.sockets;
        var i = 0, max;
        for (i = 0, max = sockets.length; i &lt; max; i = i + 1) {
            // ソケットIDが一致したクライアントに操作情報を送信
            if (sockets[i].id == id) {
                sockets[i].emit("emit_controller_data_from_server", {
                    id: id,
                    event: event,
                    value: value
                });
                flg = true;
            }
        }
        // ソケットIDが一致したクライアントが存在しなかった場合はスマートフォンに接続解除イベントを送信
        if (!flg) {
            socket.emit("emit_disconnect_client_from_server");
        }
    });
    // 接続しているクライアントの情報を1秒間に3回、接続しているクライアント全てに送信
    setInterval(function(){
        socket.emit("emit_other_carcondition_from_server", socketArr);
    }, 1000 / 3);
});</pre><p></p>

<p>接続している全てのクライアントに、接続している全てのクライアントの情報を送信するイベントは、ネットワークの負荷を考えて、1秒間に3回と制限をかけています。つまり3FPSのタイミングで同期をとることになりますが、クライアント側では30FPSでゲームが進行しているために、タイムラグが発生してしまいます。タイムラグによって発生する違和感をなくすために、クライアント側ではサーバ側から配信されるクライアント情報を元に、前回配信された情報との差分を10で割った値を算出して、クライアント側の1FPS毎の値として反映させ、違和感を解消しています。</p>

<h3>MongoDBでラップタイムの保存と走行データの保存</h3>

<p>ラップタイムを保存したり、走行データを保存するのにデータベースとして<a href="http://www.mongodb.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">MongoDB</a>を利用しています。MongoDBは、<strong>オープンソースのドキュメント指向データベース</strong>です。RDBMSのようにレコードをテーブルに格納するのではなく、ドキュメントと呼ばれる構造的データをオブジェクト形式でデータを管理します。
ちなみにNode.jsから<a href="http://mongoosejs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Mongoose</a>を利用し、MongoDBに接続しています。Mongooseでは、Schemaインスタンスを通してModelを定義する事ができます。以下のようなオブジェクト形式でデータを管理出来るのが、MongoDBの特徴です。</p>

<p></p><pre class="crayon-plain-tag">var UserSchema = new mongoose.Schema({
    id:String, // ソケットID
    name:String, // 名前
    date:String, // 登録日
    time:Number, // ラップタイム
    comment: String, // コメント
    color: {
        body: String, // ボディカラー
        wing: String, // ウィングカラー
        driver: String // ドライバーカラー
    },
    runningPath: Array // 走行データ
});
var Users = db.model("user", UserSchema);</pre><p></p>

<p>走行データは1秒間に30回、車の位置と角度を記録した配列ですので、全てのユーザーの分だけ保存すると、データ量が肥大してしまう可能性があります。データ量を押さえるために、ラップタイムでソートして10位圏外の走行データは保持していません。</p>

<p>サーバサイドではNode.jsのおかげで、Webアプリケーションを構築する環境がとても整ってきていると思います。
基本的な言語はJavaScriptですので、サーバサイドもフロントエンドエンジニアが押さえるべき領域になっているのではと思います。</p>

<h2>その他の技術的トピック</h2>

<p>サーバサイド、クライアントサイドの技術それぞれの紹介を軸として、説明させていただきましたが、これ以外にもいくつか工夫した、技術的なポイントがありますので、紹介します。</p>

<h3>コースデータの共有</h3>

<p>3D表現を利用するために使用したthree.jsと、ゲームエンジンとして使った2D物理エンジンBox2DJSで、コースデータを共有するために2次元配列を使用しました。各値には数値を格納して、数値によってthree.jsでは壁、道路、芝、タイヤ、木、等の3Dモデルが配置され、Box2DJSでは3Dモデルの形状に沿った障害物を配置します。ちなみに開発当初、コースエディット機能や、SNSでコース共有機能等を考えていましたので、テキストデータとして扱いやすい2次元配列をコースデータとして採用したという経緯があります。</p>

<p></p><pre class="crayon-plain-tag">module imjcart.logic.map.value {
    export class MapConst {
        // コースデータ用の2次元配列
        static MAP:any = [           
　　　　　　[1,1,1,1,1,1,1,1,1,　〜省略〜　1,1,1,1,1,1,1,1,1,1,1], 
　　　　　　[1,4,4,4,4,4,4,4,4,　〜省略〜　4,4,4,4,4,4,4,4,4,4,1],
           〜省略〜　　　　　　
　　　　　　[1,1,1,1,1,1,1,1,1,　〜省略〜　1,1,1,1,1,1,1,1,1,1,1]
        ]
        // コースデータ配列内の各値が、何を表しているかの定数
        static MAP_KEY_NONE:number = 0; // アスファルト
        static MAP_KEY_WALL:number = 1; // 外壁
        static MAP_KEY_BLOCK:number = 2; // ブロック
        static MAP_KEY_TIRE:number = 3; // タイヤ
        static MAP_KEY_GRASS:number = 4; // 芝
        static MAP_KEY_TREE:number = 5; // 木
        static MAP_KEY_CAR_START_POSITION:number = 6; // 車のスタート位置
        static MAP_KEY_LAP_MEDIAN_CENTER_02:number = 7; // ゴールライン（逆走制御）
        static MAP_KEY_LAP_MEDIAN_CENTER_01:number = 8; // ゴールライン（逆走制御）
        static MAP_KEY_LAP_START_POINT:number = 9; // ゴールライン
        static MAP_KEY_SAND:number = 10; // 砂地
    }
}</pre><p></p>

<p>ただ、このような膨大な量の2次元配列を、テキストエディタで作成、編集するのは非常に非効率だと考えて、途中からExcelによって管理する方法に切り替えました。Excelでは条件付き書式を設定して、セルの値によって、わかりやすいように色づけするように設定しています。データ書き出しの際には、ExcelからCSVデータとしてテキストデータを書き出して、CSVデータをテキストエディタで置換して2次元配列にしています。</p>

<p><img src="/wp-content/uploads/2014/08/img12.gif" alt="img12" width="630" height="300" class="alignnone size-full wp-image-10487" /></p>

<h3>コースの装飾</h3>

<p>コースは直線と直角だけではなく、カーブ等の曲線も再現できなくてはいけません。2次元配列をコースデータとして利用する場合は、この点を補完する必要があります。また、コースというのは大抵、両脇のシケインとの境目にラインが引いてあります。こういったアスファルトや芝生といった要素以外の装飾を、周りの要素の配置条件に応じて追加することで、よりコースらしい外観を作る事ができます。下のキャプチャが装飾やカーブの補完をかけている物と、コースデータをそのまま表示したものとの違いです。</p>

<p><img src="/wp-content/uploads/2014/08/img13.jpg" alt="img13" width="630" height="254" class="alignnone size-full wp-image-10492" srcset="/wp-content/uploads/2014/08/img13.jpg 630w, /wp-content/uploads/2014/08/img13-300x120.jpg 300w, /wp-content/uploads/2014/08/img13-207x83.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>まとめ</h2>

<p>以上が今回作成したJS-Racingの主な技術解説になります。Webアプリケーションを構築するには、今回解説したように多くの技術が必要となります。ご紹介した技術は、たくさんある中から必要なものを取捨選択した結果ですので、当然コンテンツが変われば、必要となる技術も変わります。このコンテンツで使用した主な技術の全体図をまとめました。</p>

<p><img src="/wp-content/uploads/2014/08/img02.jpg" alt="使用技術概要" width="630" height="400" class="alignnone size-full wp-image-10250" srcset="/wp-content/uploads/2014/08/img02.jpg 630w, /wp-content/uploads/2014/08/img02-300x190.jpg 300w, /wp-content/uploads/2014/08/img02-207x131.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>オンラインレースゲームというシンプルな内容のコンテンツですが、プラットフォームとしてWebブラウザを使用している点に注目していただけると嬉しいです。今までご紹介した技術は、オンラインゲームを作るだけの技術ではなく、Webコンテンツを作る上で、大きな可能性を持っている技術になります。私はゲームを作る上でこれらの技術を利用していますが、Web上の様々なサービスと連携をとることで、もっと広がりを持つコンテンツを作ることができると思います。ぜひ皆さんも、HTML5とJavaScript（クライアントサイド、サーバサイド含む）を使って、Webアプリケーションを作ってみてください。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（前編）</title>
		<link>/knockknockjp/10226/</link>
		<pubDate>Fri, 29 Aug 2014 00:00:58 +0000</pubDate>
		<dc:creator><![CDATA[西田慎吾]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=10226</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (5)今回はHTML5JapanCup2014にてWebGL賞と優秀賞を受賞したオンラインレースゲーム、JS-Racingの技術解説を書かせていただきます。 このコンテンツは...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (5)</div><p>今回は<a href="https://5jcup.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">HTML5JapanCup2014</a>にて<strong>WebGL賞</strong>と<strong>優秀賞</strong>を受賞したオンラインレースゲーム、<a href="http://js-racing.knockknock.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">JS-Racing</a>の技術解説を書かせていただきます。</p>

<p><img src="/wp-content/uploads/2014/08/img03.jpg" alt="JS-Racing" width="630" height="397" class="alignnone size-full wp-image-10255" srcset="/wp-content/uploads/2014/08/img03.jpg 630w, /wp-content/uploads/2014/08/img03-300x189.jpg 300w, /wp-content/uploads/2014/08/img03-207x130.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>このコンテンツは<strong>WebGLの3D表現を活かした3Dレースゲーム</strong>です。<br>
また、<strong>WebSocketを使用しサーバを介して、複数のクライアントでの同時走行が可能なオンラインゲーム</strong>になっています。同時に、ソケット通信時に発行されるソケットIDをPCとスマートフォンで共有することで、<strong>スマートフォンからPC上の車を操作することも可能</strong>です。</p>

<p><img src="/wp-content/uploads/2014/08/img04.jpg" alt="JS-Racing" width="630" height="500" class="alignnone size-full wp-image-10264" srcset="/wp-content/uploads/2014/08/img04.jpg 630w, /wp-content/uploads/2014/08/img04-300x238.jpg 300w, /wp-content/uploads/2014/08/img04-207x164.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>クライアントサイドの使用技術</h2>

<p>クライアントサイドの構築において、目的・用途に応じて使用した言語やライブラリに関して解説します。</p>

<h3>TypeScriptによるクラス設計</h3>

<p>クライアントサイドのメインとなるロジックを<a href="http://www.typescriptlang.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">TypeScript</a>を使用して設計しました。TypeScriptはマイクロソフトによって開発されたフリーでオープンソースのプログラミング言語です。<strong>大規模JavaScriptアプリケーションに向けて開発</strong>されたTypeScriptは、これまでのJavaScriptにはない以下の機能を有しています。</p>

<ul>
    <li><strong>型注釈とコンパイル時の型チェック</strong></li>
    <li><strong>クラス</strong></li>
    <li><strong>インターフェイス</strong></li>
    <li><strong>モジュール</strong></li>
</ul>

<p>TypeScriptはコンパイルして最終的にJavaScriptに出力することができます。今回のように多くの機能の実装が必要になるWebアプリケーションでは、クラスベースのオブジェクト指向言語的な特徴を持つTypeScriptは、設計しやすく非常に有効なものになります。</p>

<p>ActionScript3と同じように、1つのTSファイル（TypeScriptファイル）にクラスを1つだけ記述して、ファイル名とクラス名を一致させました。また、モジュール毎にディレクトリを作成して、クラスを格納しています。これにより<strong>機能毎にモジュールとクラスを整理</strong>する事ができ、再利用しやすく見やすいコードになりました。最終的には、クラス毎に作成したTSファイルを、クラス毎のJavaScriptファイルに出力（コンパイル）し、<a href="http://gruntjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Grunt</a>で結合、圧縮して、実際に読み込むJavaScriptファイルにしています。</p>

<p><img src="/wp-content/uploads/2014/08/img05.gif" alt="img05" width="630" height="670" class="alignnone size-full wp-image-10419" /></p>

<p>今回の場合、モジュールの分け方は、まず表示要素とロジックにモジュールを分けました。表示要素はゲームの各シーンや、3D描画、画面下部のランキング表示というように、表示要素単位でさらにモジュールを細分化していきます。ロジックは、イベントや値管理、定数、ユーティリティ、コースデータ管理、物理演算、リアルタイム通信といった、機能単位でモジュールを細分化していきます。このようにモジュールを分けていくことで、大規模なコンテンツ開発の際には、<strong>各クラスの責任範囲が明確化でき、バグが発生した際にも、原因を特定しやすく、さらには仕様変更にも強く</strong>なります。</p>

<p>TypeScriptは大規模開発においては、非常に設計しやすく、クラスベースのオブジェクト指向言語のメリットを最大限に享受できるものだと思います。ただその分、設計における手間と、なによりコード記述量が多くなります。中規模以下の案件では、最低限の設計で手軽に構築できる<a href="http://coffeescript.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">CoffeeScript</a>も、よい選択肢ではないかと思います。</p>

<h3>Box2DJSを使った2D物理演算</h3>

<p>車を走らせたり、障害物と衝突したりといった、ゲームの中核となるロジックは<a href="http://box2d-js.sourceforge.net/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Box2DJS</a>を使用しています。Box2DJSは、<strong>質量・速度・摩擦をシミュレーションするJavaScriptの2D物理演算エンジン</strong>です。</p>

<p>表現方法自体は3Dですが、物理演算エンジンは2Dを使用しました。今回のようなシンプルなゲームを作るには、3Dの物理演算エンジンより、2Dの物理演算エンジンの方が、ゲームバランスや操作感において向いていると感じます。コンシューマーゲームなどの本格的なゲームとなると、3D物理演算エンジンによる処理は、必要不可欠なものだとは思いますが、その分、マシンへの負荷も高くなります。</p>

<p>物理演算に関しては、別途サンプルを作成して、チューニングしていきました。ゲームの中核となる部分ですので、まずこのサンプルで楽しいと思えるかどうかで、最終的なゲームのゴールが見えてくると思います。可能な限りゲーム性向上のためのチューニングしていくことが大切です。</p>

<p><a href="http://www.knockknock.jp/sample/20140127/02/index.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/img06.gif" alt="img06" width="630" height="473" class="alignnone size-full wp-image-10421" /></a></p>

<p>初期段階のモックアップのイメージですが、まずはこのようにBox2Dを使って、2Dレースゲームを構築しました。この2Dレースゲームの情報を3D表示部分や情報部分（スピードメーター等）やコースデータ管理ロジック、リアルタイム通信ロジックに渡します。</p>

<p>物理演算クラス<code>imjcart.logic.physics.Physics</code>にて、マップ情報を元に<code>new Car</code>で車インスタンスを生成し、車の状態が変更したイベント<code>CHANGE_CAR_CONDITION_EVENT</code>をキャッチして、イベントを発行します。</p>

<p></p><pre class="crayon-plain-tag">public createCar() {
    // マップ情報を元に車を生成
    var x = 0;
    var y = 0;
    var i, j, max, max2;
    for (i = 0, max = imjcart.logic.map.value.MapConst.MAP.length; i &amp;amp;amp;lt; max; i = i + 1) {
        for (j = 0, max2 = imjcart.logic.map.value.MapConst.MAP[i].length; j &amp;amp;amp;lt; max2; j = j + 1) {
            if (imjcart.logic.map.value.MapConst.MAP[i][j] == imjcart.logic.map.value.MapConst.MAP_KEY_CAR_START_POSITION) {
                y = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * i;
                x = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * j;
                break;
            }
        }
    }
    this._car = new Car(this._context, this._world, x, y);
    // 車状態変更イベント
    this._car.addEventListener(event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, (evt) =&amp;amp;amp;gt; {
        this.dispatchEvent(imjcart.logic.physics.event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, {
            x: evt.x,
            y: evt.y,
            bodyAngle: evt.bodyAngle,
            wheelAngle: evt.wheelAngle,
            speed: evt.speed,
            power: evt.power,
            gear: evt.gear,
            direction: evt.direction
        });
    });
}</pre><p></p>

<p><code>imjcart.logic.physics.Car</code>クラスでは、<code>update</code>関数が実行されると、入力されている値をホイールに反映し、車の状態に変化を与えます。変化した車の情報を付加して、車の状態が変更したイベント<code>CHANGE_CAR_CONDITION_EVENT</code>を発行します。</p>

<p></p><pre class="crayon-plain-tag">public update() {
    // ホイールに力を適応
    var i = 0, max;
    for (i = 0, max = this._frontWheels.length; i &lt; max; i = i + 1) {
        var wheel = this._frontWheels[i];
        var direction = wheel.GetTransform().R.col2.Copy();
        direction.Multiply(this._enginePower);
        wheel.ApplyForce(direction, wheel.GetPosition());
    }
    // ホイールと車をつなぐジョイント部分に角度を適応
    for (i = 0, max = this._frontWheelJoints.length; i &lt; max; i = i + 1) {
        var wheelJoint = this._frontWheelJoints[i];
        var angleDiff = this._steeringAngle - wheelJoint.GetJointAngle();
        wheelJoint.SetMotorSpeed(angleDiff * this._steerSpeed);
    }
    // 車状態変更イベントの発行
    var position = this._body.GetPosition();
    var velocity = this._body.GetLinearVelocity();
    var speedX = Math.abs(velocity.x);
    var speedY = Math.abs(velocity.y);
    var speed = 0;
    if (speedX &lt; speedY) {
        speed = speedY;
    } else {
        speed = speedX;
    }
    this.dispatchEvent(imjcart.logic.physics.event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, {
        x: position.x,
        y: position.y,
        bodyAngle: this._body.GetAngle(),
        wheelAngle: this._frontWheelJoints[0].GetJointAngle(),
        speed: speed,
        power: this._enginePower,
        gear: this._gear,
        direction: this._engineDirection
    });
}</pre><p></p>

<p><code>dispatchEvent</code>メソッドは、イベントを発行する<code>lib.event.EventDispacher</code>クラス（オリジナルで作成）に定義されたメソッドです。表示要素のクラスはこの<code>lib.event.EventDispacher</code>クラスを継承しています。</p>

<h3>three.jsの3D表現</h3>

<p>WebGLを使った3D表示部分には<a href="http://threejs.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">three.js</a>を使用しています。three.jsは、<strong>WebGLを扱うライブラリとしては、最もよく使われているJavaScriptライブラリ</strong>です。</p>

<p><a href="http://www.blender.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Blender</a>というオープンソースの3次元コンピュータグラフィックスソフトウェアを使って、3Dモデルの作成を作成し、three.jsで読み込んで表示しています。Blenderで作成する3Dモデルデータ（今回のモデルデータはOBJ形式）は、ジオメトリ（形状）とUVテクスチャのみで、three.jsを使って、質感などの調整をしています。</p>

<p><img src="/wp-content/uploads/2014/08/img07.jpg" alt="img07" width="630" height="380" class="alignnone size-full wp-image-10422" srcset="/wp-content/uploads/2014/08/img07.jpg 630w, /wp-content/uploads/2014/08/img07-300x180.jpg 300w, /wp-content/uploads/2014/08/img07-207x124.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>また、今回のように実行環境が制限しづらいWebアプリケーションでは、なるべく多くのユーザーが利用できるように、マシンへの負荷は極力減らさないといけません。特にレースゲームは、現在走っているコースの先が見える必要があり、視野を広くしなければならないために、処理するデータ量が増え、より負荷がかかってしまいます。この<strong>負荷軽減</strong>のために、以下のことを考慮しています。</p>

<ol>
    <li><strong>ポリゴンが少なくても成り立つデザイン</strong></li>
    <li><strong>影をつけない</strong></li>
    <li><strong>ジオメトリ（形状）の結合</strong></li>
    <li><strong>負荷の少ないマテリアル（質感）を選択</strong></li>
</ol>

<p>1つめの<strong>ポリゴンが少なくても成り立つデザイン</strong>に関しては、下のタイヤのサンプルで、左のタイヤはポリゴン数を極端に減らしていますので、光や深度の計算が少なくなり、マシンへの負荷も小さくなります。右のタイヤはリアルなタイヤを再現したために、ポリゴン数も多く、マシンへの負荷も大きくなります。配置する量が少数ならそれほど問題になりませんが、コースデータに沿って多数配置する障害物ですので、マシン負荷は大きくなります。ただ、ポリゴン数が少ない分、リアルな表現からは遠く離れてしまっています。コース全体のデザインも含めてですが、リアルな表現を求めないポップなデザインを採用することで、低ポリゴンでも違和感のないようにしています。</p>

<p><img src="/wp-content/uploads/2014/08/img10.jpg" alt="img10" width="630" height="247" class="alignnone size-full wp-image-10425" srcset="/wp-content/uploads/2014/08/img10.jpg 630w, /wp-content/uploads/2014/08/img10-300x117.jpg 300w, /wp-content/uploads/2014/08/img10-207x81.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>2つめの<strong>影をつけない</strong>ですが、下のキャプチャを見ていただければ、影がない左側のキャプチャと影がある右側のキャプチャでは、3D空間としての説得力にだいぶ違いが出てしまっているかと思います。ここは苦渋の決断ですが、影をつけることはthree.jsではとても負荷のかかる処理なので、より多くのユーザにストレスなく遊んでもらうためにも影をつけない方を採用しました。</p>

<p><img src="/wp-content/uploads/2014/08/img08.jpg" alt="img08" width="630" height="227" class="alignnone size-full wp-image-10423" srcset="/wp-content/uploads/2014/08/img08.jpg 630w, /wp-content/uploads/2014/08/img08-300x108.jpg 300w, /wp-content/uploads/2014/08/img08-207x74.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>ちなみに影を出すには、レンダラーの<code>shadowMapEnabled</code>を<code>true</code>にして、光源の<code>castShadow</code>を<code>true</code>にします。そして影を作る側の物体の<code>castShadow</code>を<code>true</code>にして、影を受ける側の物体の<code>receiveShadow</code>を<code>true</code>にします。デフォルトでは<code>false</code>のため影が出ません。</p>

<p></p><pre class="crayon-plain-tag">// レンダラー
renderer.shadowMapEnabled = true;
// 光源
light.castShadow = true;
// 影を作る側
mesh.castShadow = true;
// 影を受ける側
mesh.receiveShadow = true;</pre><p></p>

<p>3つめの<strong>ジオメトリの結合</strong>に関してですが、WebGLコンテンツの様にGPUを使用するコンテンツは、ジオメトリの数だけGPUに対してドローコール（描画命令）をします。このドローコールの回数はパフォーマンスに大きく影響します。ジオメトリを<code>THREE.GeometryUtils.merge(geometry, mesh)</code>メソッドで結合することで、不要なドローコールの発生を少なくすることができます。注意点としては、結合したものは個別に動かすことや、マテリアルを個別に設定することはできませんので、今回は壁やコースなど、個別に動くことのない、大量に描画する必要のある要素に対してジオメトリの結合をしています。</p>

<p></p><pre class="crayon-plain-tag">var geometry = new THREE.Geometry(); // 空のジオメトリを作成
var meshArr = [];
// モデルデータとマテリアルを読み込む
var loader = new THREE.OBJMTLLoader();
loader.load("models/block03/block03.obj", "models/block03/block03.mtl", (object) =&gt; {
    object.traverse(function (child) {
        if (child instanceof THREE.Mesh) {
            child.material = new THREE.MeshLambertMaterial(child.material);
            child.material.ambient = new THREE.Color(imjcart.display.main.view3d.value.View3dConst.AMBIENT_COLOR);
            meshArr.push({
                mesh: child,
                material: child.material
            });
        }
    });
    // 読み込んだモデルデータをマップデータに沿って、クローンして配置。
    var i, j, max, max2;
    for (i = 0, max = imjcart.logic.map.value.MapConst.MAP.length; i &lt; max; i = i + 1) {
        for (j = 0, max2 = imjcart.logic.map.value.MapConst.MAP[i].length; j &lt; max2; j = j + 1) {
            if (imjcart.logic.map.value.MapConst.MAP[i][j] == imjcart.logic.map.value.MapConst.MAP_KEY_BLOCK) {
                var tagX = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * j + (imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE / 2);
                var tagY = 1;
                var tagZ = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * i + (imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE / 2);
                var mesh = meshArr[1].mesh.clone();
                mesh.position.set(tagX, tagY, tagZ);
                THREE.GeometryUtils.merge(geometry, mesh); // 空のジオメトリにマージして結合していく
            }
        }
    }
    this._block = new THREE.Mesh(geometry, meshArr[1].material);
    this._scene.add(this._block);
});</pre><p></p>

<p>最後に4つめの<strong>負荷の少ないマテリアル（質感）の選択</strong>は、表面の質感を上げるマテリアルを選択すると、その分マシンへの負荷が上がるということです。マテリアルの種類は代表的なもので、以下のメリットがあります。</p>

<ol>
<li><strong>MeshBasicMaterial</strong> : 光の影響を受けない
<li><strong>MeshLambertMaterial</strong> : 影や光の反射などを描画できる（ランバート反射モデル）
<li><strong>MeshPhongMaterial</strong> : 影や光の反射などをより綺麗に描画できる（フォンシェーディング）
</ol>

<p>マシンへの負荷に関しては1、2、3の順に次第に高くなります。選択したマテリアルの違いもマシン負荷への影響は大きいですが、マテリアルにバンプマップを使うかどうかもマシン負荷への影響は大きくなります。バンプマップは表面に細かな凹凸を表現します。下のキャプチャはアスファルトにバンプマップを適応したもの（右）と、適応していないもの（左）の違いです。表現力を上げるためには、バンプマップを採用したいところですが、ここでもマシン負荷を考慮してバンプマップを使っていません。</p>

<p><img src="/wp-content/uploads/2014/08/img09.jpg" alt="img09" width="630" height="400" class="alignnone size-full wp-image-10424" srcset="/wp-content/uploads/2014/08/img09.jpg 630w, /wp-content/uploads/2014/08/img09-300x190.jpg 300w, /wp-content/uploads/2014/08/img09-207x131.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>リアルな表現に近づければ近づけるほど、マシンへの負荷が増えてしまいます。ある程度の表現力は確保しながら、どれだけ負荷を減らせるかの調整は、これくらいのスペックなら問題なく表示できるようにしたいというターゲットとなるマシンを決めて、そのマシンで最低限確保したいフレームレートを決めます。あとは都度、フレームレートを確認しながら調整するということの繰り返しになります。マシンスペックだけでなく、ブラウザによっても表示速度に差異があることを意識していなければなりません。</p>

<h3>HTML5のAPIによる新しい表現力</h3>

<p>WebGL以外のHTML5の要素も、それぞれの特徴にあわせて適宜使用しています。</p>

<ul>
    <li>Canvas：コースマップ（コース縮尺図）</li>
    <li>SVG：スピードメーター</li>
    <li>WebFont：タイトルやテキスト全般</li>
    <li>CSS3：角丸やドロップシャドウやボタンデザイン</li>
</ul>

<p><img src="/wp-content/uploads/2014/08/img11.jpg" alt="img11" width="630" height="336" class="alignnone size-full wp-image-10446" srcset="/wp-content/uploads/2014/08/img11.jpg 630w, /wp-content/uploads/2014/08/img11-300x160.jpg 300w, /wp-content/uploads/2014/08/img11-207x110.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>WebGLによる3D表示をしているCanvasの上に、各要素を配置していますが、上に乗っかっている要素を動かしたり、形状を変更させる場合には、背景に不透明な物を敷くなどの工夫が必要になります。そうしないと上に乗っかっている要素に変更があるたびに、下のCanvas全体まで、不要な再描画処理がかかってしまい、描画のパフォーマンスを著しく低下させてしまいます。</p>

<h2>まとめ</h2>

<p>以上が今回作成したJS-Racingで利用した、主なクライアントサイド技術になります。</p>

<p>3D表現として利用したWebGLは、IE11の対応によって最新のモダンブラウザでは、ほぼ実行可能な環境が揃ってきていると思います。</p>

<p>ユーザーのマシンスペックや、WebGL対応ブラウザの普及率を考えると、まだある程度ユーザーをしぼる必要がありますが、最近では話題を呼んでいる3Dコンテンツも次第に増えてきたように感じます。</p>

<p>次回は<strong>サーバサイドの使用技術</strong>と、その他の<strong>技術トピック</strong>に関して解説する予定です。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>Angry Birdsの3D版!?「Enraged Fowls」の技術解説（物理エンジン編）</title>
		<link>/technohippy/10203/</link>
		<pubDate>Thu, 28 Aug 2014 00:00:46 +0000</pubDate>
		<dc:creator><![CDATA[あんどう やすし]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[5jcup]]></category>
		<category><![CDATA[cannon.js]]></category>

		<guid isPermaLink="false">/?p=10203</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (4)本記事はHTML5 Japan Cup 2014で優秀賞を頂いたEnraged Fowlsというゲームについての技術解説後編です。前編はこちらです。 物理エンジン 前編...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (4)</div><p>本記事は<a href="https://5jcup.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Japan Cup 2014</a>で優秀賞を頂いた<a href="https://5jcup.org/works/53a25c7120a279d145003005" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Enraged Fowls</a>というゲームについての技術解説後編です。<a href="https://html5experts.jp/technohippy/10084/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">前編</a>はこちらです。</p>

<h2>物理エンジン</h2>

<p><a href="https://html5experts.jp/technohippy/10084/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">前編</a>ではスリングショットコントローラーについて説明しましたが、ゲーム本体の技術要素についてはほぼ触れていませんでした。Enraged Fowlsでは弾が飛んでいく動きや、弾がぶつかって崩れるブロックの動きなどを実現するために、物理エンジンを使用しています。物理エンジンは文字通り、物理的な運動をコンピューター上で模擬してくれるライブラリで、特に今回のアプリのような物体同士の衝突を処理する必要がある場合に有用です。Enraged Fowls技術解説後編では、この物理エンジンについて簡単に説明します。</p>

<h3>cannon.js</h3>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/1d9cceeb88131b71b627b09152dda517.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/1d9cceeb88131b71b627b09152dda517-300x246.png" alt="スクリーンショット 2014-08-19 19.05.47" width="300" height="246" class="alignnone size-medium wp-image-10208" srcset="/wp-content/uploads/2014/08/1d9cceeb88131b71b627b09152dda517-300x246.png 300w, /wp-content/uploads/2014/08/1d9cceeb88131b71b627b09152dda517-207x170.png 207w, /wp-content/uploads/2014/08/1d9cceeb88131b71b627b09152dda517.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p><a href="http://www.cannonjs.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">cannon.jsについて</a></p>

<p>3次元を扱えるものに限っても、JavaScriptで実装された物理エンジンはいくつかあります。Enraged Fowlsではその中からcannon.jsという物理エンジンを採用しました。これは他の物理エンジンの多くが他言語製物理エンジンの移植で、インターフェースに違和感があったのに対して、cannon.jsはJavaScriptで新たに作成された物理エンジンなので、インターフェースが素直に見えたことと内部構造がシンプルだったためです。</p>

<p>なお、実際のEnraged Fowlsのコードは自作のライブラリを使っていて、物理エンジンの説明向きではなかったため、今回使用しているサンプルコードは、すべて説明用に単純化したEnraged Fowlsから抜き出したものになっています。単純化したコードの全文は以下にありますので、適宜参照してください。</p>

<p><a href="https://github.com/technohippy/enragedfowls-simple/blob/master/js/angry-birds-simple.js" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">簡易版Enraged Fowlsのコード全文
</a></p>

<h3>全体的な流れ</h3>

<p>物理エンジンは、物体の位置や向きを計算してくれるだけで、物体の表示には関知しません。表示に関しては、three.jsをいつも通りに使うことになります。両者を組み合わせる場合の基本的な流れは、次のようになります。</p>

<ol>
<li><strong>物理エンジンを初期化</strong></li>
<li>three.jsを初期化</li>
<li><strong>物理エンジンに物体（形状・位置・向き・速度など）を登録</strong></li>
<li>three.jsに物体（形状）を登録</li>
<li><strong>物理エンジンの物体とthree.jsの物体を関連付け</strong></li>
<li>以下を繰り返し

<ol>
<li><strong>物理エンジンに登録された物体の次の位置と向きを計算</strong></li>
<li><strong>three.jsの物体の位置と向きを、物理エンジンの関連する物体と同期</strong></li>
<li>three.jsの表示を更新</li>
</ol></li>
</ol>

<p>物理エンジンとthree.jsで、別個に物体を扱っているのが冗長に感じられるかもしれませんが、これには理由があります。両者を区別していることで、1つの物体に対して2種類のモデルを使用できるのです。例えばthree.js内で複雑な人型として扱われているオブジェクトを、物理エンジン内では単なる直方体として扱い、当たり判定を簡略化することができます。</p>

<p>上記のリストで重要なのは、5と6-2です。基本的にはオブジェクトの位置と向きは物理エンジンが管理し、オブジェクトの（表示される）形状はthree.jsが管理しますが、それぞれの情報の関連付けは開発者に委ねられます。5と6-2は、この情報の関連付けを処理しています。</p>

<p>本記事での解説は、上記の物理エンジンに関わる部分を抜き出す形で行います。</p>

<h3>物理エンジンを初期化</h3>

<p></p><pre class="crayon-plain-tag">AngryBirds.Game.prototype = {
  constructPhysicalWorld: function() {
    this.cannonWorld = new CANNON.World();
    this.cannonWorld.gravity.set(0,-9.82,0);
    this.cannonWorld.broadphase = new CANNON.NaiveBroadphase();
    // ...snip...
  },
}</pre><p></p>

<p>cannon.jsでは、物理エンジンの実体はCANNON.Worldオブジェクトです。物理エンジン全体に関わる設定や処理は、このオブジェクトを通じて行います。設定しているプロパティはそれぞれ、gravityは名前の通り重力、broadphaseは「衝突している可能性のあるオブジェクトの組み合わせを見つけるアルゴリズム」です(注1)。設定できる値はほかにもありますが、とりあえずこの2つをこの通りに設定しておけば動作します。</p>

<p>注1: 通常、物理エンジンは衝突判定をBroad PhaseとNarrow Phaseの2段階に分け、はじめにBroad Phaseで衝突している可能性のあるオブジェクトの組み合わせをなるべく素早く見つけ出し、次にそれらのオブジェクトが実際に衝突しているかどうかを、Narrow Phaseで厳密に検査します。Broad Phaseのアルゴリズムは、物理エンジンのパフォーマンスに大きく影響を与えるため、cannon.jsではプロパティとして与える形でその変更を容易にしています。</p>

<h3>物理エンジンに物体を登録</h3>

<p></p><pre class="crayon-plain-tag">AngryBirds.Game.prototype = {
  constructPhysicalWorld: function() {
    // 地面
    var groundShape = new CANNON.Plane();
    var groundWeight = 0; // 固定
    this.cannonGround = new CANNON.RigidBody(groundWeight, groundShape); // ...(1)
    this.cannonGround.quaternion = new CANNON.Quaternion();
    this.cannonGround.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2); // ...(2)

    // 鳥
    var birdShape = new CANNON.Sphere(0.5);
    var birdWeight = 10;
    this.cannonBird = new CANNON.RigidBody(birdWeight, birdShape); // ...(3)
    this.cannonBird.position.set(0, 2.5 + 2 + 0.1, 0);

    // CANNON.Worldに追加
    this.cannonWorld.add(this.cannonGround);
    this.cannonWorld.add(this.cannonBird);

    // ...snip...
  },
}</pre><p></p>

<p>cannon.jsでは、物体はCANNON.RigidBodyオブジェクトとして表され、物体の位置や向きの設定などはこのオブジェクトを通じて行います。ただし、物体の形状はCANNON.RigidBodyオブジェクトからは分離されていて、その指定にはCANNON.Shapeオブジェクトのサブクラスを使用します。上記の例では、CANNON.Plane（平面）とCANNON.Sphere（球体）を利用していますが、それ以外にも以下のような形状が使用可能です。</p>

<ul>
<li>CANNON.Sphere: 球体</li>
<li>CANNON.Plane: 平面</li>
<li>CANNON.Box: 直方体</li>
<li>CANNON.ConvexPolyhedron: 凸型多面体</li>
<li>CANNON.Compound: 上記の組み合わせ</li>
</ul>

<p>なお平面はデフォルトではz軸に垂直ですが、cannon.jsでは重力はy軸に垂直なので、地面として使用するためにquaternionを設定して、x軸に対して90度回転させています。</p>

<h3>物理エンジンの物体とthree.jsの物体を関連付け</h3>

<p>物理エンジンの物体とthree.jsの物体を関連付けについては、特に決まったやり方はありません。管理する物体の数が少なければ、単純に1つの物体に対してcannon.js用とthree.js用、2種類のオブジェクトを用意すればいいでしょう。今回の単純化したコードでは、threeFooとcannonFooという2変数で管理しています。</p>

<p></p><pre class="crayon-plain-tag">AngryBirds.Game = function(opts) {
  // ...snip...
  this.threeGround = null;
  this.threeBlocks = null;
  this.threeBird = null;
  this.cannonGround = null;
  this.cannonBlocks = null;
  this.cannonBird = null;
};</pre><p></p>

<p>実際のEnraged Fowlsでは、three.jsのオブジェクトとcannon.jsのオブジェクトを1つにまとめて使うための<a href="https://github.com/technohippy/enragedfowls/blob/master/js/c3.js" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">c3.js</a>という簡単なライブラリを作成しましたが、まだ公開するような完成度ではないので、ここでは説明を省略します。</p>

<h3>物理エンジンに登録された物体の次の位置と向きを計算</h3>

<p></p><pre class="crayon-plain-tag">this.cannonWorld.step(1.0/24.0);</pre><p></p>

<p>物体の位置を更新するには、CANNON.Worldオブジェクトのstepメソッドに経過時間を渡します。これだけで先にaddした物体間の衝突が処理され、位置や向きがそれぞれの運動状態に応じて更新されます。</p>

<h3>three.jsの物体の位置と向きを、物理エンジンの関連する物体と同期</h3>

<p></p><pre class="crayon-plain-tag">this.threeBird.position.copy(this.cannonBird.position);
this.threeBird.quaternion.copy(this.cannonBird.quaternion);</pre><p></p>

<p>先ほどCANNON.Worldオブジェクトのstepメソッドを呼び出しましたが、このメソッドはCANNON.RigidBodyの位置と向きを更新するだけです。表示位置を更新するには、描画の前にthree.js側のオブジェクトとcannon.jsのオブジェクトの位置を同期する必要があります。cannon.jsはthree.jsと組み合わせて使うことが初めから想定されているため、これは非常に簡単です。three.jsのオブジェクトのpositionプロパティ（位置）とquaternionプロパティ（向き）に、cannon.jsのオブジェクトのそれらをcopyしてください。これだけで位置と向きの同期が実現されます。</p>

<p>ここまでの実装を行うと、次のように衝突がそれっぽく扱われるようになります。</p>

<div id="attachment_10220" style="width: 292px" class="wp-caption alignnone"><a href="https://html5experts.jp/wp-content/uploads/2014/08/716c6c1ad8f4d575b797eb476eb3c8891.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/716c6c1ad8f4d575b797eb476eb3c8891-282x300.png" alt="物理エンジン前（貫通）" width="282" height="300" class="size-medium wp-image-10220" srcset="/wp-content/uploads/2014/08/716c6c1ad8f4d575b797eb476eb3c8891-282x300.png 282w, /wp-content/uploads/2014/08/716c6c1ad8f4d575b797eb476eb3c8891-194x207.png 194w, /wp-content/uploads/2014/08/716c6c1ad8f4d575b797eb476eb3c8891.png 423w" sizes="(max-width: 282px) 100vw, 282px" /></a><p class="wp-caption-text">物理エンジン前（貫通）</p></div>

<div id="attachment_10218" style="width: 305px" class="wp-caption alignnone"><a href="https://html5experts.jp/wp-content/uploads/2014/08/7988911360b8bea2eb18aa93cdd5c10e.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/7988911360b8bea2eb18aa93cdd5c10e-295x300.png" alt="物理エンジン後" width="295" height="300" class="size-medium wp-image-10218" srcset="/wp-content/uploads/2014/08/7988911360b8bea2eb18aa93cdd5c10e-295x300.png 295w, /wp-content/uploads/2014/08/7988911360b8bea2eb18aa93cdd5c10e-203x207.png 203w, /wp-content/uploads/2014/08/7988911360b8bea2eb18aa93cdd5c10e.png 443w" sizes="(max-width: 295px) 100vw, 295px" /></a><p class="wp-caption-text">物理エンジン後（瓦解中）</p></div>

<h2>まとめ</h2>

<p>モデリングツールを覚えるような時間もモチベーションもなかったため、Enraged Fowlsはthree.jsに用意されている基本図形だけでできています。それでも物理エンジンを使用すれば、その動きで見た目をある程度はカバーできていると言っていいのではないでしょうか。</p>

<p>今回の記事から分かる通り、物理エンジンの利用は存外に簡単です。初期位置を登録してstepメソッドを呼び出し結果を表示に反映させる、これだけです。three.jsを使用して単なるビューアーに留まらないインタラクティブなアプリを作るのであれば、物理エンジンを採用しない理由はありません。本記事を参考に、ぜひいろいろと試してみてください。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>Angry Birdsの3D版!?「Enraged Fowls」の技術解説（コントローラー編）</title>
		<link>/technohippy/10084/</link>
		<pubDate>Wed, 27 Aug 2014 00:00:13 +0000</pubDate>
		<dc:creator><![CDATA[あんどう やすし]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[5jcup]]></category>
		<category><![CDATA[WebRTC]]></category>
		<category><![CDATA[WebWorkers]]></category>

		<guid isPermaLink="false">/?p=10084</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (3)本記事はHTML5 Japan Cup 2014で優秀賞を頂いたEnraged Fowlsというゲームに関する技術的な解説の前編です。 Enraged Fowlsとは ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (3)</div><p>本記事は<a href="https://5jcup.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Japan Cup 2014</a>で優秀賞を頂いた<a href="http://technohippy.github.io/enragedfowls/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Enraged Fowls</a>というゲームに関する技術的な解説の前編です。</p>

<h2>Enraged Fowlsとは</h2>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a-300x199.png" alt="スクリーンショット 2014-08-16 1.41.20" width="300" height="199" class="alignnone size-medium wp-image-10088" srcset="/wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a-300x199.png 300w, /wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a-1024x681.png 1024w, /wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a-207x137.png 207w, /wp-content/uploads/2014/08/ef9fb494aaf85324e475fd93838bd91a.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>タイトルに使われているのは聞きなれない単語かもしれませんが、それぞれ類語辞典で調べたAngryとBirdの同義語です。「<a href="https://www.angrybirds.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Angry Birds</a>」については、おそらく皆さんご存知でしょう。全世界で累計15億ダウンロード（<a href="http://ja.wikipedia.org/wiki/Angry_Birds" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Wikipedia</a>）されたアクションパズルゲームで、物理エンジンを使用してスリングショットで撃ち込まれた鳥と、それにより崩れ落ちるブロックのリアルな動きを実現していることが大きな特徴です。上のスクリーンショットからも分かる通り、「Enraged Fowls」はこの「Angry Birds」を3Dにすることを目指したものです。</p>


<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe width="373" height="210" src="//www.youtube.com/embed/VGVn8wb9-Ag" frameborder="0" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>


<p><BR>
　加えて、Enraged Fowlsならではの機能としてスマホをセットして使用できる、スリングショット型のお手製コントローラーがあります。当コントローラーを使用すれば、モニターの中の世界に対して、実際にスリングショットで鳥を撃ちこんでいるような感覚を得ることができます。</p>

<h2>技術要素</h2>

<p>Enraged Fowlsの技術的な見どころとしては大きく</p>

<ol>
<li>スリングショットコントローラー</li>
<li>3Dの表示と動き</li>
</ol>

<p>の2つがあると考えています。具体的な技術要素を挙げると以下の様になるでしょうか。</p>

<ul>
<li>WebRTC（スリングショットコントローラー）</li>
<li>Web Workers（スリングショットコントローラー）</li>
<li>WebGL（three.js）</li>
<li>3D物理エンジン（cannon.js）</li>
</ul>

<p>この中でthree.jsについては、今回の「HTML5 Japan Cup 2014」の優秀・最優秀作4作品のうち、Enraged Fowlsを含む3作品が使用していることもあり、おそらく別の記事で解説されると判断して、本記事では説明を省略します。HTML5 Experts.jpにもthree.jsの解説記事がありますので、そちらを参考にしてもいいでしょう。</p>

<p><a href="https://html5experts.jp/yomotsu/5225/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">初心者でも絶対わかる、WebGLプログラミング＜three.js最初の一歩＞</a></p>

<p>また（three.jsを除いても）上記すべてを一度に解説することができなかったため、今回はスリングショット部について解説します。物理エンジンに興味のある方は次回までお待ちください。なお、Enraged Fowlsのソースコードは以下で全て公開されています。必要に応じて参照してください。</p>

<p><a href="https://github.com/technohippy/enragedfowls" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Enraged Fowlsのソースコード</a></p>

<h2>スリングショットコントローラー</h2>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/medium_IMG_20140629_010646.jpg" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/medium_IMG_20140629_010646-300x204.jpg" alt="medium_IMG_20140629_010646" width="300" height="204" class="alignnone size-medium wp-image-10094" srcset="/wp-content/uploads/2014/08/medium_IMG_20140629_010646-300x204.jpg 300w, /wp-content/uploads/2014/08/medium_IMG_20140629_010646-1024x697.jpg 1024w, /wp-content/uploads/2014/08/medium_IMG_20140629_010646-207x140.jpg 207w, /wp-content/uploads/2014/08/medium_IMG_20140629_010646.jpg 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>スリングショットコントローラーは、本物のスリングショットのようにコントローラを移動して狙いをつけます。そして、ゴム紐を引いて手を離し弾を撃つという操作を、ウェブカメラとスマートフォンの加速度センサーを利用して実現したものです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/398520a7a7b1ce6e75679a577aa51291.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/398520a7a7b1ce6e75679a577aa51291-300x161.png" alt="スクリーンショット 2014-08-18 14.24.59" width="300" height="161" class="alignnone size-medium wp-image-10109" srcset="/wp-content/uploads/2014/08/398520a7a7b1ce6e75679a577aa51291-300x161.png 300w, /wp-content/uploads/2014/08/398520a7a7b1ce6e75679a577aa51291-207x111.png 207w, /wp-content/uploads/2014/08/398520a7a7b1ce6e75679a577aa51291.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>（もちろん上記のような工作をしなくてもスマートフォンさえあれば、ウェブカムの前にかざして画面をタップするか端末の裏面を指で弾けば動作を確認することができるので、よかったら試してみてください）</p>

<h3>ウェブカムによるスマートフォンの位置の特定</h3>

<p>ウェブカメラに写るスマートフォンの位置を取得する方法は、正直かなり手を抜いていて、スマートフォンの画面を真っ赤にし、ウェブカムの「赤い部分」の平均値をスマートフォンの位置と見なしています。スリングショットコントローラーは、締め切りの一週間ほど前に、ふと思いついて追加した機能です。まず簡単な方法で実装して動作や使用感を検証し、精度が足りないようなら後できちんとしたやり方にしようと考えて実装しましたが、ちょっと遊ぶ分には大して問題もなかったため、結局そのまま今に至っています。まぁよくあることです。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/792dd322f11a7bd38696dea3dfa2d7ff.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/792dd322f11a7bd38696dea3dfa2d7ff-300x113.png" alt="スクリーンショット 2014-08-18 14.00.36" width="300" height="113" class="alignnone size-medium wp-image-10098" srcset="/wp-content/uploads/2014/08/792dd322f11a7bd38696dea3dfa2d7ff-300x113.png 300w, /wp-content/uploads/2014/08/792dd322f11a7bd38696dea3dfa2d7ff-207x78.png 207w, /wp-content/uploads/2014/08/792dd322f11a7bd38696dea3dfa2d7ff.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a>
<br />（右側の画像の緑のドットが&#8221;赤&#8221;と認識された箇所です）</p>

<p>ソースコードの該当部分を以下に抜粋します。</p>

<p></p><pre class="crayon-plain-tag">Detector.prototype.startCamera = function() {
  // ウェブカムの映像取り込み
  navigator.getUserMedia({video: true}, // ... (1)
    function(localMediaStream) {
      // ウェブカムの映像をvideo要素で表示
      this.video.src = window.URL.createObjectURL(localMediaStream); // ... (2)
      this.video.play();
    }.bind(this),
    function(err) { ... }.bind(this)
  );
};

Detector.prototype.startWorker = function() { // ... (3)
  // 画像解析用WebWorker開始
  this.worker = new Worker('js/detector_worker.js');
  this.worker.addEventListener('message', function(event) {
    // WebWorkerから返された解析結果を処理
    this.detectHandlers.forEach(function(handler) {
      handler(event.data, this.gc);
    }.bind(this));
    if (this.isDetecting) setTimeout(this.detect.bind(this), 10);
  }.bind(this));
};

Detector.prototype.detect = function() { // ... (4)
  // video要素の内容を取り込んでWebWorkerで処理
  this.gc.drawImage(this.video, 0, 0, this.video.width, this.video.height);
  this.worker.postMessage(this.gc.getImageData(0, 0, this.video.width, this.video.height));
};</pre><p></p>

<p>スマートフォンの位置の特定は、Detectorオブジェクトで行います。Detectorオブジェクトはdetector.jsとdetector_worker.jsの2つからなっていて、detector.jsではnavigator.getUserMedia関数を使用してウェブカムの画像をvideo要素に取り込み(1)(2)、画像解析用のWebWorkerを開始し(3)、定期的にvideo要素の内容をWebWorkerに送ります(4)。現在のところdetector_worker.jsでは非常に単純な解析しか行っておらず、WebWorkerを使わなくてもそれほど問題にはならないかもしれませんが、将来的に複雑な解析を行うことを可能にするために、バックグラウンドで処理しています。</p>

<p></p><pre class="crayon-plain-tag">// 直近10回の解析結果を保持
var centers = [];

addEventListener('message', function(event) {
  var imageData = event.data;
  var data = imageData.data;
  var redPoints = [];

  // 画像データを走査して赤い部分（isRed）の位置を記録
  for (var x = 0; x &amp;lt; imageData.width; x+=5) {
    for (var y = 0; y &amp;lt; imageData.height; y+=5) {
      var base = x * 4 + y * imageData.width * 4;
      if (isRed(data[base], data[base+1], data[base+2], data[base+3])) { // ... (5)
        redPoints.push({x:x, y:y});
      }
    }
  }

  // 直近10回の赤い部分の中心位置を記録
  var center = getCenter(redPoints);
  while (10 &amp;lt;= centers.length) centers.shift();
  centers.push(center);

  // 直近10回の平均位置を取得
  var centerAverage = getCenterAverage(centers); // ... (6)
  
  // WebWorker呼び出し元に結果を返却
  postMessage({
    redPoints:{points:redPoints, center:center, 
      centerAverage:centerAverage, size:redPoints.length}
  });
});

function isRed(r, b, g, a) {
  // なんとなく赤っぽい色を判定
  return 250 &amp;lt; a &amp;amp;&amp;amp; 100 &amp;lt; r &amp;amp;&amp;amp; g &amp;lt; r/2.0 &amp;amp;&amp;amp; b &amp;lt; r/2.0;
}</pre><p></p>

<p>先に書いた通り、detector_woker.jsの中心的な処理はImageDataオブジェクト内の赤い部分を抜き出して、その中心位置を返すことです。基本的にはImageDataの画素の色をチェックしているだけですが(5)、特に厳密な解析も不要なので全画素をチェックするのではなくある程度間引いた値をチェックし、それにより発生するチラツキを直近10回の解析結果の平均を返すことで防いでいるのが(6)、工夫といえば工夫です。</p>

<p>ちなみに、「赤い部分の位置の平均を取るだけだと服や部屋が赤かったりすると問題が起きるんじゃないか？」と思う人もいるでしょうが、おっしゃる通り、割と大変なことになります。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/4c3dd77191ab2b17b10f7fd33249a33e.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/4c3dd77191ab2b17b10f7fd33249a33e-300x113.png" alt="スクリーンショット 2014-08-18 14.06.23" width="300" height="113" class="alignnone size-medium wp-image-10102" srcset="/wp-content/uploads/2014/08/4c3dd77191ab2b17b10f7fd33249a33e-300x113.png 300w, /wp-content/uploads/2014/08/4c3dd77191ab2b17b10f7fd33249a33e-207x78.png 207w, /wp-content/uploads/2014/08/4c3dd77191ab2b17b10f7fd33249a33e.png 640w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>解決策はいろいろあると思うので、まぁ読者の皆さんへの宿題というか、pullreqは随時受付中です。</p>

<h3>Detectorオブジェクトの利用</h3>

<p></p><pre class="crayon-plain-tag">this.detector = new Detector();
this.detector.addDetectHandler(function(data, gc) {
  // ウェブカム画像内のスマートフォンの位置を正規化
  var center = data.redPoints.centerAverage;
  var dx = center.x / Detector.DEFAULT_WIDTH - 0.5;
  var dy = center.y / Detector.DEFAULT_HEIGHT - 0.5;

  this.cameraDirection = new THREE.Vector3(0, 0, 5);

  // y軸方向の位置を射出の縦方向に変換
  var yAxis = new THREE.Vector3(0, 1, 0);
  var yawAngle = -dx * Math.PI/2;
  var yawMatrix = new THREE.Matrix4().makeRotationAxis(yAxis, yawAngle);
  this.cameraDirection.applyMatrix4(yawMatrix);

  // x軸方向の位置を射出の横方向に変換
  var xAxis = new THREE.Vector3(1, 0, 0);
  var pitchAngle = -dy * Math.PI/4 - Math.PI/8;
  var pitchMatrix = new THREE.Matrix4().makeRotationAxis(xAxis, pitchAngle);
  this.cameraDirection.applyMatrix4(pitchMatrix);

  // 視点とカメラの向きを射出方向に合わせて変更
  this.world.threeCamera.position.copy(new THREE.Vector3().copy(
    this.bird.threeMesh.position).sub(this.cameraDirection));
  this.world.threeCamera.lookAt(this.bird.threeMesh.position);
}.bind(this));
this.detector.start();</pre><p></p>

<p>Detectorを利用する側のコードは、上記のようになります。Detectorオブジェクト自体はなるべく汎用的にしたかったので、Enraged Fowls独自の処理はaddDetectHandler関数で、利用側がハンドラ登録するようにしています。</p>

<p>一見複雑な処理にみえるかもしれませんが、要は下の図のように、目の前に固定されたスリングショットがあるイメージで、ウェブカム映像内でスマートフォンが写っている位置に応じて、撃ち出す方向や視点を変更しているだけです。具体的な座標変換についてはコードが全てですし、説明を省略します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/anim.gif" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/anim.gif" alt="anim" width="300" height="231" class="alignnone size-medium wp-image-10130" /></a></p>

<h3>加速度センサーによるゴム紐リリースの検知</h3>

<p>スリングショットで狙いを付けることができるようになったので、次にゴム紐を伸ばして離すことで、狙いをつけた方向に鳥（弾）を撃てるようにします。正直なところ、これも非常に手を抜いたやり方で実装しています。</p>

<p></p><pre class="crayon-plain-tag">window.addEventListener('devicemotion', function(event) {
  var threshold = 5;
  if (threshold &amp;lt; Math.abs(event.acceleration.z)) {
    toggleMarkerColor();
  }
});</pre><p></p>

<p>windowオブジェクトのdevicemotionイベントで、端末にかかる加速度を取得できます。スマートフォンの画面に対して垂直な方向はz軸方向なので、event.acceleration.zの値がある閾値を超えたときに、スマートフォンの裏側に何かしらの衝撃があったと判断できます。その衝撃を検知したことをアプリ本体に伝えられればいいわけですが、ここでも先ほどのDetectorオブジェクトを使用します。つまり衝撃を検知したときにスマートフォンの画面の色を赤から青に変更し、その色の変化を先のDetectorオブジェクトで検知してアプリに伝え、鳥（弾）を発射します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/08/3df13bc490329152910634962a56c357.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/3df13bc490329152910634962a56c357-170x300.png" alt="スクリーンショット 2014-08-18 23.39.59" width="85" height="150" class="alignnone size-medium wp-image-10133" srcset="/wp-content/uploads/2014/08/3df13bc490329152910634962a56c357-170x300.png 170w, /wp-content/uploads/2014/08/3df13bc490329152910634962a56c357-117x207.png 117w, /wp-content/uploads/2014/08/3df13bc490329152910634962a56c357.png 224w" sizes="(max-width: 85px) 100vw, 85px" /></a> &laquo;&raquo; <a href="https://html5experts.jp/wp-content/uploads/2014/08/ed3b06ec3c7faf3ab55092cb3a5e604b.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/ed3b06ec3c7faf3ab55092cb3a5e604b-170x300.png" alt="スクリーンショット 2014-08-18 23.40.31" width="85" height="150" class="alignnone size-medium wp-image-10134" srcset="/wp-content/uploads/2014/08/ed3b06ec3c7faf3ab55092cb3a5e604b-170x300.png 170w, /wp-content/uploads/2014/08/ed3b06ec3c7faf3ab55092cb3a5e604b-117x207.png 117w, /wp-content/uploads/2014/08/ed3b06ec3c7faf3ab55092cb3a5e604b.png 224w" sizes="(max-width: 85px) 100vw, 85px" /></a></p>

<p>勘のよい方はお気づきかと思いますが、z軸方向の加速度センサの値を見ているだけなので、例えば急にスマートフォンを裏返したり倒したりするだけで弾が暴発します。時間があればなんとかしようとも思っていたのですが、ちょっと遊ぶ分には大して問題もなかったため、結局そのまま今に至っています。まぁよくあることです。</p>

<p>加速度センサの値の履歴から特定のパターンの場合にだけ反応するなど解決策はいろいろあると思うので、読者の皆さんへの宿題というか、pullreq随時受付中です。</p>

<h3>まとめ</h3>

<p>スリングショットコントローラーに使用されている個々の技術は、非常に基本的で、特に難しいことも行っていません。ただそれらの組み合わせでスリングショットを実現したところは、ほんの少しだけ新しいのではないかと自負しています。</p>

<p>次回は、アプリ本体で使用している物理エンジンについて解説する予定です。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>SpeechRecognitionとWebRTCでつながる新感覚言葉遊び「コトバツナギ」の技術全て見せます！</title>
		<link>/foka/9979/</link>
		<pubDate>Tue, 26 Aug 2014 00:00:15 +0000</pubDate>
		<dc:creator><![CDATA[藤岡宏和]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[5jcup]]></category>
		<category><![CDATA[PeerJS]]></category>
		<category><![CDATA[SpeechRecognition]]></category>
		<category><![CDATA[WebRTC]]></category>

		<guid isPermaLink="false">/?p=9979</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (2)「コトバツナギ」というWebコンテンツを作成し、HTML5 Japan Cup 2014で最優秀賞を頂きました。コトバツナギは、SpeechRecognitionとWe...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (2)</div><p>「<a href="https://kotoba.tsukuenoue.com/" title="コトバツナギ" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">コトバツナギ</a>」というWebコンテンツを作成し、HTML5 Japan Cup 2014で最優秀賞を頂きました。コトバツナギは、SpeechRecognitionとWebRTCを軸にしたマルチユーザーコンテンツです。このコンテンツで使っている主な技術の解説をしたいと思います。</p>

<h2>概要</h2>

<p><a href="https://kotoba.tsukuenoue.com/" title="コトバツナギ" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">コトバツナギ</a>は、声に出して声で遊ぶマルチユーザーコトバアソビゲームです。</p>

<p><img src="/wp-content/uploads/2014/08/capture_01_enter.png" alt="コトバツナギ" width="600" height="382" class="aligncenter size-full wp-image-10009" srcset="/wp-content/uploads/2014/08/capture_01_enter.png 600w, /wp-content/uploads/2014/08/capture_01_enter-300x191.png 300w, /wp-content/uploads/2014/08/capture_01_enter-207x131.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p><img src="/wp-content/uploads/2014/08/capture_sp2.png" alt="コトバツナギ" width="285" height="517" class="aligncenter size-full wp-image-10029" srcset="/wp-content/uploads/2014/08/capture_sp2.png 285w, /wp-content/uploads/2014/08/capture_sp2-165x300.png 165w, /wp-content/uploads/2014/08/capture_sp2-114x207.png 114w" sizes="(max-width: 285px) 100vw, 285px" /></p>

<p>PCサイトを開き、スマートフォンを皆で持って集まって遊ぶゲームになっています。スマートフォンの代わりにマイク機能付きのノートPCでも可です。</p>

<p>WebRTCとwebkitSpeechRecognitionを使っているため、2014年8月の時点ではPC・スマホともにChromeブラウザのみ対応です。iOSのChromeはWebRTCとwebkitSpeechRecognitionに非対応のため不可ですが、MacのChromeは動作します。一人でも遊べます。</p>

<p>動作環境が限られるので遊べないユーザーがいる場合もあると思い、デモ動画も用意しました。</p>

<p>
<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe width="640" height="360" src="//www.youtube.com/embed/cTaC_h_ao_E" frameborder="0" 0="allowfullscreen" scrolling="yes" class="iframe-class"></iframe>
<br>
　解説文字無しの動画はこちら → [<a href="http://youtu.be/G6HGNISv4mo" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">http://youtu.be/G6HGNISv4mo</a>]</p>

<p>コトバツナギの主な技術をまとめると、</p>

<ul>
    <li>SSL</li>
    <li>WebRTC（getUserMedia）</li>
    <li>WebRTC（PeerJS）</li>
    <li>SpeechRecognition</li>
    <li>SpeechSynthesis</li>
    <li>Web Audio</li>
    <li>テキスト解析</li>
    <li>画像検索</li>
</ul>

<p>で、できてます。</p>

<p>次章より詳しく説明していきます。</p>

<h2>getUserMediaとSSL</h2>

<p>WebRTCでカメラ・マイク入力を利用可能にするgetUserMediaは、使用する度にブラウザに許可を得るダイアログが出てしまいます。このままだとゲームとして遊ぶには問題がありますが、httpsでアクセスできるようにすると回避できるため、SSLを導入しました。httpsの場合、アクセスしているドメインに対して最初に1回だけ許可すると、その後の許可は不要になります。（ブラウザを閉じても、設定をクリアするまで有効）</p>

<p><img src="/wp-content/uploads/2014/08/3f1c4e6aeb57ca113dda496e8aec5cb9.png" alt="マイク・カメラへのアクセス許可" width="250" height="394" class="aligncenter size-full wp-image-9998" srcset="/wp-content/uploads/2014/08/3f1c4e6aeb57ca113dda496e8aec5cb9.png 250w, /wp-content/uploads/2014/08/3f1c4e6aeb57ca113dda496e8aec5cb9-190x300.png 190w, /wp-content/uploads/2014/08/3f1c4e6aeb57ca113dda496e8aec5cb9-131x207.png 131w" sizes="(max-width: 250px) 100vw, 250px" /></p>

<p>コトバツナギでは、カメラ・マイクでそれぞれ許可ダイアログが出るので、最初に計2回の許可が必要になります。getUserMediaのvideo・audioを一度に扱えば一回で済みますが、マイク入力は使えるけどカメラが使えない（またはカメラの利用が嫌だ）という場合にも対応するため、このコンテンツではそれぞれの許可を分けました。</p>

<h2>PeerJS</h2>

<p>PCとスマートフォン間でWebRTCによる通信を実現するために<a href="http://peerjs.com/" title="PeerJS" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">PeerJS</a>を利用しています。PeerJSは無料で使える<a href="http://peerjs.com/peerserver" title="http://peerjs.com/peerserver" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">PeerServer Cloud service</a>を用意してくれていますがSSLに対応していません。今回は、レンタルしているVPSにPeerServerをインストールして、下記のサーバーサイドjavascriptをnode.jsのforeverコマンドで起動し、PeerServerを立てました。</p>

<p></p><pre class="crayon-plain-tag">var fs = require('fs');
var PeerServer = require('peer').PeerServer;
var server = new PeerServer({
	port: [ポート番号を指定します],
	path: '[パスを指定したい場合は記述します]',
	ssl: {
		key: fs.readFileSync('[sslのkeyファイルのパスが入ります]'),
		certificate: fs.readFileSync('[sslのcrtファイルのパスが入ります]')
	}
});</pre><p></p>

<h2>アイコトバでハジメル</h2>

<p>PCとスマートフォンを接続する際に、数字入力や文字入力をするコンテンツがよくありますが、その方法はあまり味気ないと以前より思っていたので、このコンテンツでは別の方法を検討しました。タップと声だけで遊べるコンテンツにしたかったので、アイコトバを声に出して言ってから始める仕組みにしています。</p>

<p><img src="/wp-content/uploads/2014/08/capture_02_aikotob.png" alt="コトバツナギ：アイコトバでハジメル" width="600" height="382" class="aligncenter size-full wp-image-10010" srcset="/wp-content/uploads/2014/08/capture_02_aikotob.png 600w, /wp-content/uploads/2014/08/capture_02_aikotob-300x191.png 300w, /wp-content/uploads/2014/08/capture_02_aikotob-207x131.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p>コトバツナギではアイコトバやゲーム本編での音声認識に、webkitSpeechRecognitionを使ってます。アイコトバは予めいくつか用意しておいて、認識した音声を対応する数字に変換するという仕組みをとっています。</p>

<p></p><pre class="crayon-plain-tag">var recognition = new webkitSpeechRecognition();
recognition.maxAlternatives=1; //webkitSpeechRecognitionは複数の解析候補を出力してくれる場合があるが、このコンテンツでは一つだけに絞って使用。
recognition.onresult = function(event) {
	//音声認識の解析結果のテキスト
	var resultText=event.results[0][0].transcript;

	//resultTextを予め用意してあるリストに照合して、マッチしたら該当の数字に変換
}
recognition.start();</pre><p></p>

<p>なお、webkitSpeechRecognitionは、onresult以外に、onstart、onend、onaudiostart、onsoundstart、onspeechstart、onspeechend、onsoundend、onaudioend、onnomatch、onerrorという多くのイベントがあり、必要に応じて使い分けることが重要になります。</p>

<p>解析結果（上記resultText）を数字に変換したら、WebRTCのDataChannel（PeerJSのDataConnection）を利用してPC側のゲーム本体と通信します。</p>

<p></p><pre class="crayon-plain-tag">var peer = new Peer('[自分のID番号]', {host: '[PeerServerのhost]', port: ['ポート番号'], path: '[パスを指定してPeerServerを立ち上げた場合は記述]'});

var connect = peer.connect('[接続先のゲーム本体のID番号。このコンテンツでは、resultTextのテキストを数字に変換]');
connect.on('open', function(){
	//接続成功
}
connect.on('data', function(data){
	//接続先から送られてきたdataを処理
}</pre><p></p>

<p>数字入力や文字入力を使った方が動作は安定するのですが、あえてアイコトバを使うようにしたのは、声に出して遊ぶゲームであることをゲーム本編の前にユーザーに体験してもらい、確認・練習してもらうという意図があります。また、ゲーム本編の前にマイク入力の許可をさせておきたいという狙いもあります。</p>

<h2>ゲームモードの選択</h2>

<p>ゲームは「シリトリでアソブ」「レンソウでアソブ」の2つのモードで遊べるようにしています。</p>

<p><img src="/wp-content/uploads/2014/08/capture_03_modeselect.png" alt="コトバツナギ：モード選択" width="600" height="436" class="aligncenter size-full wp-image-10011" srcset="/wp-content/uploads/2014/08/capture_03_modeselect.png 600w, /wp-content/uploads/2014/08/capture_03_modeselect-300x218.png 300w, /wp-content/uploads/2014/08/capture_03_modeselect-207x150.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p>ゲームモードを選択する際、スマートフォンの場合にはタップ操作以外に端末を右か左に傾けることでも選べるようにしました。参加者みんなが体を傾けて選択している絵が作れたら面白いと思い、こういう機能をつけてます。</p>

<p>端末側の傾き検知は、以下のようになっています。
必要に応じて、傾き検知を開始・停止できるようにしておくと便利です。
</p><pre class="crayon-plain-tag">var peer = new Peer([自身のID番号],[PeerServer情報]);
var connect = peer.connect([ゲーム本体のID番号]);

//傾き検知が必要になったらstartDeviceMotion()を呼んでaddEventListenerする
var startDeviceMotion=function(){
	window.addEventListener('devicemotion',onDevicemotion);
};

//必要ない時に止められるようにしておく
var stopDeviceMotion=function(){
	window.removeEventListener('devicemotion',onDevicemotion);
};

//端末が傾くと呼ばれる。実際にはaddEventListnerしていると常に呼ばれ続ける。
var onDevicemotion=function(e){
	var gravity = e.accelerationIncludingGravity;
	var data={mode:"gravity",gx:gravity.x,gy:gravity.y};
	connect.send(data);
};</pre><p></p>

<p>ユーザーの端末傾き情報をゲーム側で受け取って、ゲームモード決定するところは以下のようになっています。
このコンテンツのように一対多で接続する場合は、WebRTCのDataChannel（PeerJSのDataConnection）を接続毎に保持して、各端末からの通信を処理します。
</p><pre class="crayon-plain-tag">var users=new Array();
var peer = new Peer([ゲーム本体のID番号],[PeerServer情報]);

peer.on('connection', function(connect) {
	//一対多の接続の場合は端末から接続がある毎に呼ばれるので、connectを保持しておく。
	//今回はUserクラスを用意してconnectを保持
	var user=new User(connect);
	users.push(user)
});

//各ユーザーがシリトリを選んでいるかレンソウを選んでいるか調べる
var cnt=0;
setInterval(function(){
	var siritoriSelected=0;
	var rensouSelected=0;

	for(var i=0;i&lt;users.length;i++){
		var selectmode=users[i].getSelectedMode();
		if(selectmode=="siritori"){
			siritoriSelected++;
		}else if(selectmode=="rensou"){
			rensouSelected++;
		}
	}
	
	//一定カウント後にどちらが多いかによってモード決定
	//（実際のゲームでは、全員の選択が落ち着くのを待ってからカウントしている）
	cnt++;
	if(cnt&gt;3){
		if(siritoriSelected&gt;=rensouSelected){
			//シリトリをはじめる
		}else{
			//レンソウをはじめる
		}
	}

},500);

//Userクラス
var User=function(connect){

	connect.on('data', function(data){
		//接続先の端末からいろいろな通信情報がここに送られるので、処理分岐できるようにしておく
		if(data.mode=="gravity"){
			onGravity(data);
		}
	});

	var onGravity=function(data){
		//data.gx、data.gyを元にアイコンを移動させる。
	};
	
	//画面右の方にいるか左の方にいるか調べてシリトリかレンソウを返す
	this.getSelectedMode=function(){
		var selectMode;
		if([左の方にいる場合]){
			selectMode= "siritori";
		} else{
			selectMode= "rensou";
		}
		return selectMode;
	}
}</pre><p></p>

<p>ゲームモード決定時には「シリトリでアソブ」か「レンソウでアソブ」と、ゲーム本体から声が出ますが、これは音声合成で発話しています。</p>

<p></p><pre class="crayon-plain-tag">var speech=new SpeechSynthesisUtterance();
speech.text="しりとりであそぶ";
speech.lang = "ja-JP";
speech.volume = 1;
speechSynthesis.speak(speech);//speechSynthesisはwindowが持っているオブジェクト</pre><p></p>

<h2>ゲーム本番</h2>

<p>シリトリゲーム、または連想ゲームでコトバをつないで遊びます。</p>

<p><img src="/wp-content/uploads/2014/08/capture_04_siritori.png" alt="コトバツナギ：ゲーム画面" width="600" height="382" class="aligncenter size-full wp-image-10012" srcset="/wp-content/uploads/2014/08/capture_04_siritori.png 600w, /wp-content/uploads/2014/08/capture_04_siritori-300x191.png 300w, /wp-content/uploads/2014/08/capture_04_siritori-207x131.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p>「シリトリでアソブ」のゲームの処理の流れを、利用している技術要素とともに図にしました。おおまかには、①～⑧の流れでコトバをつないでいきます。</p>

<p><img src="/wp-content/uploads/2014/08/0b3a21b2bd83d515cbe8e037e27b4195.png" alt="コトバツナギ：ゲームの処理の流れ" width="668" height="893" class="aligncenter size-full wp-image-10389" srcset="/wp-content/uploads/2014/08/0b3a21b2bd83d515cbe8e037e27b4195.png 478w, /wp-content/uploads/2014/08/0b3a21b2bd83d515cbe8e037e27b4195-224x300.png 224w, /wp-content/uploads/2014/08/0b3a21b2bd83d515cbe8e037e27b4195-154x207.png 154w" sizes="(max-width: 668px) 100vw, 668px" /></p>

<p>カメラの利用が許可されている場合、回答する度に毎回操作端末側のカメラでユーザーを撮影して、ゲーム本体に画像を送信しています（フロー②）。</p>

<p>また、ユーザーの操作端末がノートPCの場合は、回答の音声を端末側で録音し、blobデータとしてゲーム本体に送信しています。（フロー②、③）録音には<a href="https://github.com/mattdiamond/Recorderjs" title="recorder.js" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">recorder.js</a>を利用しました。recorder.jsはrecorderWorker.jsがセットになっており、Web Workerとして使う仕組みになっているようです。</p>

<p></p><pre class="crayon-plain-tag">var mediaStream;
var rec;
var audioContext=new AudioContext();

navigator.getUserMedia({audio:true}, 
	function(stream) {
		mediaStream=stream;
		var source = audioContext.createMediaStreamSource(stream);
		rec=new Recorder(source,{workerPath:[recorderWorker.jsまでのパス]"});
		rec.record();
	},
	function(err){
		//エラーの場合は何もしない。
		//スマホの場合はwebkitSpeechRecognitionと同時併用できないのでエラーになる。
	}
);

//録音終了したいタイミングで呼び出す
var recStop=function(){
	rec.stop();
	mediaStream.stop();

	//wav形式に変換したらonRecExportedを呼び出す
	rec.exportWAV(onRecExported);
};

//wav形式変換が完了するとblobデータが取得できる
var onRecExported=function(blob){
	//blobをWebRTCでゲーム本体に送信
};</pre><p></p>

<p>スマートフォンの場合、2014年8月現在ではSpeechRecognitionとgetUserMediaのaudioを同時に使えない仕様になっていたので、残念ながらスマートフォンの場合は録音を諦めました。（SpeechRecognitionを同時に使わなければ、スマートフォンでも録音することができます）</p>

<p>なお、ここで録音撮影した音声・画像は、ゲーム終了時に使います。</p>

<h2>ゲーム終了</h2>

<p>ゲーム終了すると、これまでつないだコトバが連続して再生されます。</p>

<p><img src="/wp-content/uploads/2014/08/capture_06_kotobachain.png" alt="コトバツナギ：ゲーム終了" width="600" height="382" class="aligncenter size-full wp-image-10013" srcset="/wp-content/uploads/2014/08/capture_06_kotobachain.png 600w, /wp-content/uploads/2014/08/capture_06_kotobachain-300x191.png 300w, /wp-content/uploads/2014/08/capture_06_kotobachain-207x131.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p><img src="/wp-content/uploads/2014/08/capture_07_last.png" alt="コトバツナギ：ゲーム終了" width="600" height="382" class="aligncenter size-full wp-image-10014" srcset="/wp-content/uploads/2014/08/capture_07_last.png 600w, /wp-content/uploads/2014/08/capture_07_last-300x191.png 300w, /wp-content/uploads/2014/08/capture_07_last-207x131.png 207w" sizes="(max-width: 600px) 100vw, 600px" /></p>

<p>getUserMediaのvideoが使える場合、終了時に流れる各コトバに表示されているユーザー画像は、ゲーム中に回答した時に、毎回撮影したものを表示しています。（ゲーム本番のフロー②で撮影）それぞれのコトバを発声した時に、どんな顔をしていたかがわかるようになっています。（ページ上部のデモ動画参照）</p>

<p>また、ノートPCを使って回答したユーザーのコトバの場合、ゲーム中に回答した時に、録音した音声を再生します。（ゲーム本番のフロー①②で録音）上述の通りスマートフォンでは音声録音がSpeechRecognitionと併用できないので、スマートフォンを使って回答したユーザーのコトバの場合は、音声合成で代用します。</p>

<p></p><pre class="crayon-plain-tag">var audioContext=new AudioContext();

//audioBlobはゲーム時に保存していたblobデータ
if(audioBlob){
	//audioContextはコンテンツ内でnewできる数に上限があるため、何度も同じ処理をする場合は、毎回newするのはなるべく避ける。
	//このコンテンツのように同時発音する可能性がなければ、AudioContextは再利用した方がnew上限エラーにならないので良いと思われる。
	if(!audioContext){
		audioContext=new AudioContext();
	}
	var source = audioContext.createBufferSource();

	audioContext.decodeAudioData(audioBlob,function(buffer){
		source.buffer = buffer;
		source.connect(audioContext.destination);
		source.start(0);
	});

//audioblobがない場合は合成音声で発話。recognitionTextはゲーム時に保存していた音声解析のテキスト。
}else{
	var speech=new SpeechSynthesisUtterance();
	speech.text=recognitionText;
	speech.lang = "ja-JP";
	speech.volume = 1;
	speechSynthesis.speak(speech);
}</pre><p></p>

<h2>最後に</h2>

<p>コトバツナギの主な仕組みは上記のようになっています。ゲーム本編だけでなく、ゲーム終了後にも参加者みんなで結果を振り返って楽しんでもらえるように作っています。音声解析がなかなかうまくいかないことも多いですが、思わぬ解析結果になることも含めて楽しんでもらえれば幸いです。<br>
よかったら遊んでみてください。</p>

<p>■コトバツナギ<br>
<a href="https://kotoba.tsukuenoue.com/" title="コトバツナギ" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">https://kotoba.tsukuenoue.com/</a></p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>池澤あやかさんと振り返る「HTML5 Japan Cup 2014」受賞作品たち</title>
		<link>/miyuki-baba/10362/</link>
		<pubDate>Mon, 25 Aug 2014 00:00:58 +0000</pubDate>
		<dc:creator><![CDATA[馬場 美由紀]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[5jcup]]></category>
		<category><![CDATA[Webアプリ]]></category>
		<category><![CDATA[html5j]]></category>

		<guid isPermaLink="false">/?p=10362</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (1)html5j主催により開催された、WebデザイナーやWebエンジニアのためのクリエイティブ・アワード「HTML5 Japan Cup（5jCup）」。応募期間4月23日...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (1)</div><p>html5j主催により開催された、WebデザイナーやWebエンジニアのためのクリエイティブ・アワード「<a href="https://5jcup.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">HTML5 Japan Cup（5jCup）</a>」。応募期間4月23日～6月30日の約2カ月で集まった作品数は、なんと289作品でした。</p>

<p>この数あるHTML5を使ったアプリの中から最優秀賞・優秀賞作品や審査員特別賞などを受賞した作品たちを、5jCupの審査員も務めた池澤あやかさんと一緒に紹介していきたいと思います。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup003.jpg" alt="" width="600" height="378" class="alignnone size-full wp-image-10166" srcset="/wp-content/uploads/2014/08/5jcup003.jpg 600w, /wp-content/uploads/2014/08/5jcup003-300x189.jpg 300w, /wp-content/uploads/2014/08/5jcup003-207x130.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲Rubyが得意な「GEEK系アイドル」池澤あやかさん</span></p>

<h2>優秀賞4作品と審査員特別賞3作品が選抜されるまで</h2>

<p>7月26日に開催された「HTML5 Japan Cup 2014 The Final」まで、実は2回の審査会を行っています。1回目はhtml5j＆5jCupスタッフ有志約30名による審査基準チェック。作品にWeb技術を使っているか、5jcup開催期間中に制作・更新されたものであるか、モバイルアプリは端末で操作できるかといった基本的な確認に加え、「独創性」「完成度」「表現力」「技術力」の観点から審査を行い、20作品に絞り込まれました。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup005.jpg" alt="" width="600" height="202" class="alignnone size-full wp-image-10174" srcset="/wp-content/uploads/2014/08/5jcup005.jpg 600w, /wp-content/uploads/2014/08/5jcup005-300x101.jpg 300w, /wp-content/uploads/2014/08/5jcup005-207x69.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲PC画面やモバイル端末、Leap Motionなどの実機を使って検証、審査するスタッフの皆さん</span></p>

<p>その20作品に対して、5jCUp審査員による二次審査会を行いました。審査員全員が半日に渡り議論を重ねながら選ばれたのが、優秀賞の4作品と審査員特別賞の3作品です。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup0061.jpg" alt="" width="600" height="320" class="alignnone size-full wp-image-10179" srcset="/wp-content/uploads/2014/08/5jcup0061.jpg 600w, /wp-content/uploads/2014/08/5jcup0061-300x160.jpg 300w, /wp-content/uploads/2014/08/5jcup0061-207x110.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲審査員の池澤あやかさん、及川卓也さん、羽田野太巳さん、Daniel Davisさん、藤村厚夫さん、秋葉秀樹さん、吉川徹さん</span></p>

<p>「HTML5 Japan Cup 2014 The Final」では優秀賞に選ばれた4組がプレゼンを行い、会場の参加者全員で10円玉で投票するというやり方で最優秀賞が決定しました。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup007.jpg" alt="" width="600" height="384" class="alignnone size-full wp-image-10195" srcset="/wp-content/uploads/2014/08/5jcup007.jpg 600w, /wp-content/uploads/2014/08/5jcup007-300x192.jpg 300w, /wp-content/uploads/2014/08/5jcup007-207x132.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲審査員も来場者と同じ一票（10円玉）を投じました</span></p>

<h2>最優秀賞・優秀賞・審査員特別賞に選ばれた作品たち</h2>

<h3>＜最優秀賞＞コトバツナギ</h3>

<p>会場の票を集め、最優秀賞に選ばれた作品は、<a href="https://html5experts.jp/foka/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">藤岡宏和さん</a>の「<a href="https://5jcup.org/works/53b0af237fbdb8f1ff0030d2" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">コトバツナギ</a>」。PCやスマートフォンで「声に出して声で遊ぶ」ゲームです。シリトリもしくは連想ゲームを選択し、WebRTCと音声解析を使ってコトバをつないでいきます。コトバは文字だけでなくネット上から画像を検索して表示させる機能もあり、どんな画像が現れるのか予測できないという楽しみもあります。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup33.jpg" alt="" width="600" height="391" class="alignnone size-full wp-image-10231" srcset="/wp-content/uploads/2014/08/5jcup33.jpg 600w, /wp-content/uploads/2014/08/5jcup33-300x195.jpg 300w, /wp-content/uploads/2014/08/5jcup33-207x134.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲参加者がスマートフォンに向かってアイコトバ（合言葉）を伝えるとゲームがスタートします</span></p>

<p>デモ動画（<a href="http://youtu.be/cTaC_h_ao_E" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">解説文字付きデモ動画</a>／<a href="http://youtu.be/G6HGNISv4mo" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">文字なしデモ動画</a>）が公開されていますので、ぜひこちらもご覧ください。詳しい技術解説は後日藤岡さんのレポートで！</p>

<h3>＜優秀賞＞Enraged Fowls</h3>

<p>優秀賞1作品目は、「Angry」と「Bird」でおなじみのゲームをThree.js（WebGLライブラリ）とCannon.js（物理エンジン）を組み合わせて3Dゲームに仕立てた「<a href="https://5jcup.org/works/53a25c7120a279d145003005" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Enraged Fowls</a>」。制作者の<a href="https://html5experts.jp/technohippy/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">あんどうやすし</a>さんいわく、WebGLと3次元の物理エンジンを一緒に使っている作品はEnraged Fowlsだけという自信作。<a href="http://youtu.be/VGVn8wb9-Ag" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">デモ動画</a>と<a href="https://github.com/technohippy/threejs-toys/tree/master/angry-birds" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>も公開中です。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup34.jpg" alt="" width="600" height="412" class="alignnone size-full wp-image-10259" srcset="/wp-content/uploads/2014/08/5jcup34.jpg 600w, /wp-content/uploads/2014/08/5jcup34-300x206.jpg 300w, /wp-content/uploads/2014/08/5jcup34-207x142.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲Google I/Oで配布されたProject Cardboardをヒントに100円ショップで自作したスリングショットコントローラー</span></p>

<p>さらに利用したHTML5技術として、WebWorker（画像解析）、navigator.getUserMedia (WebRTC：ウェブカメラ画像取込）、navigator.vibrate (Vibration API：タップ通知）、window.localStorage（ハイスコア保存）、devicemotionイベント（スマートフォンの裏面タップ検知）があるのだとか。最優秀賞で賞金100万円を獲得したら、電子書籍でWebGL+物理エンジンの技術について執筆するとアツく語っていましたが、今回はHTML5 Experts.jpで授賞作品の技術解説を書いていただくことになりました。お楽しみに！</p>

<h3>＜優秀賞＞YouTubeそっくりなWebGLプレーヤー</h3>

<p>カメラのアングルを動かせる「<a href="https://5jcup.org/works/53b14ce828eeadf1aa0000dc" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">YouTubeそっくりなWebGLプレーヤー</a>」で優秀賞を受賞したのは、jThree合同会社の<a href="https://html5experts.jp/mitsuhide/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">松田光秀</a>さん。一見動画に見えるデモ画面の中で踊るキャラクターたちは3DCGモデルで、マウスで動かすことができる。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup35.jpg" alt="" width="600" height="382" class="alignnone size-full wp-image-10276" srcset="/wp-content/uploads/2014/08/5jcup35.jpg 600w, /wp-content/uploads/2014/08/5jcup35-300x191.jpg 300w, /wp-content/uploads/2014/08/5jcup35-207x131.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲「jThree」で世界のWebをたぎらせたいとアツく語る松田さん</span></p>

<p>プレゼンで最も強調して語られたのは、松田さんが開発したjQueryの記法で作るWebGLライブラリ「jThree」の有用性について。このプラグインを使えば、デモ1本のコーディングがたったの3KBで書け、デザイナーやプログラミング初心者でも簡単にWebコンテンツを作ることが可能だという。</p>

<p>Oculus Riftモードやカメラコントロールは、設定不要の標準搭載。表彰後の懇親会では、池澤あやかさんもLeap MotionやOculus Riftで体験。池澤さんの感想は「ブラウザで3Dレンダリングできて、しかもLeap Motionからの入力でそのモデルが動くなんて、すごく時代は進んだなと思いました」。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup36.jpg" alt="" width="600" height="393" class="alignnone size-full wp-image-10281" srcset="/wp-content/uploads/2014/08/5jcup36.jpg 600w, /wp-content/uploads/2014/08/5jcup36-300x196.jpg 300w, /wp-content/uploads/2014/08/5jcup36-207x135.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲Leap Motionで3DCGモデルを動かす体験を試みる池澤あやかさん</span></p>

<h3>＜優秀賞＞JS Racing</h3>

<p>優秀賞4作品目は、<a href="https://html5experts.jp/knockknockjp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">西田慎吾（株式会社アイエムジェイ・TSUKURITE）</a>さんのWebGLとWebSocketを使用した3Dオンラインレースゲーム「JS Racing」。審査員である<a href="https://html5experts.jp/futomi/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">羽田野太巳</a>さんが、時間を忘れるほどはまってしまったというシンプルながらもゲーム性の高い作品です。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup37.jpg" alt="" width="600" height="398" class="alignnone size-full wp-image-10289" srcset="/wp-content/uploads/2014/08/5jcup37.jpg 600w, /wp-content/uploads/2014/08/5jcup37-300x199.jpg 300w, /wp-content/uploads/2014/08/5jcup37-207x137.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲PCだけでなく、スマートフォンからも操作ができ、複数人で同時走行やオンライン対戦も可能</span></p>

<p>その他に使ったHTL5技術はSVG、Canvas、WebFont、CSS3。クライアント技術としてTypeScript、jQuery、Three.js、Box2DJS。サーバサイド技術としては、Node.js（Socket.IO、Express、Jade）、MongoDBを活用しているとのこと。元々Flasherだったという西田さんは、TypeScriptがとても使いやすかったそうです。</p>

<h3>＜審査員特別賞＞PACPAC</h3>

<p>当初予定されていなかったものの審査会で優秀賞と甲乙つけがたいと評価された3作品に、審査員特別賞が授与されました。その一つがCanvasとCSS3を組み合わせて立体の面にペイントできるようにした作品「<a href="https://5jcup.org/works/539be52fa697452ebd004c93" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">PACPAC</a>」（いしかわさん）。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup38.jpg" alt="" width="600" height="397" class="alignnone size-full wp-image-10303" srcset="/wp-content/uploads/2014/08/5jcup38.jpg 600w, /wp-content/uploads/2014/08/5jcup38-300x198.jpg 300w, /wp-content/uploads/2014/08/5jcup38-207x136.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲池澤さんが描いた3Dの牛乳パック。拡大して見たい方は<a href="http://pacpac.atlr.org/pacpac2/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">こちら</a>から</span></p>

<p>その他に使ったHTL5技術はアニメーションにjQuery、Ajaxをページ遷移を少なくするために用い、画像の保存はクライアント側でcanvasをdataURLにして、サーバー側でファイルに保存しているとのこと。池澤あやかさんいわく 「divで牛乳パックが構成されてることに驚きが隠せなかった」のだそう。ちなみに最も応募数の多かった、html5jエンタメ技術部の「エンタメアプリ・コンテンツ賞」もダブル受賞でした。</p>

<h3>＜審査員特別賞＞花王カタログカルタ</h3>

<p>node.jsを利用した多人数での同時対戦が可能な花王製品カルタゲーム「<a href="https://5jcup.org/works/53b1680e6bb223aa5c001341" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">花王カタログカルタ</a>」（博報堂アイ・スタジオ）。各画像はsvg、カルタの拡大画像などのアニメーションは主にCSS3で実装することによって、パフォーマンスやクオリティの向上を図っています。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup39.jpg" alt="" width="600" height="394" class="alignnone size-full wp-image-10306" srcset="/wp-content/uploads/2014/08/5jcup39.jpg 600w, /wp-content/uploads/2014/08/5jcup39-300x197.jpg 300w, /wp-content/uploads/2014/08/5jcup39-207x135.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲製品にまつわる利用シーンなどのあるあるネタをカルタ化している</span></p>

<p>技術力に加え、インタラクティブコンテンツの制作会社である強みである最大限に活かしたマーケティング力とクリエティブ性の高い作品です。</p>

<h3>＜審査員特別賞＞TouchBloomy</h3>

<p>オブジェクトの連鎖点を予想して、ブラウザ上でタップしてつなげるパズルゲーム「<a href="https://5jcup.org/works/53ae875cd1dc88aab2002f9c" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">TouchBloomy</a>」で受賞したのは、チームアルクリットの吉村智志さん、小澤駿さん。1ステージ約30秒、ワンタップでできるシンプルなゲームで、ステージ投稿機能なども面白い仕掛けとなっています。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup40.jpg" alt="" width="600" height="405" class="alignnone size-full wp-image-10309" srcset="/wp-content/uploads/2014/08/5jcup40.jpg 600w, /wp-content/uploads/2014/08/5jcup40-300x202.jpg 300w, /wp-content/uploads/2014/08/5jcup40-207x139.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲画像を使用せずに処理速度を維持。enchant.js、canvas、DOMなどの技術を使って制作している</span></p>

<p>上記で紹介した最優秀賞・優秀賞・審査員特別賞の受賞作品について、池澤あやかさんに感想を聞いてみました。<br>
「受賞作品はWebRTCで参加型のWebに仕上げたものが多く、印象に残りました。意外と今までは参加型のWebが少なかったので、Webの近未来を感じました。WebRTC、私も今度いじってみようと思います」</p>

<p>池澤あやかさんの言うとおり、今回の5jCupはWebRTCを使った応募作品が最も多く、41作品。そして、WebGLの30作品、Monaca/Onsen UIが20作品と、Webの先端技術を駆使した作品が多数応募されました。受賞作品の講評、審査員コメントは以下で紹介されていますので、合わせてご覧ください。</p>

<ul>
<li><a href="http://blog.5jcup.org/2014/07/html5-japan-cup-2014_27.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">【HTML5 Japan Cup 2014】最優秀賞・優秀賞・審査員特別賞の受賞作品と審査員講評</a></li>
<li><a href="http://blog.5jcup.org/2014/07/html5-japan-cup-2014_85.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">【HTML5 Japan Cup 2014】テーマ賞の受賞作品と受賞理由</a></li>
<li><a href="http://geechs-magazine.com/2397" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">geechsマガジン独占！豪華審査員インタビュー</a></li>
</ul>

<h2>テーマ賞作品LTで、池澤あやかさんが印象に残った2作品</h2>

<p>「HTML5 Japan Cup 2014 The Final」表彰式終了後の懇親会では、各テーマ賞受賞者の方々によるLT大会が行われました。飲食OK、ただし全員着席で全力でLTを聞くのをルールとしたこともあり、歓声と拍手で大盛り上がり。どれも大変面白い作品ばかりなのですが、今回は池澤あやかさんが印象に残ったという2作品に絞って紹介したいと思います。</p>

<h3>!CheerZ!　乾杯可視化システム</h3>

<p>まず1作品目は「<a href="https://5jcup.org/works/53b11ad64a2b6badd7006990" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">!CheerZ!　乾杯可視化システム</a>」（0101室サーバ担当チーム）。センサー付きのグラスを使って乾杯を可視化し、遠方にいる人とも乾杯ができるというもの。「<a href="https://5jcup.org/awards/kddi" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">スマートフォンの次を狙え！生活を快適にするデバイス×Webアプリ</a>」受賞作品。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup41.jpg" alt="" width="600" height="366" class="alignnone size-full wp-image-10320" srcset="/wp-content/uploads/2014/08/5jcup41.jpg 600w, /wp-content/uploads/2014/08/5jcup41-300x183.jpg 300w, /wp-content/uploads/2014/08/5jcup41-207x126.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲WebGLを使って表示、 Socket.IOで画像を飛ばしている</span></p>

<p><img src="/wp-content/uploads/2014/08/5jcup42.jpg" alt="" width="599" height="396" class="alignnone size-full wp-image-10321" srcset="/wp-content/uploads/2014/08/5jcup42.jpg 599w, /wp-content/uploads/2014/08/5jcup42-300x198.jpg 300w, /wp-content/uploads/2014/08/5jcup42-207x136.jpg 207w" sizes="(max-width: 599px) 100vw, 599px" /><br><span style="font-size: 80%;">　▲乾杯するとグラスに付けている加速度センサーが認識して、地図上に表示される</span></p>

<h3>UFO-Escape</h3>

<p>もう1作品は小学6年生のプログラマ・シュン君の「UFO-Escape」。<a href="https://5jcup.org/awards/html5j-webplatform" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Webプラットフォーム賞</a>の審査基準は「最低でも二つ以上のプラットフォームで、同様の挙動をすること」だったが、応募したWindowsストアアプリ、Firefox OS、Chrome Apps、Android (4以上)すべてのプラットフォームできちんと動くことが確認できた唯一の作品だったのだとか。</p>

<p><img src="/wp-content/uploads/2014/08/5jcup43.jpg" alt="" width="600" height="401" class="alignnone size-full wp-image-10326" srcset="/wp-content/uploads/2014/08/5jcup43.jpg 600w, /wp-content/uploads/2014/08/5jcup43-300x200.jpg 300w, /wp-content/uploads/2014/08/5jcup43-207x138.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲トップバッターにも関わらず、堂々と発表するシュン君</span></p>

<p><img src="/wp-content/uploads/2014/08/5jcup44.jpg" alt="" width="600" height="386" class="alignnone size-full wp-image-10327" srcset="/wp-content/uploads/2014/08/5jcup44.jpg 600w, /wp-content/uploads/2014/08/5jcup44-300x193.jpg 300w, /wp-content/uploads/2014/08/5jcup44-207x133.jpg 207w" sizes="(max-width: 600px) 100vw, 600px" /><br><span style="font-size: 80%;">　▲enchant.jsで作ったゲームを、Windowsストアアプリ、Firefox OS、Chrome Apps、Androidなどのプラットフォームに移植</span></p>

<ul>
<li><a href="https://codeiq.jp/magazine/tag/shun/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">シュン君が挑戦した「enchant.jsでHTML5ゲームを作り、プラットフォームに移植してみよう！」</a></li>
<li><a href="http://blog.5jcup.org/2014/08/html5-japan-cup-2014-finallt.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">【HTML5 Japan Cup 2014 The Final】LT＆懇親会レポート！</a></li>
</ul>

<p><br>
<img src="/wp-content/uploads/2014/08/5jcup48.jpg" alt="" width="145" height="150" class="alignleft size-full wp-image-10337" /><strong>＜池澤あやかさんの感想＞</strong><br>カンパイ楽しかったです。この作品はジョッキの下にマイコンがとりつけてあったのですが、この作品のようにマイコンを使って現実世界と繋がるWebも今後発展していくのではないかと思います！<br><br>そしてまだ小学生の男の子が堂々とLTしていたのを見て、今後の日本は安泰だと思いました。しかもゲームもよくできてたので、本当にすごいなと。</p>

<p>HTML5 Experts.jpではこの後も「HTML5 Japan Cup 2014」特集を組んで、最優秀賞・優秀賞受賞者の皆さんによる技術解説レポートも掲載予定です。ご期待ください！</p>

<p><img src="/wp-content/uploads/2014/08/5jcup49.jpg" alt="" width="628" height="327" class="alignnone size-full wp-image-10349" srcset="/wp-content/uploads/2014/08/5jcup49.jpg 628w, /wp-content/uploads/2014/08/5jcup49-300x156.jpg 300w, /wp-content/uploads/2014/08/5jcup49-207x107.jpg 207w" sizes="(max-width: 628px) 100vw, 628px" /><br><span style="font-size: 80%;">　▲61団体,延べ参加人数1449名（htmlday含）で日本のWebをたぎらせた「HTML5 Japan Cup 2014 The Final」にカンパイ！</span></p>

<p><DIV align=right><span style="font-size: 80%;">(C)HTML5 Japan Cup 2014, 表彰式撮影：佐藤聡／審査会撮影：市川純、馬場美由紀</span></div></p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
	</channel>
</rss>
