ばかおもちゃ本店:Youtube twitter:@sashimizakana Amazon.co.jpアソシエイト

2013年12月21日土曜日

AngularJSのscopeの継承とかを理解する

まえおき

本稿はAngularJS Startup AdventCalendar2013の21日目です。
20日目:AngularJSをTypeScriptで書くときのあれこれ - Qiita [キータ]

scopeについて

scopeはAngularJSでビュー側に値を渡すときに利用するサービス。
たぶん知ってると思う。これがビューとコントローラーがデータをやりとりする。
で、今回はちょっとAngularJSをさわり始めると公式ドキュメントなんかあちこちに出てくる、新しいscopeが作られるっていう部分について書く。
ディレクティブなんかのAPIを読んでると出てくる。このディレクティブは新しいscopeを作りますって、あれってなんなのか。

scopeの生成と継承

scopeは一番上位に位置するrootScopeの下に階層化されて作られていく。
scopeはJavaScriptのレキシカルスコープみたいにブロックを持ち、親子関係を持つ。
なのだけど、少しだけjavaScriptのスコープとは違う部分がある。ここがちょっとだけわかりにくい。

一般的にディレクティブを作るときにscopeを作ることが多いので、それを例に取って説明する。
ディレクティブの作成時にscopeの生成には、false(作らない:デフォルト)、true(作る)、オブジェクト(親を継承せず作る)ってのがある。
一応比較対象としてfalseの作らないやつからfiddleに例を作った。

AngularJS Scope-1 - JSFiddle

これは見たまんまでディレクティブ内でいきなり親スコープのプロパティを読んでるけど、問題なく表示されているし更新も出来る。念のために書いておくと、これはサンプルなのでそういうことをしているけど、普通にこんなことをするとモジュール間の結合度が上がりすぎて最終的に動かないプログラムを作ることになるのでやってはいけない。
ダメ絶対。

普通にやる場合はlinkの第三引数(attrs)からタグに設定された属性の中身を読みとってscope.$watchで受け取ったりする。
なんでそう書いてないのかというとコードを短くしたいってことと、この後のサンプルの意味が分かりづらくなるから。

というわけで、trueを設定した場合。

AngularJS Scope-2 - JSFiddle

trueとfalseが変わっただけだけど、子+を押すと親+は変更されず、以後はまったく独立してカウントされるようになる(なので先に親+から押してください)。これがAngularJSのscopeがJavaScriptのスコープと違う部分で、つまり親を継承して子スコープを作った場合は、親の値は参照可能だけど上書きすることはできないということ。
上書きしようとすると変数名などはそのままに、別の値として作成されてしまう。
これを知らないで居ると全く意味不明な挙動に見えるときがある。

たとえばng-includeなどでもこんな風にscopeは作成される。そのため、たとえば親のscopeの値をそのまま利用して、かつng-include内部でちょこっと数値を変えるようなものを書いてしまうと、親の方で値を操作しているうちは良いけど、ng-include以下で操作すると急に親から値が読めないなどということが起きたりする。

で、最後がscopeにobjectを指定した場合。

AngularJS Scope-3 - JSFiddle

これは親を継承しないので、親の値は全く参照することが出来ない。
つまり動きません。お使いのPCは正常です。

ただこのobjectに親から継承したいものを設定することができる。ここではすべては詳しく書かないけど、親のscopeの変数を変更可能な状態で受け取ることとか、子のDOM内にのみ入れることとか、親のcontextで実行させるとか(ng-click="hoge()"みたいなやつのこと)、ができる。

値を受け取る場合はプロパティ名が子scopeでプロパティ名にしたい名前にして、その値を"=自分のDOMの属性名"にする。つまり<div hoge="***">みたいな場合、scope:{myValue:"=hoge"}というようなこと。
ちなみに子scope内で属性名と同じ名前を使うときは属性名は省略可能。
{hoge:"="}ってな感じ。

いちおうサンプル。

AngularJS Scope-4 - JSFiddle

まとめ

具体的にどういうときに使うんだって言う例を作っておきたかったけど、時間がなかった。実際にバリバリ書いてると絶対に分かってないとダメな局面があったはずなんだけど、なかなかちゃんと再現するコードを書くのはむずかしい。
でもjQuery拡張とかをディレクティブに放り込んでAngularJS対応にしてたりとか、複数のディレクティブをタグに付けまくったりしたりすると、なんか値が上手く変わらんとか思うことがあった。でもこのあたりを理解してからは問題なくなった。

scope作るときに実際どれ使えば良いかっていうので言うと、普通に使うだけならオブジェクトを渡して必要なプロパティだけ共有するのがおすすめ。安全だしミスを起こさないので良いと思う。

余談

$watchで値を受け取るとき、受け取った値がオブジェクトとか配列とかだと参照渡しされているのでscope:trueに設定してあってもそのオブジェクトのプロパティへの変更とかは通常通り行われて親scope側の値に影響する。
まあでも関数の引数と同じ。

2013年12月15日日曜日

AngularJSでゲームをつくる「艦隊くりっかー」

まえおき

これはAngularJS Startup AdventCalendar の15日目の記事です。
14日目:AngularJSとAngularJSモジュールでi18nを実現する(2) - Qiita [キータ]

本稿ではAngularJSでゲームを作ったときに気づいたこととかを元に、どんな感じでアプリケーションを構成するかをざっくり書きます。実際のゲームを作る上でのTipsとかってよりは、基礎的なディレクティブとかサービスの使い方中心ですが、ゲームの実例も多少書くのできっとどう分けるかを理解できるはず。で、それが把握できればゲームをどう作るかもわかるはず。
一応ある程度AngularJSの基礎用語くらいは聞いたことあるくらいの人対象です。
それのどこがスタートアップなんだとか気にしない。泣かない。
ちなみにAngularJSはゲームを作るのに適したフレームワークではないです。
もっとも数値を操作するだけのゲームならAngularJSでも十分です。
そういうわけでAngularJSやろうぜ!

自己紹介

