長谷川理恵さんのオフィシャルサイトを作りました。
アートディレクション・基本デザインはH.D.O.さま。
Web向けの調整は nssgraphica 町田さまによるもの。
僕はFlashを担当させていただきました。

長谷川理恵オフィシャルサイト
http://hasegawarie.com
ArtDirection / Design : H.D.O.
Design : Munehiro Machida.nssgraphica
Flash : KOSUKE,Nakamura.nipx


Adobe AIR Contest 2010でFlowerWallPaperが優秀賞(クリエイティブ賞)を受賞しました。賞は本当に光栄で嬉しいかぎりです。
この作品をダウンロードしてくださった皆様、審査・選出いただいた審査員の皆様、ありがとうございました。
コンテストのことは知っていましたが、FlowerWallPaperは特に賞を意識して作った作品ではなく、自分たちのプライベートワークで初めてのAir作品として、初期のWeb作品Flower Rockをもとに作り上げたものです。息の長い作業の末の作品だけに本当に嬉しいです。コツコツ進めていたことが、こういう結果につながることもあるんだなぁということで、どんなことも挫けず真摯に続けることだと思います。


FlowerWallPaper
http://nipx.jp/download/FlowerWallPaper/
ApplicationDesign&Flash / KOSUKE,Nakamura. nipx
CharacterDesign / Yoco,Nakamura. nipx
Award : Adobe AIR Contest 2010 優秀賞(クリエイティブ賞)

Adobe AIR Contest 2010のウェブサイトは下記バナーよりご覧いただけます。

FlowerWallPaperについて審査員さまからコメントをいただいています。時間が出来たらFlowerWallPaperは追加機能のアップデートや細かなバグフィックスも行いたいと思っています。がんばる!
使うことになりそうなのでブログに設置。確認中。押してみるしかないし。
Flash Player 10からは任意のタイミングでカーソルを変更できるようだ。これって今まで出来なかったんだ?
ということで確認用にエントリーしておきます。文字の部分はbuttonMode = trueとしていますが、カーソルを変更しているとボタンの状態にならないので(なっては困るか…)、任意のタイミングで戻すことも必要でしょう。
This movie requires Flash Player 10.0.0

papervision3dやFlashPlayer10以降の3D機能を使ったコンテンツを目にする機会が以前よりずっと増えてきたので、自分ももう三たび目くらい?にいろいろと模索中です。今だなかなか思い通りにいかないことも多い。3D空間にUIを統合させてデザインしていくことは、2Dと違って3D空間の座標と見た目の画面の座標が一致しないし、こういう動きをして、ここで止まって、これをこのサイズ・この角度で表示したいというような2Dなら訳ないことが簡単にいかないことがままある訳です。
最近のプロジェクトではDesigner、Flasherなどと分業されることが多いと思いますが、その場合、個人的な心象としてはFlasherだけでなく、Designerはもといプレゼンターたる役割のDirectorなりも相応の理解がなければやってられないという感じがします。自由変形でなんとなく作られたデザインでなんとなく説明されてきたものを、さあ組んでと言われるような話ならたまったもんじゃない気がする。イメージと違う、この絵にならないなんてことで右往左往することが目に浮かぶ。それはイメージが違う、なり得ない絵の間違いなんじゃないかみたいな。PhotoshopやIllustratorにも3D機能がある今、本気で3Dコンテンツを作るなら3Dのスキルを習得すべきはFlasherだけでないように思います。
fladdict氏のiOS4.1考察。
半年もたたない間になんだか慌ただしいことになってきています。
Packager for iPhone の開発再開について – akihiro kamijoなんて話も目にしました。
どうなるんでしょうね。再びFlashでiPhoneアプリを作れるようになるなら楽しそうです。
個人的にAppleの先の規約に端を発し何故だかHTML5対Flashみたいな話が過熱しちゃって、何もわかってない人に、もうFlash不要みたいな風評が広がったことは風評被害以外の何ものでもありません。
このあたりも落ち着いてくれればよいのだけれど。
TLFTextFieldを弄っていて気づいたところ。
デフォルトで隙間があるんです。TextFieldにもあったけど。
borderをつけてみるとわかる。
XML.prettyPrinting = false;
XML.prettyIndent = 0;
var markup:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008"><p><img source="contrail.jpg" width="200" height="150"/></p></TextFlow>;
var field:TLFTextField = new TLFTextField();
field.border= true;
field.x = 10;
field.y = 10;
field.width = 230;
field.height= 200;
field.tlfMarkup = markup.toString();
addChild( field );
端から2pxの隙間がある。

