エイバースの中の人

アプリとWEBサービスを作っているABARSのBLOGです。

HTML5

iPad Proの筆圧をJavaScriptで取得する

iPad ProとApple Pencilを使用すると、JavaScriptで筆圧を取得することができます。取得方法はとても簡単で、touchmoveイベントの中で、forceプロパティを参照するだけです。

if(e.touches[0].force){
pressure=e.touches[0].force;
}

pressureには0〜1.0の値が入ります。ただし、touchstartの最初の筆圧は、かなり強い値が来ることがあるので、いくつかの値は捨てた方がよいかもしれません。

筆圧を使用したお絵かきツールのサンプル

IMG_1649

WebAudio APIを使ってHTML5のゲームに音を付ける

HTML5のゲームで音を再生する場合、従来はAudio要素を使用していました。例えば、次のようにするとurlで指定した音を再生することができます。

var audio=new Audio(url);
audio.play()

この方法はPCだと問題なく動作しますが、iOSの場合、ユーザのタッチイベントの中でしかplayを受け付けないという問題があります。回避策として、ユーザのタッチイベントでaudio.load()しておいてplayする方法もありますが、1回のタッチイベントで1つのAudioファイルしかloadすることはできないため、効果音を全てプリロードすることはできません。複数の効果音を1つのファイルに結合してプリロードする、オーディオスプライトという方法もありますが、同時に1つの効果音しか再生できません。

これらの問題を解決するためには、Audio要素ではなく、WebAudio APIを使用する必要があります。WebAudio APIの場合、iOSでも、ユーザのタッチイベントで何か1つ音を再生すると、以降は自由に音を再生できるようになります。プリロードはXmlHttpRequestで行うため、タッチイベント外で、全ての効果音をまとめて行うことができます。

WebAudio APIを使用するには、まず、AudioContextを作成します。

try {
	window.AudioContext = window.AudioContext || window.webkitAudioContext;
	context = new AudioContext();
}
catch(e) {
	onerror('Web Audio API is not supported in this browser');
}

次に、XMLHttpRequestで音声ファイルを読み込みます。iOSとAndroidの場合、wavとmp3の両方を再生することができます。ファイルを読み込んだら、decodeAudioDataでデコードします。Audioタグのストリーミングとは異なり、事前に全てデコードするので、BGMなど長い曲では処理に時間がかかります。

var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
	context.decodeAudioData(request.response, function(buffer) {
		audio_buffer = buffer;
	}, function(){
		//エラー
	}
	);
};
request.send();

再生するには、BufferSourceを作成して、startを実行します。効果音を再生するたびにBufferSourceを作成しても、パフォーマンス的な問題は起きませんでした。

var source = context.createBufferSource();
source.buffer = audio_buffer;
source.connect(context.destination);
source.start(0);

ループ再生するには、BufferSourceのloop属性にtrueを入れます。

source.loop=true;
source.start(0);

ループ再生を停止するには、startしたBufferSourceでstopを実行します。仕様上はstopの引数は任意ですが、iOSの場合はstopの引数は必須となっており、設定しないと例外が飛びます。playで引数を指定しない場合は例外が飛ばないので、不思議な挙動です。

source.stop(0);

音量を調整するには、gainNodeを使用します。

var gainNode = context.createGain();
gainNode.gain.value=gain;
source.connect(gainNode);
gainNode.connect(context.destination);
source.start(0);

WebAudio APIを使うと、iOSのMobile Safariでも、ネイティブゲーム並みの音声操作ができてオススメです。Androidは標準ブラウザは未対応で、Chromeでは対応しています。

YosemiteにEmscriptenを導入する

Emscriptenを使うと、C++のコードをJavaScriptに変換してブラウザで実行することができます。また、OpenGLのコードも自動的にWebGLに変換され、ブラウザで実行することができます。

Emscriptenは、C++をLLVMバイト・コードに変換した後、JavaScriptに落とします。そのため、LLVMとnode.jsに依存しています。Emscriptenはgitから直接インストールすることもできますが、LLVM3.4を要求されたり、fastcompを自分でビルドをしないといけなかったりします。公式のSDKを使うと、依存するライブラリ全てを自動的にインストールしてくれるので楽です。

Emscriptenのページから、Emscripten SDKをダウンロードします。

SDKのDownload

ダウンロードしたemsdk-portable.tar.gzを解凍してできたemsdk_portableで、emsdk update、emsdk install latest、emsdk activate latestを実行します。