ばかおもちゃ本店という名前でニコニコ動画に電子工作とかの動画をあげています。
全自動スカートめくり機とか、念力スカートめくり機とか、そういうのを作りました。人様に言いづらい。

そして本稿で説明する艦隊くりっかーという二次創作ではない(重要)ゲームを作りました。

艦隊くりっかー?

艦くり - Kantai Clicker

CookieClickerのクローンです。
本当は更に艦隊これくしょんの二次創作のつもりでしたが、ゲームは禁止されているので、
キャラクター要素を削って良くわからない艦隊これくしょん便乗商品のようなものになった。
数値を増やすために数値を増やすという超単純なゲームです。

(本文と関係のない画像です)

AngularJSアプリの大まかな構成

AngularJSのアプリケーションは、ざっくり以下の様な構成になる。

directive
ディレクティブ。HTML内に埋め込んで表示を制御する。値の実際の入出力を処理する。
配列渡されたらフォーマットしてリスト出したり、入力値を値にセットする。

controller
コントローラー。ng-controllerで呼ぶとそのタグの階層以下のscopeを管理できる。
scopeってのはAngularJSでビューと値をやりとりするときのオブジェクトのこと。

service
サービス。値を保存したり読み込んだり、それに伴う通信したり。
もちろん値への操作も入れちゃって構わない。いわゆるモデル。

filtter
フィルター。リストの内容を変えたり値を整形したりするディレクティブの補助的なもの。
今回使ってないのでもうこれっきり出てきません。

つまりAngularJSはHTMLに利用するコントローラーとか含めてdirectiveでテンプレートを書いて、
controllerがそのdirectiveとserviceの間の値のやり取りをscopeってのを使ってやる。
なるほど、かんたん。

各部の詳細とか

以下、詳細というか使ってる時に思ったこととか、注意点みたいなのをまとめる。

controller
AngularJSの公式のサンプルなんかを見て、モジュールを分けることを意識しないで書くとファットコントローラーになって手に負えない状況になりがち。見た目は全部ディレクティブ、値の操作はサービスでする。
ここで値を直接変更してたり、見た目に関連するフラグの変更とかやってるならたぶん間違ってる。
コントローラー間での値の受け渡しとかで悩んでたりするなら考え方が根本的に違う可能性が高い。

directive
雑に言うと、この中でならjQueryとか素で使ってもOK。
なのでjQueryの拡張とかをそのまま使うときもこの中に閉じ込める。
directiveのcompileの第一引数とかlinkの第二引数とかはディレクティブがつけてある要素そのものなのだけど、これはもともとjQueryオブジェクトの形で渡される。
ちなみにAngularJSよりjQueryを先に読み込んでないとjqLiteという機能縮小版になる。
(たしかfindとかなかったりremoveが無かったりして不便なときが多い)

余談だけど、linkのサンプルコードで第一引数のscopeに$マークがないのは、ここは名前で引数が決定されるわけじゃなくて、普通に順番で引数が決定するからだとか何とか。
ECMA3で機械的に挿入されたコードのみで$の利用が許可されるとか言ってるのと関係有るかも(ないかも)。


書き始めると終われないので飛ばしていくけど、directiveはscope周りが一番面倒なので注意深く勉強するといいかも。
親の値をそのまま変更可能だったり(scopeが未設定かfalse)、親の値が上書きのみ別の値になるか指定したもののみ上書きも可(scopeがtrueかオブジェクトで指定)とかある。
ちなみに普通の引数と同じくオブジェクトの場合は参照で渡されるので、falseでもオブジェクトのプロパティの変更のみは出来たりするので混乱の元になる。
自分の作ったディレクティブにng-hideとかを組み合わせて使うつもりが無いなら、スコープは常に作ったほうが事故ることが少ないと思う。
逆に言うと、親スコープ内で使うつもりなら、スコープをそもそも使わないか、親スコープと絶対にかぶらないような名前で利用しない限り危険。うっかり名前かぶったりするとミスに気付きづらくて泣く。

service
複数画面のアプリケーションの場合もserviceはシングルトンなので、データは共有される。
これ重要。
angular.('モジュール名',[依存モジュール...]).factory('ディレクティブ名',[利用サービス...,function(){
    return サービスのオブジェクト;
}]);
みたいな感じで作るわけだけど、もちろん、
var MyService = function(){
    this.initialize.apply(this,arguments);
}
MyService.prototype = {
    initialize:function()...
}
return MyService;
みたいにクラス渡して、コントローラー側で、
['$scope','MyService',function($scope,MyService){
    var svc = new MyService();
}];
てな感じで使ってもいい。
私はこういう感じのクラスにデータ取得するメソッドとキャッシュとか持たせて使ったりしてる。
var MyService = function(){
    this.initialize.apply(this,arguments);
}

MyService.prototype = {
    initialize:function()...
}

MyService.cache = {};

MyService.getData = function(id){
    if(this.cache[id]){
        //キャッシュにあればそれを返す
        return this.cache[id];
    }

    //なければバックエンドとかからデータ持ってくる
    var svc = new MyService(バックエンドから持ってきたデータ);
    this.cache[id] = svc;
    return svc;
}
return MyService;
でMyService.getData(4);みたいな感じで呼び出す。
factoryが呼ばれるのは最初の一回だけなので、複数画面とかならどの画面を最初に開いても、データが既に読み込まれてたらキャッシュを呼ぶし、そうでないならバックエンドからデータを持ってくることになる。
一覧と詳細のリストを持ってて、詳細を開くと追加データを読んでキャッシュするとかそういう使い方に便利。有効期限とかキャッシュの強制削除とかそういうのもいるかも。

小休止

何回、controller、directive、serviceって繰り返すんだよクソっ! って気になってきたかと思いますので本文とは特に関係ない挿絵を御覧ください(あと一回繰り返します)。

艦隊くりっかーでの全体の構成

敵のパラメーターと説明、施設のパラメーターと設定なんかはjsonに書いてある。

controller
データの保存とかロードをやってるだけ。
上記のjsonのデータを呼び出すserviceとかクッキーの入出力serviceとかの実行。でその値をscopeに入れるだけ。