この隙間を無くしたいと思いました。
paddingだろうと思って、それらしきものを調べてみるとすべて未定義。
//結果はもれなくundefined。
trace( field.textFlow.paddingTop );
trace( field.textFlow.paddingLeft );
trace( field.textFlow.hostFormat.paddingTop );
trace( field.textFlow.hostFormat.paddingLeft );
trace( field.textFlow.format.paddingTop );
trace( field.textFlow.format.paddingLeft );
この隙間はコンテナレベルのpaddingに指定されていました。
//コンテナレベルのレイアウトを確認してみる。
var controller:ContainerController = field.textFlow.flowComposer.getControllerAt( 0 );
//TLFContainerController。謎のクラス。
trace( controller );
//これだ。
trace( controller.paddingTop );
trace( controller.paddingLeft );
trace( controller.format.paddingTop );
trace( controller.format.paddingLeft );
controller.paddingTop = controller.paddingLeft = 0;
field.textFlow.flowComposer.updateAllControllers();
TLFContainerControllerって名前で意味はわかりますが、ググっても全然出てこない謎のコントローラー。
やたらとテキスト周りのエントリーが続いています。
覚えること多すぎなText Layout Framework。そしてFlash Text Engine。
TLF Markupのimgタグについて気づいたことをメモ。
TLF Markupでは、InlineGraphicElementをimgタグで記述しますが、そのソース画像の指定はsource属性です。srcでないところに注意。
たとえばこの場合、画像は表示されない。
var markup:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008"><p><img src="contrail.jpg" width="200" height="150"/><span>飛行機雲</span></p></TextFlow>;
var flow:TextFlow = TextConverter.importToFlow( markup, TextConverter.TEXT_LAYOUT_FORMAT );
flow.flowComposer.addController( new ContainerController( container, 480, 480 ) );
flow.flowComposer.updateAllControllers();
<img src="contrail.jpg" width="200" height="150"/>
のsrcがNGなわけです。
試しにこの時のInlineGraphicElementの属性を確認してみる。
var img:InlineGraphicElement = flow.getFirstLeaf() as InlineGraphicElement;
trace( "img.source = " + img.source );
結果はnull。
とsource属性に値が無いです。
少し混乱するのがここからで、TextFlowを再度テキストに書き出してみると、
var str:String = TextConverter.export( flow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.STRING_TYPE ) as String;
trace( str );
結果は、
<TextFlow columnCount="inherit" columnGap="inherit" columnWidth="inherit" lineBreak="inherit"
paddingBottom="inherit" paddingLeft="inherit" paddingRight="inherit" paddingTop="inherit" verticalAlign="inherit"
whiteSpaceCollapse="preserve" xmlns="http://ns.adobe.com/textLayout/2008">
<p>
<img src="contrail.jpg" height="150" width="200"/>
<span>飛行機雲</span>
</p>
</TextFlow>
src属性はそのまま残っていたりします。マークアップは別途保存されるんですかね。
これはいいとして、以前のエントリーで2段階で変換すればうまくいくと書きました。
var markup:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008"><p><img src="contrail.jpg" width="200" height="150"/><span>飛行機雲</span></p></TextFlow>;
var flow:TextFlow = TextConverter.importToFlow( markup, TextConverter.TEXT_FIELD_HTML_FORMAT );
markup = TextConverter.export( flow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE ) as XML;
flow = TextConverter.importToFlow( markup, TextConverter.TEXT_LAYOUT_FORMAT );
flow.flowComposer.addController( new ContainerController( container, 480, 480 ) );
flow.flowComposer.updateAllControllers();
これなら期待どおり変換されて画像が表示されます。
もう少しだけ、よさそうな方法がありました。
TextConverter.getImporterとTextConverter.getExporterを使ってまとめておくと便利かもしれません。
var HTMLImporter:ITextImporter = TextConverter.getImporter( TextConverter.TEXT_FIELD_HTML_FORMAT );
var TLFImporter:ITextImporter = TextConverter.getImporter( TextConverter.TEXT_LAYOUT_FORMAT );
var TLFExporter:ITextExporter = TextConverter.getExporter( TextConverter.TEXT_LAYOUT_FORMAT );
function getFlow( source:* ):TextFlow{
return TLFImporter.importToFlow( TLFExporter.export( HTMLImporter.importToFlow( source ), ConversionType.STRING_TYPE ) );
}
var container:Sprite= new Sprite();
addChild( container );
var markup:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008"><p><img src="contrail.jpg" width="200" height="150"/><span>飛行機雲</span></p></TextFlow>;
var flow:TextFlow = getFlow( markup );
flow.flowComposer.addController( new ContainerController( container, 480, 480 ) );
flow.flowComposer.updateAllControllers();
まとめのサンプル
Progression 4 で追加されたコマンドにDoExecutorがあります。
このコマンドはその名の通り指定したExecutorObjectを実行出来るのですが、便利そうなケースがあったので記録しておきます。
- トップページは、直下に子シーンを持つ。
- 子シーンは背景イメージを変更する。
- トップページでは子シーンのいずれかの背景イメージを表示する。
ぎゅっと簡略した形ですがギャラリーコンテンツなんかでありそうなケース。
子シーンはこんな感じです。シーンに到達したら背景イメージを追加するだけ。
package{
import flash.display.Bitmap;
import jp.progression.commands.Prop;
import jp.progression.commands.display.*;
import jp.progression.scenes.SceneObject;
public class ChildScene extends SceneObject{
public function ChildScene(name:String=null, initObject:Object=null){
super(name, initObject);
}
public var bmp:Bitmap; //背景イメージ
protected override function atSceneLoad():void{
//※確認用、シーンパスを表示
var indexScene:IndexScene = parent as IndexScene;
addCommand(
new Prop( indexScene.field, { text:sceneId.path } )
);
}
//背景イメージ追加
protected override function atSceneInit():void{
addCommand(
new AddChildAt( container, bmp, 0 )
);
}
//背景イメージ削除
protected override function atSceneUnload():void{
addCommand(
new RemoveChild( container, bmp )
);
}
}
}
トップページはこちら。トップページでは背景イメージをランダムに選んで表示したいのですが、背景イメージの表示は子シーンにも記述があります。なのでこれをDoExecutorコマンドで動かしてしまおうという魂胆。
package{
import flash.display.Bitmap;
import flash.text.*;
import jp.nipx.debug.btn.Btn;
import jp.progression.casts.*;
import jp.progression.commands.*;
import jp.progression.commands.display.*;
import jp.progression.commands.lists.*;
import jp.progression.commands.managers.*;
import jp.progression.commands.media.*;
import jp.progression.commands.net.*;
import jp.progression.commands.tweens.*;
import jp.progression.data.*;
import jp.progression.events.*;
import jp.progression.executors.*;
import jp.progression.scenes.*;
public class IndexScene extends SceneObject{
public function IndexScene(){
var btn:Btn;
btn = new Btn( { label:"Index", sceneId:new SceneId( "/index" ), x:5, y:225 } );
container.addChild( btn );
btn = new Btn( { label:"1", sceneId:new SceneId( "/index/1" ), x:btn.x + 5 + btn.width, y:225 } );
container.addChild( btn );
btn = new Btn( { label:"2", sceneId:new SceneId( "/index/2" ), x:btn.x + 5 + btn.width, y:225 } );
container.addChild( btn );
btn = new Btn( { label:"3", sceneId:new SceneId( "/index/3" ), x:btn.x + 5 + btn.width, y:225 } );
container.addChild( btn );
addScene( new ChildScene( "1", { bmp:new Bitmap( new Img1( 250,250 ) ) } ) ) as ChildScene;
addScene( new ChildScene( "2", { bmp:new Bitmap( new Img2( 250,250 ) ) } ) ) as ChildScene;
addScene( new ChildScene( "3", { bmp:new Bitmap( new Img3( 250,250 ) ) } ) ) as ChildScene;
field = new TextField();
field.defaultTextFormat = new TextFormat( "_ゴシック", 10, 0x333333 );
field.x = 5;
container.addChild( field );
}
public var field:TextField;
protected override function atSceneInit():void{
//子シーンをランダムに選ぶ
var i:Number = Math.round( numScenes * Math.random() );
i = ( i == numScenes ) ? 0 : i;
var scene:SceneObject = getSceneAt( i );
addCommand(
new Prop( field, { text:sceneId.path } ),
//子シーンexecutorを動かす、シーン到着時のイベントを送信
new DoExecutor( scene.executor, new SceneEvent( SceneEvent.SCENE_INIT ) )
);
}
protected override function atSceneGoto():void{
addCommand(
new RemoveChildAt( container, 0 )
);
}
}
}
DoExecutorのサンプル
こんな形で使うと似たような処理をいくつものSceneObjectに書くようなことを減らせることもありそうですね。
ここでは、もともとSceneObjectに実装されているイベントでExecutorObjectを動かしていますが、独自のイベントでExecutorObjectを動かすことも可能です。
このあたりExecutorObjectってなに?ってところから、解りやすく書かれている記事を見つけました。
Progression 4 の DoExecutorコマンドを使い倒す!
DoExecutorコマンドは、動かしたExecutorObjectの処理でもコマンドシークエンスが有効ってところがとても便利ですね。
埋め込みフォントをSWCに書き出して利用すれば、高速なパブリッシュが出来んだが、Flashで利用する際、アウトラインフォーマットがクラシック(DF3)で、SWCに書き出したフォントと同じフォントを指定したテキストフィールドがあるとうまくSWCのフォントを利用できなかったのでメモしておく。
SWCに書き出すほうのflaファイルでは以下のように日本語フォントを埋め込んでSWCに書き出します。パブリッシュのSWF設定、SWC書き出しにチェックでSWCに書き出せる。