1. Download and unzip the portable SDK package to a directory of your choice. This directory will contain the Emscripten SDK.
2. Open a command prompt to the directory of the SDK.
3. Run `emsdk update`. This will fetch the latest registry of available tools.
4. Run `emsdk install latest`. This will download and install the latest SDK tools.
5. Run `emsdk activate latest`. This will set up ~/.emscripten to point to the SDK.

インストールが終わると、emsdk_portableのフォルダ構成は以下のようになります。

README.md		emsdk			node
clang			emsdk_env.sh		zips
emscripten		emsdk_manifest.json

emsdk_portable/emscripten/1.27.0に移動します。hello.cppを作成します。

#include 

int main()
{
    printf("hello world\n");
}

以下のコマンドでコンパイルします。

./em++ -o hello.html hello.cpp

hello.htmlとhello.jsが生成されるので、hello.htmlをブラウザで開くと実行されます。

emscripten

hello.jsは356KBもあります。Looking through Emscripten outputにあるように、-O2 --closure 1を付けると89KBになりました。stdio.hをincludeしてもしなくても、これぐらいの容量になります。

スタック管理などの固定で消費するjsの容量が大きいので、C++のファイルを1つずつjsにするのではなくて、個別にバイト・コードにコンパイルした後、まとめてjsにするのがよさそうです。