directive
ディレクティブとして作ったのは、体力とか経験値のバーと船の部分、施設の部分。
今見直すと、施設の部分はディレクティブとして分ける必要性が薄いし、船の部分も含めてビジネスロジックまで書いててまずい。
体力とか経験値のバーは与えられた数値で要素の長さを変えてバーっぽく見せてるだけ。
船の数値のやつは、$rootScopeのイベントを見張って攻撃されたりクリックしたら渡された数値を表示するだけ。
この辺後述するけど、$watchをどこでも使うよりイベントのがいい感じの時も多い。

service
ディレクティブと同じく分離がうまく言ってない箇所があって構成が説明しづらい。
本来だとユーザー関連と敵関連と施設関連を分離してそれぞれがクッキーへの入出力サービスに依存してるような感じにすべきだったと思う。で、クッキーへの入出力モジュールがロード時にデータをキャッシュしたり、一定時間おきにデータの変更を確認して保存すれば良かった。
ちなみにAngularJSのクッキーモジュールはブラウザ閉じるまで以外の有効期限を設定できないので、
クッキーへの書き出しとか読み込みとかは自前で作った。

だいたい終わった

というあたりで大まかな構造はだいたい語れたので満足した。
つうかそんな複雑な構造してない。
あとその他開発中に思ったことを列挙。

・クッキーすげえ壊れる

クッキーは壊れる。ポッケに入れて膝に矢を受けたら真っ二つ。
結構長いデータをJSONにしてbase64にしただけっていう横着なやり方だからか結構壊れた報告を受けた。
受けたから、テキストで保存できるようにしたのだけど、根本的に直す方法は良く分からない。
確認した限りでは全部真っ白になるわけではなくて、後半データが切れるみたいな壊れ方が大半だったので、容量に余裕があるなら一つ前の状態も保存して、壊れてたら前のデータ参照みたいなやり方ならまだ被害は少ないかもしれない。

・イベント利用($emit,$on)のすすめ

普通AngularJS的には、各ディレクティブ内で見た目とかが変わるときは依存性として渡してあるモデルを$watchしてその状況に応じて変更するみたいなやりかたが常道っぽい。
ただこれだと、っていうかゲームのようなDOMの見た目変更が複数条件で決定されかつ複雑なときには、ディレクティブに片っ端からサービス渡したりすることになって現実的じゃない。
しかも今回は小規模なので問題になってないけど、私がやっちゃったみたいにディレクティブ内でサービスのデータ変えたりするともう目も当てられない。
どこで何が変わっているのか、どこに何が依存しているのかの把握がむずかしくなる。
でっかいオブジェクトなんかをまるごと$watchするのがあちこちにあるとこれもまた怖い。
そのへん、イベントは投げたところと受け取るところがはっきりするので、ある程度統制を取りやすい気がする。

自データサービスは敵に攻撃されたことをイベントで受け取って、引数の攻撃力に応じて自分の艦数を減らして、
もし0になったら敗北イベントを発生させる。
敵サービス側は攻撃状態にある間は一定時間おきに攻撃イベントを発生させて、プレイヤー側の攻撃、またはクリックのイベントを受けて自分の艦数を減らして、もし0になったら敗北イベントを発生させて攻撃状態を解除、あるいはプレイヤーの敗北イベントが発生しても攻撃状態を解除する。

というような感じ。

・ぐるぐる回る

そもそも上記のように$watchを多用してオブジェクトとかを監視しまくる構成になると、把握が難しいならまだしも最悪の場合はループするし、そうでなくても無駄な呼び出しが増える傾向にある。
これは大変に厄い。
最初のうち何も考えずに$watchを活用しまくって適当に書いていると、なんか知らないけどこのプロパティ変えただけで、関係ない処理が山ほど流れるなんてことになったことがあった。
filterなんかとくにそうなりやすい。console.logで出力してみると何故かちょこっと動かすたびにフィルタ動いてるみたいになる。
オブジェクトのプロパティも監視対象にできるのであんまり大きなオブジェクト全体を見張らないで、必要な部分だけにすべきなのだと思う。
(わざわざ第三引数にtrue渡さないとプロパティを含めたオブジェクト全体は見張らないし、もともとそういう想定なのだと思う)

まとめ

個人的な印象で言うと、アクションゲームみたいな動きの多いものでなければ、AngularJSでゲームを作るのは結構簡単で楽しいのではないかと思いました。$watch周りとか$scope周りはややこしいこともあって、混乱することもありますが、その辺をある程度整理したり、こういうことはすべきではないということが分かれば、本当に楽に書けて良いと思います。
時間と場が残っていればこのAdventCalendar内で、scopeあたりについても書ければいいなと思います。

宣伝

艦くりは今年年末から来年初くらいまでの間にアップデートを予定しています。
ちなみに私が作ったゲームやおもちゃその他や、それらの制作動画のお知らせはこのブログ(RSS)か@sashimizakanaに掲載しています。
君もばかおもちゃの最新情報をチェックだ!

2013年12月11日水曜日

安いTEGRA NOTE7で液タブみたいにお絵描きしてみる

TEGRA NOTE7を買った。
TEGRA NOTE7は最近はやりの7インチタブレットの一種で、最大の特徴としてはTEGRA4というグラフィック描画にバッキバキに特化したコアを搭載していることで、値段は¥25,800とNEXUS7よりちょい安いくらい。もっともメモリや液晶の解像度なんかでは一段下のスペックになっている。ではなぜTEGRA NOTE7を買ったかというと、それでもGPUの性能のおかげで各種ベンチマークなどでは完全にTEGRA NOTE7が買っていることと、その高い画像処理能力を使って、標準で筆圧対応のスタイラスがついているからだ。
といっても筆圧感知の方式自体は一般的なものと変わらず接地面積の多寡で認識しているようだが、感度が非常に高いためペン先をスリムに作れ、かつ形状の変化をさせなくても利用できるというのが一番のセールスポイントなのではないかと思う。
(現状の一般的なスタイラスは先端に丸いゴム球がついていてこれが潰れることで接地面積を変えるというものが多く、普通に絵を描く向きにはそのゴム感が使いにくいとされることも多い)