SWCを利用するほうのflaファイルで、SWCにパスを通し書き出したクラス名のインスタンスを宣言すると埋め込みフォントとして利用できるようになる。しかもパブリッシュは軽い。
package{
import flash.display.Sprite;
import flash.text.*;
public class EmbedDF3 extends Sprite{
public function EmbedDF3(){
//SWCに埋め込んだフォントを利用
var embedFont:Font = new HiraginoKakuGoProW3DF3();
//利用できる埋め込みフォントを確認
var arr:Array = Font.enumerateFonts();
for each( var i:Font in arr ){
trace( i.fontName ); //出力:Hiragino Kaku Gothic Pro W3
}
var str:String = "SWCの埋め込みフォントを利用" + "\n";
str += "Hiragino Kaku Gothic Pro W3";
var format:TextFormat = new TextFormat();
format.font = embedFont.fontName;
format.color= 0x999999;
var field:TextField = new TextField();
field.defaultTextFormat = format;
field.x = 25;
field.y = 25;
field.width = 200;
field.height= 100;
field.borderColor = 0x999999;
field.border = true;
field.multiline = true;
field.wordWrap = true;
field.embedFonts= true;
field.text = str;
addChild( field );
}
}
}

ここまではいいんです。とっても便利。
しかし、flaに同じフォントを指定したテキストフィールドがあったとします。
ここではステージにテキストフィールドを配置していますがどこにあっても同じ。
このテキストフィールドのアンチエイリアスはデバイスフォントとしています。

これで書き出すと、

埋め込みフォントが利用できません。
どうも同名のフォントがあるとそちらが優先される模様。
この時は、
//利用できる埋め込みフォントを確認
var arr:Array = Font.enumerateFonts();
for each( var i:Font in arr ){
trace( i.fontName ); //出力:無し(arr.length = 0)
}
も出力されないので、埋め込みでない同名フォントが優先されているのかなと。
試しにステージに配置したテキストフィールドのアンチエイリアスを「アンチエイリアス(アニメーション優先)」とした場合、テキストフィールドに入っている文字だけが表示される。

traceの部分では、Hiragino Kaku Gothic Pro W3が出力されているんだけど、Flashが自動的に埋め込む、ステージに配置したテキストフィールドのフォントになっているんだと思う。