8月13日13時でYahoo Creative Award の応募は締め切ってしまいました。 私は7/5の日記の通り、MeetUpイベントにも参加し、そこで出会ったデザイナーと共に2人でずっと計画してきました。
しかし、結果としては完成度60%程度で全く間に合わず。。 せっかく夏休みになったのに、締め切りが初日じゃ意味ないよな。せめてあと1週間あればな。 ということで、このままだとあまりにもったいないし、私の気が収まらないのでせめてこのブログに今迄の作成秘話を綴りたいと思います。
コンテンツ
Yahoo Creative Awardについて
毎年、何かをテーマにクリエイティブな作品を集め、表彰を行うコンテスト。
個人の部、企業の部がある。テーマはスマホの新しい使い方だったり、Yahooのサービスをアピールする広告であったり、いくつものテーマがある。 詳細はhttp://creative-award.yahoo.co.jp/
構想
今回のテーマは「課題解決エンジン」としてのYahoo!をアピールすべし、というものに絞った。
理由としては、新しく今年から追加された課題で、尚かつ「課題解決エンジンになりたいと考えています」という、これからYahooが押していきたい姿なのだろうという印象を受けたから。 テーマの1つとして列挙されているけど、実はYahooが一番作ってほしいのはここではないか。 必然的に、表彰される確率も高いはず。という予測の元に決定した。
ということでまずは1人でブレスト。休日丸一日かけ、家にあるホワイトボードで1人アイデア出し。
アイデア集
出たアイデアを挙げてみると。。
- 遠くのあいつと乾杯しよう:遠くに住んでいる仲間同士で、スマホをビールに見立てて相手に向かって乾杯できる
- 右手の道具が進化:スマホを右手に持ち、最初は石(1万年前を想定)、次は鉄砲(100年前を想定)が表示され、最後にYahooのトップ画面(現在を想定)が出てきて、「あなたの課題は右手一つで解決できるようになった」というメッセージが現れる
- 絶対安全ろうそく:スマホ画面に本物そっくりのローソクを表示し、それを使って擬似的なローソクで遊べる。誕生日のケーキのお祝いや、キャンドルリレー等。今迄は危険で家の中では避けていたことも、このサービスなら場所も年齢も選ばない
- 前を向かせるサービス:後述
- スマホの中におばあちゃん:スマホの中に小さいおばあちゃんが住んでいるという設定で、検索したワードはそのおばあちゃん達が相談した結果を応えてくれるというもの
結局は、前を向かせるサービスを選んだ
私はある日街を歩いていて、ふと気付いた事がある。それは、みんな下を向いているということだ。 そして手にはそう、スマホだ。
ぱっと見ると、みんなうつむいて悩んでいるみたいで何となく見ていて暗い気分になる。 私自身何となく違和感を感じていたのは、こういうことだったのだ。スマホが楽しくなりすぎたおかげで、人々は今前を向く時間が減っている。 もちろん恐らくほとんどの人は、悩んでいるから下を向いているわけではないのだろう。
しかし、人の特性として、下を向いてばかりいると気持ちも悪い方向に進んでしまって行くのではないか。少なくとも私はそうだ。 これは社会にとって大きなマイナスだ、と私は捉え、一瞬でも良いので、前を向けさせ、前を向く事の重要性を訴えられる作品にしたいと思った。 ということで、この構想に決定。
メンバーとブレストし、内容も決定
先日のミートアップイベントで知りあったデザイナーである猪瀬さんにこの構想を伝えると、猪瀬さんもそれいいね!と言ってくれた。 Google Driveにどうやってこの構想を作品に仕上げようか、内容をひたすら挙げていった。 1週間で30個くらいのアイデアが出た。 Skype会議をし、雨が滴り落ちるイメージとする事に決定。 仕様としては、こうだ。
- Yahoo!JAPANのTOPページ使用
- 画面を開くと、雨が降ってくる(rainy mood風に)
- "雨は実際にiphoneに降っているようにリアリティを追求
- 水平だったら雨がぽたぽたたまっていく感じ、傾くと滴り落ちていく感じ(重力に従う)"
- 水平の時は雨量多い→垂直にする程少ない→垂直では晴天
- 雨の音も忠実に再現(実際の雨音を録音)
- "垂直時の動き --垂直にして3秒くらい経つと雨が上がる ** →晴れてホワイトアウト ** →「下ばかり見て悩んでないで、前を見よう」 ** →「その悩み、Yahoo!が少しだけ協力します」 ** →Yahoo!JAPANロゴ" 現在7/23、残り20日間。
作成
構想が決まったので、作成に取りかかる。
モックアップ作成いろいろ
私はスマホのジャイロセンサーを利用したサービスを作るのが始めてだったので、簡単に遊んでみる。 Web上にぱらぱらマンガ用のエルモ画像があったので、これを使って角度に応じてマンガが動くというアプリを作ってみた。 エルモぱらぱらマンガ 完成したのはこちテスト javascriptで加速度センサーの情報を取得できるのは知らなかったので、とても良い勉強になった。 ただし、センサーの情報をそのまま取得するだけではぶれやノイズ等でマンガが小刻みに動き、見ててともて気持ち悪くなった。 そこで一工夫し、平均化処理を行う。
色々な方法があると思うが、ここでは簡単に過去10回分のセンサ値を平均し、その情報によって角度を決定するという方法を採用した。 あとはスレッショルド持たせたりしたいけど、とりあえずはこんなところで。 ちなみにコードはこんな感じ。素人プログラムですみません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | $(function(){ var msg = 0; var ptz = 0; var tz,tz1,tz2,tz3,tz4,tz5,tz6,tz7,tz8,tz9; var i = 0; //チャタ取り用 window.addEventListener("devicemotion",function(evt){ var x = evt.accelerationIncludingGravity.x; //横方向の傾斜 var y = evt.accelerationIncludingGravity.y; //縦方法の傾斜 var z = evt.accelerationIncludingGravity.z; //上下方向の傾斜 //水平を0、垂直を256とする var pz = (z / 10 * 256) + 256; //整数に変換しないと読み込んでくれない tz = Math.round(pz); //チャタ取り。tz1新しい&#8644;tz4古い //平均化 var ave_tz = (tz+tz1+tz2+tz3+tz4+tz5+tz6+tz7+tz8+tz9) / 10; tz9 = tz8; tz8 = tz7; tz7 = tz6; tz6 = tz5; tz5 = tz4; tz4 = tz3; tz3 = tz2; tz2 = tz1; tz1 = tz; //エルモ画像 var preImgNum = ave_tz / 4; var imgNum = Math.round(preImgNum); if (imgNum <= 62 ){ $("#elmo").attr("src","img/images/elmo-"+imgNum+".jpg"); }else if(i>=5){ $("#elmo").attr("src","img/images/elmo-62.jpg"); } //加速度センサの情報を表示 $("#test").html("x:"+x+"<br>y:"+y+"<br>z:"+z+"<br>tz:"+tz); //数字と文字を変化させる if( z < 2 && z > -2 ) { if( msg == 0 ) { $("<h1>さぁ、前を向こう</h1><img src='img/images.jpeg'/>").appendTo("#result").hide().fadeIn(1000); msg = 1; }else{ msg = msg; } }else{ $("#result h1").remove(); $("#result img").remove(); msg = 0; } ptz = tz },false); sleep(100); }); |
あと、テストもう一つも作ってみた。角度に応じて明るさを変えて、垂直まで立てるとメッセージが表示されるというもの。 これもなかなか良いね。 現在7/28。
リアルを追求したくて悩む
今回プッシュしたいものはメッセージ性と、なんといってもリアリティ。 いつも通りにスマホを見ていると、晴れているはずなのに雨がぽたぽた落ちてくる。雨の音も鳴っている。おかしいな、と思ってスマホを上げてみると、雨は止み、前を向こうのメッセージ。これをやるためには現実と錯覚させるためのリアリティが必要不可欠。 イメージとしては[http://www.rainymood.com/:title=Rainy Mood]がかなり近い。 ひたすら雨のシーンを再生するだけだけど、かなりクールなサイトなので知らない人は要チェック。 猪瀬さんもリアリティを追求したいという所は同感で、最初はスマホに実際に雨を降らせ、それをムービーで流そうという話になった。 猪瀬さんのコネでスタジオが借りれるということだったので、それではということで一任した。 ただ、かなり撮るのに大変だったみたいで、断念。 私自身、自分のスキルアップのためにもjavascriptを使いたかったためCreative JSを使う事にした。 ハッカソンで会ったYahooのメンターの方もお奨めしてたし。
Cretive JSとの格闘
しかし、まともにjavascriptを使ったことのない自分にとって、これはかなりハードルが高かった。 オブジェクト指向の考え方が身に付いてないので、参考書を片手にトライ。
この本、口コミ通りかなり分かりやすく、「Webクリエイターのため」と銘打っているだけあってjavascriptの基礎的な所からスタートし、CreativeJSのインストール方法から導入までも書かれている。 現時点で、ここまでCreativeJSに特化した書籍はないと思う。
書いたコードはこちら。決まり通り、html内にcanvas要素をまずは作成。
1 2 3 | <body onload="initialize()"> <canvas id="myCanvas" width=600 height=900></canvas> |
次に、CreativeJSのライブラリを読み込む。一つ一つ役割が違う。数の多さにびびってはダメだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <script src="easeljs/utils/UID.js"></script> <script src="easeljs/geom/Matrix2D.js"></script> <script src="easeljs/geom/Point.js"></script> <script src="easeljs/events/EventDispatcher.js"></script> <script src="easeljs/utils/Ticker.js"></script> <script src="easeljs/events/MouseEvent.js"></script> <script src="easeljs/display/DisplayObject.js"></script> <script src="easeljs/display/Container.js"></script> <script src="easeljs/display/Stage.js"></script> <script src="easeljs/display/Bitmap.js"></script> <script src="easeljs/display/Graphics.js"></script> <script src="easeljs/display/Shape.js"></script> <script src="easeljs/display/Shadow.js"></script> <script src="easeljs/filters/Filter.js"></script> <script src="easeljs/filters/BoxBlurFilter.js"></script> <script src="easeljs/filters/ColorMatrixFilter.js"></script> <script src="easeljs/filters/ColorMatrix.js"></script> <script src="preloadjs/AbstractLoader.js"></script> <script src="preloadjs/LoadQueue.js"></script> <script src="preloadjs/TagLoader.js"></script> <script src="preloadjs/XHRLoader.js"></script> <script src="tweenjs/Tween.js"></script> <script src="tweenjs/Ease.js"></script> |
実際に書いたのはこちら。まずはcanvasに画像をロードする所。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function initialize(){ //傾きアクション //canvasを用意 var canvasElement = document.getElementById("myCanvas"); stage = new Stage(canvasElement); //preloadjs起動 var loader = new LoadQueue(false); //イベントリスナー関数。fileloadが完了したら、drawイベントを実行する。drawには()を付けない事!ここでは登録するだけなので loader.addEventListener("fileload",draw); //tweenする方(雨)は後で呼び出す loader.addEventListener("fileload",tweentest); //表示の基準点を補正 loader.center = new Point(canvasElement.width / 2, canvasElement.height /2); //YahooTopを読み出す loader.loadFile({src:file}); } |
後は長いので省略するが、概要を説明すると 画像のロード完了→draw関数呼び出し→createShape関数で円(雨)を複数作成→あたり判定をし、trueなら結合するためにcombinedShape関数呼び出し といった流れだ。 ここまでで雨が繋がる様子はクリア。
ベジェ曲線をマスター
ここまでのコードで一番苦労したのは、間違いなく雨が繋がる所。 ベジェ曲線で雨を描こうとしたのも、単なる円ではなくよりリアルな形状にしたかったのと、もう一つの理由が結合するプログラムが書きやすいと判断したこと。 円で雨を作成してしまうと、繋がった時にどういう形状になるかをプログラムで書く事ができない(少なくとも私の知識では)。 その点、ベジェ曲線であれば、単なる開始ベクトルと終点ベクトルの集合なので、点がいくつになろうが、どんな繋がり方になろうが、ベジェ曲線で表現できないものはないためだる。 もちろんリアルを追求するには雨の表面張力と言った物も考慮する必要があるのだが、それはまた次のステップの話。 ひとまずは雨を作る、繋げるといった行為であれば、今の所ベジェ曲線が唯一解であり最良解である。 とはいうものの、自身はまだベジェ曲線に関して素人。 [http://jsdoc.hotcom-web.com/wordpress/archives/168:title=html5 framework tutorial] で勉強した。 数あるサイトの中で、一番分かりやすく座標軸で説明されていた。 このサイトと、Photoshopでベジェ曲線で作成した円の座標を元に、CreativeJSとCanvasを使って円を書いていく。 一度覚えてしまえば、何の事はない。 開始ベクトルと終端ベクトルの大きさと向きを座標で表しているだけのこと。
作成したコードはこちら。var bptがベジェ曲線の中身。今回は雨を3つのアンカーポイントで表現しようと思ったので、開始点座標2つと、3つのアンカーそれぞれに6つずつの座標情報が書かれている。 分からない人は、ひとまずphotoshopでペンツールで円を作ってみよう。
なお、ここでは雨の形を変えられるために、scaleで全体の大きさを、sizeでxy方向の大きさを変えられるようにしてある。 今後は、回転させられたり座標軸も何種類か用意する予定である。 現時点で8/2。残り10日間。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function createShape(nX, nY, custom, numX, numY){ var myShape = new Shape(); myGraphics = myShape.graphics; setAppearance(myShape, nX, nY); myGraphics.beginStroke(Graphics.getRGB(255,255,255)); var bpt = [10, 71.5, 51, -48.5, 203.5, 5, 225.5, 73.5, 245.5, 132, 167.5, 219.5, 92.5, 200.5, 26.5, 185, -19.5, 163, 10, 71.5]; myShape.bpt = bpt; //ベジェ曲線で雨を描く if (custom == "size") { myGraphics.moveTo(bpt[0]+numX,bpt[1]+numY).bezierCurveTo(bpt[2]+numX,bpt[3]+numY,bpt[4]+numX,bpt[5]+numY,bpt[6]+numX,bpt[7]+numY).bezierCurveTo(bpt[8]+numX,bpt[9]+numY,bpt[10]+numX,bpt[11]+numY,bpt[12]+numX,bpt[13]+numY).bezierCurveTo(bpt[14]+numX,bpt[15]+numY,bpt[16]+numX,bpt[17]+numY,bpt[18]+numX,bpt[19]+numY).endStroke(); }else if(custom == "scale") { myGraphics.moveTo(bpt[0]*numX,bpt[1]*numY).bezierCurveTo(bpt[2]*numX,bpt[3]*numY,bpt[4]*numX,bpt[5]*numY,bpt[6]*numX,bpt[7]*numY).bezierCurveTo(bpt[8]*numX,bpt[9]*numY,bpt[10]*numX,bpt[11]*numY,bpt[12]*numX,bpt[13]*numY).bezierCurveTo(bpt[14]*numX,bpt[15]*numY,bpt[16]*numX,bpt[17]*numY,bpt[18]*numX,bpt[19]*numY).endStroke(); } //シャドウは一つしか付けれなさそう myShape.shadow = new Shadow("#000000", 0, 7, 3); return myShape; } |
技術的な障壁
ここまではある程度順調だったのだが、この結合の実装がかなり手強かった。 というより、結論から言うとこの工程に手番をかけすぎて間に合わなかった。 ポイントとしては、下記点でつまづいた。 - 結合すべきアンカーポイントの選定 - 結合の仕方(角度)に応じたプログラム - 配列操作(参照の仕方)
やり残した点
あとはこのあたりをやりたかったな。トータル手番としてあと10日間!全然足りない。。 - TweenJSを使用した雨の移動(スマホの角度に応じて) - SoundJSを使用した雨のサウンド再生 - 垂直にした時のメッセージや仕掛け - 読み込みのスピードアップ(現状20秒くらいかかる) そして現時点での作品はこんな所。全くダメすね。一応、読み込むたびに雨の様子が変わります。 [http://storyauc.com/test9.php:title=作品]
最後に
今回は間に合わなかったが、自分の提案したコンセプトに共感してくれる人も現れ、且つ、ちょっとしたデモでやっぱりこの作品の良さが実感できてある程度の手応えを感じる事ができた。 技術的にも、CreativeJSやオブジェクト指向、参照という考え方やベジェ曲線の作り方等を学ぶ事ができた。 やはり、強烈に自分で「これが作りたい」と願う事が一番の教材なのだと改めて感じた。 今回は途中で期限切れにはなったけど、こつこつと続きを作っていきたいな。 他のコンテストでも、機会があれば出したい。 それにしても、リアルを表現するのって難しいけどとても面白く、とてもやりがいがあることだと思った。 猪瀬さんも、お疲れ様でした。