というわけで、本稿ではそのスタイラスでお絵かきをすることに絞ってレビューをする。

外観

サイズはNEXUS7と似たようなもの。フロントの上下(左右?)にスピーカーがあって音が良い。

裏面。おしゃれというよりはいかにもビデオカードメーカーっぽいガッチリ感。

スタイラスは本体に収納されてて、引き出すとランチャーが起動してお絵かきソフトを選べる。

ペンは細めなので筆圧をかけるタイプの人は疲れるかも。個人的には見た目よりは描きやすいと思う。

アプリ

スタイラスを使うためにTegraDrawというアプリとWriteというアプリが付属する。
Writeはメモ書き用のソフトなのでここでは省略する。
で、TegraDrawなのだけど、たしかにペンの書き心地は良い。入りも抜きも私の好きな筆圧だけで大きく線の太さが変わるのでなかなか気持ちよく描ける。ただ、このソフトは少なくとも現段階ではお絵かきに使うにはあまりにも足りない。

TegraDrawで適当に落書き中。

なにも私はレイヤーが無いとかそういう高度な機能がないと不平を言っているわけではない。このソフトで使える色は上の写真に表示されているものですべてなのだ。それならそれで色をいい感じに選んでくれればまだどうにかなりそうなものなのに、選ばれている色も一昔前のofficeみたいな原色とその彩度を落としたようなパレットで、およそ絵を描きたくなるような色ではない。
ペンの感触としてはかなり良いだけに大変残念だが、今の段階ではあまり使い物にはならない。

で、じゃあこれは使いものにならないのか、というとそんなことはない。
前述の通り、筆圧感知方式は一般的なものと変わらないため、いくつかのアプリで試してみたところ、まともに筆圧を感知してくれた。接地面積が普通のスタイラスより小さいことが問題にならないかと心配だったが、特にわからなかった。使い比べてみると違うのか、あるいはそういう部分はハードウェアの内部でソフトウェアに渡される前に処理されているのか、詳しくは分からない。

使ってみたアプリと、描いてみた絵

TegraDrawは色も選べないんですよ! とか言った直後に出すのは心苦しいんですが、このソフトは色は全く使えません。グレースケールだけです。それも普通に使う分には三色のみ。拡大・縮小等々お絵かきソフトとして必要な機能はほぼない。
でも、このソフトはペンの描き心地が最高で大好き。




無料版もあるけど、気に入ったので有料版を買った。

SketchBook Pro

たぶんAndroidのお絵かきソフトとしては一番完成度が高いであろうやつ。
レイヤーとか拡大縮小とか、必要そうな機能は全部入り。
ペンもものすごく精緻で追従性が高く書かれる感じで、そのあたりは私の下手さが余計出るのであまり好きではない。機能が多すぎるのもちょっと疲れるなと思う。ただばかおもちゃ本店の専属イラストレーターこと私の妻はもともとグラフィックソフトに親しんでいる人なので、簡単に使いこなしていて気に入ったようだ。
以下妻が走り書きしたもの。



色を塗るのには良いのでZenBrushで描いたものに乗算で色を乗せるとかでもいいかも。

当然私の絵である。

というわけで、液タブを買う金はないし、iPadですらまだ高いし、ついでに早くて安いAndroidタブレットが欲しいという人にはかなりおすすめできるのではないかと思う。お金がある人はCintiqとかiPad+Bluetooth接続系のスタイラスとか買えばいいかと思います(使ったことないけど)。



ZOTAC NVIDIA TEGRA NOTE 7 [Androidタブレット] ZT-TN701-10J
ZOTAC
売り上げランキング: 4,490
実際NEXUS7より安いし、デザインとかGoogle製だとかにこだわらないなら絵とか関係なくても大変おすすめ。

2013年12月9日月曜日

本当にカップラーメンが更に旨くなる魔法の粉なのか試した


すこし前にネットニュースで話題になっていた味源のカップラーメンが更に旨くなる魔法の粉を買った。
この商品は名前の通り、俺達の大好きなカップ麺にふりかけると更に旨くなるとかというもので、魔法がかかってるらしい。魔法、粉、ブラック(ペッパー)と聞くといろいろな感覚が覚醒してしまうようなものの利用が疑われるが使われてません。原材料を見る感じ、魔法の正体はさば節とかかつお節とか一般的な調味料っぽい。

というわけで安心したので食べよう。



ドサァ。
分量は小さじ1~3。

はい、かけすぎた。
コショウ効きすぎになって何がなんだかわからない。

このあと、色々な袋麺とかカップ麺とかうどんとかに試して見たけど、うどんを除いていい感じに魚介系の味に変わるのでなかなか良かった(うどんはなんかどこかに味が消えて良くわからない感じになった)。
もっとも味そのものが強いので、色々なラーメンで変化が楽しめるというよりは、入れ過ぎると何に入れても同じ味に落ち着く傾向が強い。そのため最近はある程度ラーメンを食べたあとで、最後のほうで小さじ半分くらいを入れて元の味とのミックスを楽しむ感じになった。

ただその同じ味ってのがなかなか悪くないので、まずいカップ麺にあたってがっかりみたいなときには、これをふりかけてやればある程度美味しくなるので、そういう使い方もあるかなと思う。




レッドペッパー味もためしたい。

2013年11月23日土曜日

まどか☆マギカ新編の特典フィルムをamazonで買った安スキャナで取り込んでみた

※劇場版のネタバレはありませんが特典のフィルムの画像がありますので
 すこしでも見たくないという人は注意してください



まどか☆マギカ新編みてきた!
もちろん特典のフィルムももらった!


分からん。
どこのシーンか分からん。
こっちがわけがわからないよである。

もうちょっと拡大すれば分かるかもしれない。
それならフィルムスキャナで取り込めば良いのでは無いかと思った。

フィルムスキャナというのは普通のスキャナと違って、写真のフィルムをデジタルデータ化するために、後ろから光を当ててその透過光を取り込めるスキャナである。もっとも普通のフラットベッドスキャナでも高級機ならフィルムを読めるやつとかオプションが追加できるようなやつもあるらしい。
これが最近では結構安いやつもあって、amazonで数千円で購入することができる。