External Interface的に、C++のコードからJavaScriptライブラリのメソッドを呼び出す場合は、--js-libraryオプションを使うとよいようです。(EmscriptenでC言語をJavaScriptに変換する

ネイティブとHTML5の共通フレームワークを作る場合は、C++でインタフェースを切っておいて、ネイティブ向けにはC++のコード、HTML5向けには--js-libraryで外部のJavaScriptコードを呼ぶ感じでいけそうです。

WebRTCとVideo、Audioタグの互換性まとめ

WebRTCとVideo、Audioタグの互換性まとめです。テストはMacで行いました。IEはParallels経由のWindows8.1です。

WebRTC(マイク)Video(mp4)Video(mp4を2つ同時再生)Audio(mp3)getCureentTime
IE 11非対応OKOKOKOK
Safar i8非対応OKOKOKOK
Chrome 38OKOKOKOKOK
Firefox 31OK非対応非対応OKOK
Android 5遅延大OKOKOK低精度
iOS 8非対応強制全画面再生非対応OKOK


WebRTC。PCではChromeとFirefoxのみ対応。モバイルではAndroidのみ対応です。Nexus5では、スピーカーとマイクの位置の問題から、ハウリングしやすい傾向はあります。

Videoタグ。Firefox以外はmp4が再生できます。Firefoxではtheoraかwebmにする必要があります。また、iPhoneのiOSは強制的に全画面再生になります。iPadはページ内再生可能です。

Videoタグの同時再生。PCとAndroidは問題なく2つ同時再生が可能です。iPadのページ内再生の場合、同時に2つは再生できず、最後に再生命令を送った1つのみが再生されます。

Audioタグ。mp3は調査した全ての環境で動作しました。Firefoxはmp4が再生できないということで、mp3もダメなイメージだったんですが、最近は問題なく再生できるようです。尚、iOS 8のSafariはhttps経由ではmp3を再生できません。

getCureentTime。PCとiOSは20msec程度の分解能で取得できます。Androidは200msec程度の分解能しかないので、音ゲーとか作る時は、タイミングの取り方を考える必要がありそうです。

WebRTCのテストにはWiiUのワイヤレスマイクを使用しました。Macでも挿すだけで使えて便利です。

IE10のModernStyleでスクロールとズームを抑制する

タッチデバイス向けのお絵かきアプリやゲームをHTML5で作る場合、スクロールやズームを抑制したいことがあります。iPadやAndroidの場合はmetaタグのviewportで抑制できますが、IE10ではWebkitのmetaタグは動作しません。 IE10では、bodyのCSSでスクロールとズームを抑制します。-ms-touch-action:none;でスクロール禁止、-ms-content-zooming: none;でズーム禁止です。

<style>
	/* for IE10 */
	body{
		-ms-touch-action: none;
		-ms-content-zooming: none;
	}
</style>

WacomのJavaScript筆圧プラグインがChromeに対応

Wacomが公開している、JavaScriptから筆圧を取得できるWacomTabletDataPluginが更新されました。最新版は、Windowsが2.1.0.3、Macが2.1.0.2です。

TabletDataPluginは、version2.0系まで、IE8やChromeにおいて、キャプションが外れると筆圧が取得できなくなるという問題を抱えていました。それが、version2.1系で改善され、メジャーなブラウザで問題なく動作するようになりました。

さっそく、イラストブックにも導入してみましたので、以下からお試し頂けます。


筆圧を使って試し描きしてみる


最新のWacomTabletDataPluginは、Wacomのドライバの最新版を入れると自動的に入るので、導入コストも低いかと思います。
Wacomのドライバのダウンロード

イラストブックで使っている筆圧取得の参考コードは、Githubからどうぞ。
wacom_tablet_plugin_ver2.js

Google In-App Payments APIの仕様を調べてみた

グーグル、ウェブアプリ内課金サービスを開始--「Chrome Web Store」以外も対象に

本日、GoogleからIn-App Payments APIが公開されました。これを使うと、あらゆるWEBサイトで、簡単なAPIを使って課金することができます。



まだ、米国の銀行口座を持っている開発者でなければ使えませんが、そのうち国内でも使えるようになると思うので、APIの仕様を調べてみました。APIの使い方は、Getting Startedのページにまとまっています。以下は、実際に実装したわけではないので、間違っている部分もあるかもしれないのでご了承下さい。

まず、サーバサイドでJSON Web Tokenというものを作ります。このトークンには次のように、課金する商品の内容や価格を入れて、秘密鍵で符号化します。

"name" => "Piece of Cake",
"description" => "Virtual chocolate cake to fill your virtual tummy",
"price" => "10.50",

符号化には、Google提供のJWTライブラリを使用します。Ruby、Python、Java、PHP、.Netと、ほとんどの環境のライブラリが用意されています。具体的に、Pythonのライブラリでは
 jwt.encode({"some": "payload"}, "secret")
のように符号化します。符号化結果は暗号化はされませんが、
 jwt.decode("someJWTstring", "secret")
によって、認証することができます。decodeは後で使用します。encode/decodeの実際の処理は、jwt/__init__.pyで確認することができます。

次に、クライアントサイドのJavaScriptでpayment APIのライブラリを読み込みます。JavaScriptでは課金完了と課金失敗のコールバック関数を定義しておきます。課金が完了すると、これらのコールバック関数が呼ばれることになります。課金完了のコールバック関数の中で、プレイヤーのライフ回復など、課金成功の実処理を記述することもできますが、コールバック関数をFireBugなどで直接呼ぶことができてしまうので、推奨されていません。課金結果は、サーバサイドのデータベースの中で反映させるのが望ましいです。

最後に、ボタンなどを押した場合に、goog.payments.inapp.buy関数を呼び出します。関数の引数には、最初に作成したJSON Web Tokenと、コールバック関数を与えます。これによって、ユーザに課金を促すウィンドウを開くことができます。

ユーザが課金を実行すると、課金の完了が、設定したpostback URLに対して、POSTメッセージで届きます。postback URLは、SandBoxの設定ページ、およびreal merchant accountの設定ページで設定します。POSTメッセージのデータには、buy関数で与えたJSON Web Tokenが、オーダ番号が付加された形で格納されています。これを、秘密鍵で次のように認証します。

 jwt.decode("someJWTstring", "secret")
 If the secret is wrong, it will raise a jwt.DecodeError.

認証後、正常に購入したアイテムなどのデータをサーバに書き込んだ後、200 OKを返します。その後、JavaScriptのコールバックに課金完了が通知されるわけです。

aaa


Google In-App Payments APIの手数料は何と5%!びっくりするぐらい安いです。従来、クレジットカードの課金システムというのは高い初期費用と、年間維持費用がかかってしまって、とても個人で使える代物ではありませんでした。それが参入障壁となり、アプリストアや電子書籍ストアなどのプラットフォームを個人で作るのはほぼ不可能だったのですが、Google In-App Payments APIで可能になります。これで何ができるようになるかというと、個人でもパブーのようなプラットフォームが作れるようになるのです。

サーバはGoogle App Engineを使って自動でスケールさせて、ユーザにコンテンツをアップロードしてもらって、ユーザがコンテンツを購入した場合にGoogle In-App Payments APIを使用して決済をして、手数料を得る。そこまで自動化したプラットフォームが誰でも作れるようになります。これは革命的なことです。

後は、国内でも使えるようになって、WEBマネーのようにコンビニでプリペイドカードを買えるようになって、さらにAndroidと同じ決済システムであるGoogleCheckoutを使っている利点を活かして携帯キャリア課金までできるようになれば最強ですね。一時の閉塞感を抜けだして、Google+、GoogleCheckout、GoogleAppEngine、Androidと、未来に繋がるプロダクトが出てきて、最近のGoogleは元気でいいですね。

WACOMがJavaScriptから筆圧を取れるプラグインを公開していた

WacomTabletPluginです。完全に見落としていました。サンプルリファレンスもあります。ものすごい簡単なので、サンプルを見ればすぐに使えると思います。

具体的に、

< !--[if IE]>
< object id='Wacom' classid='CLSID:449E4080-7C69-4767-A1AE-6AAE25B0B906'
codebase="http://www.wacom.com/U/plugins/Windows/WacomIE.cab#Version=-1,-1,-1,-1">< /object>
< ![endif]-->
< embed name="wacom-plugin" id="wacom-plugin" type="application/x-wacom-tablet" HIDDEN="TRUE" pluginspage="http://www.wacom.com/productsupport/plugin.php">
< !-->

でプラグインを読み込んでおいて、

function getWacomPlugin()
{
 return window.Wacom || document.embeds["wacom-plugin"];
}

function getPressure()
{
 if(!m_is_wacom) return 0;
 return getWacomPlugin().pressure;
}

function initWacom()
{
var isWacom = getWacomPlugin().isWacom;
if ( isWacom == undefined )
{
m_is_wacom=false;
}
else if ( isWacom == 0 )
{
m_is_wacom=false;
}
else
{
m_is_wacom=true;
}
}

とするだけで筆圧が取れます。素晴らしい!

従来、FLASHで筆圧を使うには、JAVA仮想マシンを通してJtabletを呼び出さなければならなかったんですが、WacomTabletPluginを使うと、JAVA仮想マシン無しで筆圧が取れるようになります。動作プロセスが一つ減るので、かなり高速化されて素晴らしいです。早速、ILLUST BOOKではWacomTabletPluginを使った実装に変更しました。getWacomPlugin().isEraserで消しゴムモードフラグも取れるのもいいですね。何気に英語サイトしか無いあたり、Wacomはグローバル企業だなぁとかも思いました。

GoogleClosureCompilerを使ってJavaScriptを圧縮して容量を削減

1d399045.jpgGoogleClosureCompilerはJavaScriptのコードを最適化して圧縮してくれるコマンドラインツールです。まず、GoogleClosureCompilerのページの右側のFeatured downloads:からcompiler-20091217.zipをダウンロードします。zipを展開して入っているcompiler.jarが本体です。

in.jsを圧縮して、out.jsに出力するには、次のように入力します。簡単。
 java -jar compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS --js=in.js --js_output_file=out.js
SIMPLE_OPTIMIZATIONSを指定することでローカル変数名を短いものに置換してくれます。

メトセラで実行した結果は以下です。
・元ファイル:918KB
・自作ツールで改行とコメントを消去:623KB
・GoogleClosureCompiler:565KB

元ファイルからは39%減、そこそこ最適化したファイルからは9%減です。特にモバイルだと、ロード時間が直接ユーザビリティに響いてくるので、10%減るのは大きいですね。ちなみにFlashではバイトコードにまで落ちるので218KBになります。この差は、グローバル変数名と関数名ではないかと考えています。

最適化テクニックもすごくて、
  activity_thre[p]=2500;

  activity_thre[a]=9E4;
と16進数に置換することで容量を削減していたりもします。その発想は無かった!

さらにGoogleClosureCompilerは文法チェックもしてくれます。

compress.js:25637: WARNING - unreachable code
if(name=="")
^
compress.js:27746: WARNING - Suspicious code. This code lacks side-effects. Is there a bug?
if(player_y[i]>=511) player_y[i]>=511;
^

のように、到達しないコードや、代入を間違って比較にしてしまった部分とかを警告してくれます。JavaScriptはインタプリタなので非常に助かります。GoogleClosureCompiler、かなりオススメです。
Search
Profile

abars

アプリとWEBサービスを開発しています。最近はUnityとGAE/pyが主戦場。

ブラウザ向けMMOのメトセライズデストラクタ、イラストSNSのイラストブック、東証の適時開示情報を検索できるTDnetSearchを開発しています。

かつてエンターブレインのTECH Win誌でATULADOを連載しました。

サイト:ABARS
Twitter:abars
Github:abars

Twitter
TopHatenar
HotEntry
Counter

アクセス解析付きカウンター。あなたのBLOGにもどうですか?登録はこちらから。

TOP/ BLOG/ LECTURE/ ONLINE/ RUINA/ ADDON/ THREAD/ METHUSELAYZE/ IPHONE/ MET_IPHONE/ ENGLISH/ RANKING