もっともそれらは前述の通り、写真を取り込むためのもので映画のフィルムが読めるとはどこにも描いていない。ただ一般的な映画用のフィルムと写真のフィルムは35mmで同じ規格なのだ。それならば読めるはずだ。普通の写真のフィルムとは見た目が違うじゃんと思うかも知れないが、それはネガフィルムという反転しているフィルムだからで、写真のフィルムにはポジフィルムとかリバーサルフィルムという色が反転していないものもあり、フィルムスキャナはそういうのも読めるのである。


つうわけで買った。けっこう大きい。
右側においてあるのがフィルムをスキャンするためにセットするマウントである。右のが普通のフィルムとかの6枚用のやつで、左側のはポジフィルムなんかをスライドにしてもらったときにつかうやつである。


サイズはぴったり。
ただ、映画のフィルムは普通の写真の半分程度のサイズなので、一つ分の窓から二つ見えることになる。ちなみにハーフサイズっていう一本のフィルムで倍とれるっつうカメラがあって私の子供の頃実家にあったカメラがそれだったんだけど、サイズはそれに近いらしい。


で、ぐりっとクチの部分にマウントをねじ込む。このへん手動。
付属のアプリケ-ションでだいたいリアルタイムにプレビューを見ながら取り込める。

実際に取り込んだ画像がこちら。


やはりよく分からん。なんか最後の方な気もする。
輪郭とかすごいボケてる感じがすると思うがこれは絵に光りのエフェクトみたいなものがかかっていて、わざとボカされているんじゃないかと思う。
で、こんなもん見せられてもよく分からないだろうから、参考までに妻が見に行ったときにもらった方のフィルムも取り込んでみた。


あら素敵。映画のワンシーンみたい!

というわけで、こんな風に取り込んであとは壁紙にするも良し、プリントサービスで出力して飾るも良し、色々出来て楽しめそうである。

ちなみに写真の現像屋さんに頼めばプリントをしてくれるところもあるらしい。もっとも断られることも多いらしいし、大量にフィルムを集めてるとか、アニメの特典フィルムを頼んでみるってのも恥ずかしいと思うならこういうスキャナを買ってみるのも良いかも知れない。



画質を追求するならもうちょい良い奴の方がいいかも。

2013年11月8日金曜日

AWSのDynamoDBをJavaScriptから直接操作する

前回の記事のとおり、AWSのSDKがブラウザ用JavaScriptで利用できるようになった。
今回は実際に試して利用できるようになったまでの手順を記す。
ちなみに検索しても日本語の情報はおろか英語の情報すらあまり見つからず、総当り的に試行錯誤ており、またDynamoDBそのものとかGoogleの認証周りは今ひとつわかっていないので、手順には無駄や間違った箇所があるかもしれない。そのあたりは各自で修正していただきたい。(そして出来れば私にも教えてほしい)

今回やることは、Googleで認証を受けて、その認証トークンを使ってDynamoDBに接続して、データを取得・設定する。利用の想定はGoogleのユーザーIDごとにjsonかなにかの文字列を保存しておく単純なアプリケーションとする。

クライアント側での大まかな流れとしては、Googleでログインしてもらってそこから返されたid_tokenからGoogleのuser_idを取得する。AWSのDynamoDBのキー値はこのuser_idにする。DynamoDBとのアクセス時に一緒にid_tokenを渡すことでAWS側でもuser_idが正しいことが照合され、自分のuser_idがキーのデータのみにアクセスできるようになる。

利用までの手順としては以下のような流れになる。
  1. Googleにアプリケーション登録をする
  2. AWSでDynamoDBにテーブルを作成する
  3. DynamoDBでWeb認証のときのポリシーを作成できるので作ってコピーしておく
  4. AWSでIAMにDynamoDBにアクセスできるRoleを作成する(3のポリシーを使う)
  5. ブラウザ上でDynamoDBに接続するアプリケーションを作成する
ではひとつずつ説明していく。

1.Googleにアプリケーション登録をする

Google APIs Console
Google Cloud Console

上記リンクのどっちでも良い(下の方が新しい)。
これらは本来GoogleのAPI(地図とかカレンダーとか)を利用申請する画面なのだけど、今回はログインを利用するだけなので登録のみでOK。適当に登録するとAPI Accessとかの欄にClient IDがあるのでそれを記録しておく。****.apps.googleusercontent.comみたいなやつ。****.projectというやつは違うので気を付ける。Client Secretは使わない。
ちなみに下の方はGoogle App Engineなんかのプロジェクトとも統合されていて、その設定を行える。
このあたりはたぶんググればどんだけでも情報があるので省略。

2.AWSでDynamoDBにテーブルを作成する

ふつうにCreate Tabelで作成する。
ググれば(略)
スループットを全Table合計でwrite:5/read:10以上に設定すると、時間単価が有料になるので気を付ける(初めて作るならどっちも1にしておけば大丈夫)。

3.DynamoDBでWeb認証のときのポリシーを作成できるので作ってコピーしておく

これ。


Identity ProviderをGoogleにして、権限をあたえる処理にチェックをする。
Allowed Attributesってので列制限もできるみたい。


ここで設定するわけではなくPolicy Documentの欄の設定値をコピーしておく。
ざっくり設定に触れると、dynamodb:LeadingKeysが${accounts.google.com:sub}になっているので、キー値がgoogleのsub(ユーザーID)と一致したときのみ権限が与えられるようになっている。
id_tokenはgoogleのエンドポイントに投げるとユーザーID、アプリケーションID等々が返されるので、正しいアプリケーションであるかどうかとか、正しいユーザーIDであるかどうかが分かるのでAWS側で照合してくれてるっぽい。

4.AWSでIAMにDynamoDBにアクセスできるRoleを作成する(3のポリシーを使う)

IAMのサービスにアクセスしてRoleを作成する。



 é©å½“なRole名をつける。

一番下のを選ぶ。

Googleを選択してAudienceに Client IDを設定する。
これであとで渡すtokenが他のアプリに発行されたものじゃないことが確認される。

確認して次へ。

さっきのポリシーを入れるためにCustom Policyを選択する。

3で作成したポリシーをコピペする。

完了。
あとで使うのでこのRoleのSummaryからRole ARNをメモっておく。
こんな感じのやつ。
arn:aws:iam::(数字):role/(Role名)

5.ブラウザ上でDynamoDBに接続するアプリケーションを作成する

Googleから取得する必要があるのは、id_tokenというJWTっていうJSONの情報をまとめて署名してるナニ(よく知らない)と、Googleのuser_idの二つ。
id_tokenはGoogleのエンドポイントに渡すとそのトークンがどのアプリケーションIDに対して発行されたものかとか、どのuser_idに対するものであるとか、有効期限はいつまでだとか分かるのでその辺で有効な認証情報かAWS側で照合するのに利用されてるっぽい。
user_idはDynamoDBに格納するときのキーとして使うことになる。
これまでの手順が間違いなく出来ていたなら、DynamoDBにはこのid_tokenで確認されたuser_id以外のキーを受け入れないようになっている。

id_tokenとuser_idを取得する方法

これには調べた限りふたつの方法があって、楽なんだけど今ひとつ微妙なGoogle+ボタンを使う方と、面倒だけどちゃんと制御できるGoogle APIのJavaScriptライブラリを使う方法がある。多分内部的には同じ手順を踏んでるはず。
どちらの場合も上の手順で取得しておいたClient IDと、ユーザーにどこまでの権限を要求するかということを決めるscopeというものを用意する必要がある。ここではユーザーの基本的な情報(ユーザーIDの番号とアカウント)だけを要求する最低限のものにする。
その場合以下のようなアドレスをscopeに設定する。

https://www.googleapis.com/auth/userinfo.profile

各scopeの要求時に表示される画面なんかは以下のアドレスで確認できる。

OAuth 2.0 Playground

ちなみに上記のサイトはGoogle認証のOAuth2.0の手順を追っかけられるサイトなので、何が起きてるのかとか全く分からないなら色々いじくり回すと良いと思う。

で、話を戻して認証にはGoogle+ボタンを使う場合と直接やる場合とある。ただ調べ方が悪いのか、もともとそういうもんなのか、+ボタンを使う場合、上記のscopeが常にGooge+ API v1のloginを要求する権限が要求されてしまう。Google+を利用したことがないので分からないが、たぶんtwitterで言うと[今何々をプレイしてます!]みたいなものを自動でつぶやかせるために使うような権限だろうと思う。facebookで言うとウォールに載るかどうかみたいなもんだろう(facebookも使ったことがないのでこのたとえが正しいのかも知らない)scopeで言うと、https://www.googleapis.com/auth/plus.loginのやつがそれだ。
+ボタンって言ってるんだし、たぶんもともとそういうもんなんだろう。
上のuserinfo.profileで要求すると、+内でのユーザー情報と、+のサークルに知らせる権限と、Googleの情報とかなるので要求が多くて敬遠されそうな感じがする。あとログイン済みの場合、勝手に画面にトーストを表示させるを消す方法も分からなくて嫌だったので使わなかった。

ただ、Google+のユーザーでその方面で共有して欲しいと思うなら、使い方は簡単なのでおすすめだ。GoogleがホストしてるJavaScriptのファイルをロードして、spanに決まったクラスやdata属性でアプリケーション情報なんかを設定するだけでid_tokenを含んだデータがcallbackに帰ってくる。

以下に日本語で公式ドキュメントがあるので読めばすぐに使える。

Google Platform — Google Developers

user_idに関しては、手順が共通なのでライブラリを直接操作してid_tokenを取得する方法のあとに書く。

Google+ボタンを使わない方法

というわけでライブラリの使い方。ぱちぱち。
ちなみに+ボタンを使わないときでも、Google+ボタンガイドラインみたいなものがあって、それに準拠しなきゃならないのか悩むところだけど、何度か読み返してもこれはGoogle+の連携アプリとして作成するときはっつう話っぽいので多分大丈夫だと思う。+の権限を使うなら遵守すべき。
で本題。

Google JavaScript API - Google Platform — Google Developers
JavaScript Client Library Reference - Google APIs Client Library for JavaScript (Beta) — Google Developers

このあたりのリファレンス読めば分かる(おわり)。

なのだけど、一応ひっかかるポイントもあるのでサンプル。
gapi.auth.authorize({
    client_id:"******.apps.googleusercontent.com"
    ,immediate:true 
    ,response_type:"token id_token" 
    ,scope:"https://www.googleapis.com/auth/userinfo.profile"
},function(response){
    if(response && response.access_token){
        //ログインできたときの処理
    }else{
        //ログインできなかったときの処理
    }
});
上記の引数で一番重要なのはresponse_typeに"token id_token"という風にid_tokenとtokenのどっちも指定すること。tokenはあとでuser_idを問い合わせるときに使う(たぶんid_tokenで問い合わせることも出来ると思うんだけど調べてない)。ちなみに指定しないとtokenになるみたいでid_tokenが取得できず悩んだ。

immediateは連携許可の画面を出すか否かというフラグで、falseの場合、連携の有無に関係なく連携許可の画面がポップアップする。ただ既に連携の許可があった場合、ポップアップはちらりと見えてすぐ消える。そして上記のログインできたときの処理が流れる。許可が無ければ、あるいはログインしていなければその画面内でログイン|承認を受けられればログインできたときの処理が流れる。

trueの場合、連携の有無に関係なく、ポップアップは表示されない。連携がありログインしていれば問答無用でログイン処理に移行し、そうでなければできなかったときの処理が行われる。一長一短である。

つまりログインの処理をまっとうにやろうとすると、gapi.auth.authorizeはimmediateフラグをtrueで流したのち、ログインできなかったらfalseで流し直すか、ログインボタンを表示して押されたらfalseで実行するような形にすべきなのだと思う。
そうすると認証済みユーザーはシームレスに、新規ユーザーは承認画面に移行できる。

user_idを取得する

で、上記のどちらかの方法でid_tokenとaccess_tokenを取得できたはずだ。
そもそもこのtokenって何のtokenかというと連携許可を受けたデータにアクセスするためのtokenなので、このtokenを自分が許可を受けた権限で要求可能なエンドポイントに投げてやれば必要な情報が手に入る(必要な操作を行える)という寸法である。

これも上記のリファレンスに載っているのだけど、サンプルはこんな感じ。
var request = gapi.client.request({
    'path':'/oauth2/v2/userinfo'
    ,'params': {key:/*取得したaccess_token*/}
});

request.execute(function(userinfo){
    /*user_idを利用した処理*/
});
#callbackばっかりでネストが深くなりそうならdeferを使おう(jQueryだとDeferred)

やっとAWS SDK for JavaScriptをさわる

AWS SDK for JavaScript in the Browser

ざっと読めばだいたい大丈夫。
まずhttps://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.jsがsdkなのでscriptタグでロードしてやる。
そいでサンプルはこんな感じ。
AWS.config.credentials = new AWS.WebIdentityCredentials({
    RoleArn: "arn:aws:iam::*******:role/TestRole"
    ,WebIdentityToken: id_token
});
AWS.config.region = "ap-northeast-1";
var DB = new AWS.DynamoDB();

//値を入れる
DB.putItem({
    TableName:"TestTable"
    ,Item:{user_id:{S:user_id},data:{S:"TEST"}}
},function(response){
    //エラーがあればresponseに入る
});

//値を取り出す
DB.getItem({
    TableName:"TestTable"
    ,Key:{user_id:{S:user_id}}
},function(response,data){
    //データに取り出した値が入る
});
AWS.configに設定しておくとS3とかDynamoDBとかで共通のリージョンとか認証情報が使える感じ。RoleArnにRoleを作ったときにメモっておいたArnを入れて、id_tokenを渡して、regionを設定すればあとはテーブルを操作するだけ。

ItemとかKeyでDynamoDB側に値を渡しているときのSとかいう名前のプロパティはその値の型名でSはString、NはNumberとかそんな感じ。
やったーEC2なしでDynamoDBにアクセスできた!

2013年11月3日日曜日

JavaScriptからAWSのSDKを使って格安ブラウザゲー運用を目論む

ブラウザからAWSのサービスが使えたらどうなの?

先日、ブラウザのJavaScriptに対応したAWSのSDKのプレビューが公開された。
JavaScriptではこれまでもNode.js版は用意されていたがこっちはブラウザ用である点が違う。現在のところS3、DynamoDB、SQS、SNSが対応している。公式ドキュメントはNode.jsと共通なのでぱっと見ほかも使えそうに見えるが、ブラウザ版を利用したときはクラスが存在せず使えない。

で、これが何に使えるのかっていうと、EC2を使わないでもデータやファイルの保存なんかが出来るっていうことだ。それができれば、個人でやるような小規模なプロジェクトならかなり安く運用できる可能性が出てくる。たとえば艦隊くりっかーはクッキーに保存しているので破損しやすく、容量もそう増やすわけにはいかないけど、もしかするとこれをさほどのコストをかけずに安定した大容量のセーブに対応させられるかもしれない。さらにログインに対応させて、複数の機器や、出先でもセーブデータを共有するようなことだって可能だろう。

それって今までだって出来たんじゃね?

もちろんこれまでだって、EC2を使えば同じことは達成できた。
しかしAWSではEC2を使うとすぐに課金額が大きくなってしまう上、時間で課金されるのでなかなかその部分を圧縮するのは難しい。収益が見込めるような事業で使うならEC2は便利でコストメリットもある程度あるし、一時的に大量のサーバーが必要なんて用途にはばっちりくる。だが個人が24時間落とさないで稼動させる用途で使おうと思うと、驚くほど安いとかそういう感じではなくなる。

たとえば個人でブラウザゲームを作って、それを安定稼動させようとすると一台では障害時に安定稼動しないし、かといって複数台構成にしてELB使うなんてことになるとさらにに金も手間もかかってしまう。一番小さなマイクロインスタンス一台だけでも月1,000円近くかかる。
思いつきでアホなゲームを公開するのに月に3,000円も4,000円も継続的にかかっていては寛容な我が家の大蔵省だってあまりいい気はしないだろう。しかもこれは稼動させている限りずっとかかる。

艦隊くりっかーはどうしているのか、というとあれはサーバーサイドとの通信がまったくないのでS3についているホスティングサービスを使っている。これはファイルさえ置いておけばホスティングをしてくれるというもので、1GBあたり月10円支払っておけばあとは転送料分だけ支払えばよい。これの何がいいのかというと、ウケなくて誰も使わなければお金がかからないという部分だ。これが上記みたいにEC2を動かしたりすると、誰もやっちゃいないのに月に何千円も支払うことになる。こんなに悲しいことはない。
そのあたりは以前詳しく書いた。

AWS S3で安くて頑丈なWebサーバーを立てる/艦くりのバックボーン - ばかおもちゃ製作所

これがEC2抜きで、たとえばファイルならS3、データならDynamoDBに直接アクセスして利用できるようになれば管理の手間もコストもぐっと下がる。もちろんそれぞれのサービスに利用するための費用は必要だがS3はもともとかなり安いし、DynamoDBは人気がなければ予約帯域みたいなもんを無料枠まで引き下げればタダで使うことができる。

DynamoDBってなんなん?

高速なNoSQLでつまりセーブデータを保存するような用途に結構向く感じのサービス。
課金はデータの保存量と一秒間にどれくらい書き込み・読み込みできるかという性能で決まる。一秒間に5KB(5ユニット)の書き込みと10KB(10ユニット)の読み込みまでは無料。書き込みは10、読み込みは50増やすごとに月600円弱くらいかかるっぽい。
それで実際どれくらい動かせるのかは、正直やってみないとわからない。
艦隊くりっかーの多かった時期で同時アクセス400弱くらいだったので、まあ昔ながらのRPGみたいな10分に一回くらい保存するものなら、400人が6000秒に一回保存するわけで、1セーブデータを1KBに納められたなら無料枠で大丈夫じゃないかという気がする。

ブラウザから直接アクセスって危なくないのん?

そこが今回の発表で一番大事なところ。
というか私が今回知っただけで実際には今回の発表より以前にAWSはIAMという権限管理のシステムで、facebook、Amazon(たぶんアメリカのアカウントのみ)、Googleの認証情報でログインできるという拡張を行っていた。見たことがあると思うが、ツイッターアカウントでログインするとか、そういう感じのやつのことだ。これを設定しておいて、各サービスの認証画面を呼び出し、承認後帰ってきたトークンをAWSに渡せばあらかじめ付与しておいた権限が与えられる。つまりAWSへのアクセス権限のある鍵をブラウザ上から送る必要はなくなり、鍵が流出してS3を誰かのエロ画像の保管庫にされたり、テロリストの情報交換用の掲示板を作られたりする心配をしなくていい。
さらに各サービスで認証IDに紐付いた権限を設定できるようになっているので、正規アクセス権のある人がDynamoDBへのリクエストを書き換えてほかの人のゲームデータを横取りしようとしても、それは出来ないようにすることができる。これはS3でも同様だ。パスの一部にアカウントIDを含めて、その認証アカウントじゃない場合はアクセスできないようにすることができる。

具体的にどうやんの?

次回書く。というか一日かけてやっとある程度わかったので前置きだけですごい長くなっちゃった。

2013年11月1日金曜日

塗装用品あれこれ2

前のエントリで書いたとおり筆塗りなんかをやっている。
うまくいかないなーってことをこねくりまわしていると、いつかはそう悪くないかもって思える形になっていくのが楽しい。特に塗装は時間をかけてじっくりやると、割とかけた時間に応じて良くなる感じがする。

で、いつもどおり何かをはじめると嬉しくなってつい色々買ってしまう。
買ったのは、塗料入れ用のダンボール製棚と、保持具、ペイントステーション。あとついでにキムワイプ。



保持具は塗装する対象を持っておくためのクリップつきの棒。
GSIクレオスからだと、ねこの手なんていう台座つきのやつとか、ペッタンゴムなんていう塗装対象を粘着させるやつなんかもあるんだけど、これはオーソドックスなクリップのやつ。


はさむ力もそこそこあって安いし塗装以外でも持ってていいかもという気もする。
これまでは割り箸を発泡スチロールに突き刺して使っていたのだけどやはり専用のものは使いやすい。
また発泡スチロール部分の変わりに買ったのがペイントステーション。


ひとつ上の写真ですでに写ってるけど、ダンボールを横にして敷き詰めてるようなもんで、穴の間に棒を差して使う。軽いし不安定かなとも思っていたのだけど特にそんなこともなく安定している。4つ入り。


塗料入れの棚はボール紙製で組み立て時にちょっと曲げ損なって角が壊れたりしたけど、それなりにしっかりしてるし収納数も多い。¥1,000弱だしもう一個買うつもり。


あといまさらではあるけど、キムワイプは繊維がくっつかないティッシュみたいなものでティッシュで拭いたら傷がつくとか、繊維がつくっていうようなときに使うもので、とにかく便利。六個入り買った。

もっとうまく塗れるようになるといいなー。



ペインティングクリップII (PTC2)
ハイキューパーツ
売り上げランキング: 303
20本入り。

Mr.ペイントステーション GT68
ジーエスアイ クレオス (2010-08-04)
売り上げランキング: 790
4つ入り。

Mr.カラー&水性ホビーカラー収納BOX
ジーエスアイ クレオス (2011-09-07)
売り上げランキング: 8,877
4引き出しつき。

日本製紙クレシア キムワイプ S-200 6個入り
日本製紙クレシア (2013-09-02)
売り上げランキング: 30
6つ入り。

2013年10月28日月曜日

プラモデル初めての筆塗り

こういう題名だとはじめての筆塗りのためにはどうしろみたいな内容かと思われるだろうけど違います。私が初めて筆塗りをしたということです。なので、特にうまい作例とか良いハウツーとか特にないです。

塗ったのはこれ。



ついにおれもマシーネンクリーガーを手に入れたぞ!


で、下地に銀を塗って更に上に色塗ってところどころ禿げて銀が見えたら良いなって思った。
が、今までエアブラシとかで描いてるときに気づけよって話だけど、こういう塗料ってものすごくがっちり下地が透けるので、ものすごい色が重くなっちゃってうすめ液で剥がしたりして出来上がったのがこれ。



ムラだらけだし、塗り残しがあちこちにあったりもするんだけど、なんかそれはそれで味があるなーって思う。面白くなっちゃってまだまだ模様とか描いたり、汚しとか陰影とかつけたりしたい。こんなに面白いなら昔からもっと塗ってりゃ良かった。


ちなみに今回使った筆は5本セットで100円均一のもの。
良い筆がいかなるものかってのを私は知らないけど、そう悪いものでもなかった。
あとスポイトなんかも100均で見つけて買ったけどあまり使わなかった。
うすめ液も100均の容器に移して使ったらなかなか便利だった。
調色皿は100均じゃないけど、そもそも10枚100円で大変安い。
でもへりで絵の具を落としたりするには軽すぎるし小さいので、もう少し大きい絵皿とか、昔使ってたようなパレットみたいなものを用意してもいいかもしれない。ちなみにパレットも100均に売ってた。

筆で何かを塗るなんて本当に十数年ぶりだと思うけど楽しかった。デジタルで何かをやるより遥かに思い通りにならないし、手も汚れるけど、そういう面倒くささもそれはそうあるものとしてやり過ごせるようになった。たぶんおっさんになったんだろうと思う。
とても楽しかったので、しばらくいろいろ塗ってみよう。


かっこいい。

横山宏Ma.K.モデリングブック
横山 宏
大日本絵画
売り上げランキング: 135,412
これで塗り方を勉強しよう! とかいうよりは読み物としてすごく面白い。
これ読むといろいろ好きに塗って、好きに作ったら良いのだなあと思う。